Last active
October 9, 2019 05:53
-
-
Save jkbjh/fb2825c7ba4036592e4213fc327d7851 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import subprocess | |
import socket | |
from contextlib import closing | |
import threading | |
import time | |
import os | |
import signal | |
import argparse | |
def find_free_port(): | |
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: | |
s.bind(('', 0)) | |
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
return s.getsockname()[1] | |
class Registry(object): | |
KILLTIMEOUT = 60 | |
def __init__(self): | |
self.registry = None | |
self.mutex = threading.RLock() | |
pass | |
def start(self): | |
with self.mutex: | |
if self.registry is None: | |
p = subprocess.Popen("docker run --rm -p 5000:5000 -i --name registry registry:2", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True, preexec_fn=os.setsid) | |
self.registry = p | |
def stop(self): | |
with self.mutex: | |
assert self.registry | |
self.registry.send_signal(2) | |
start = time.time() | |
pgrp = os.getpgid(self.registry.pid) | |
os.killpg(pgrp, signal.SIGINT) | |
while self.registry.returncode is None and time.time() - start < self.KILLTIMEOUT: | |
time.sleep(0.0001) # no timeout in wait for subprocess? | |
self.registry.poll() | |
self.registry.poll() | |
if self.registry.returncode is None: | |
os.killpg(pgrp, signal.SIGKILL) | |
self.registry.wait() | |
self.registry = None | |
def push(self, name): | |
assert ":" not in name, "':' not allowed in name: %r" % (name,) | |
subprocess.check_call("docker tag {NAME} localhost:5000/{NAME}".format(NAME=name), shell=True) | |
subprocess.check_call("docker push localhost:5000/{NAME}".format(NAME=name), shell=True) | |
def is_port_open(self): | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
port_open = 0 == sock.connect_ex(('localhost', 5000)) | |
sock.close() | |
return port_open | |
def is_running(self): | |
self.registry.poll() | |
not_stopped = self.registry.returncode is None | |
return not_stopped | |
def wait_for_open_and_running(self, timeout): | |
start = time.time() | |
while self.is_running() and not self.is_port_open(): | |
time.sleep(0.001) | |
if (time.time() - start) > timeout: | |
break | |
def create_singularity(self, name, imgname, sandbox=False): | |
# Build singularity container | |
subprocess.check_call("SINGULARITY_NOHTTPS=1 singularity build {SANDBOX} {IMGNAME} docker://localhost:5000/{NAME} ".format( | |
IMGNAME=imgname, | |
NAME=name, | |
SANDBOX="--sandbox" if sandbox is True else "", | |
), | |
shell=True) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description='Convert docker to singularity image using a local registry.') | |
parser.add_argument('docker_name', type=str) | |
parser.add_argument('singularity_image_name', type=str) | |
parser.add_argument('--sandbox', action='store_true', help='build a sandbox directory') | |
args = parser.parse_args() | |
print(dict(docker_name=args.docker_name, singularity_image_name=args.singularity_image_name)) | |
assert ":" not in args.docker_name | |
assert ":" not in args.singularity_image_name | |
docker_name = args.docker_name | |
singularity_image = args.singularity_image_name | |
registry = Registry() | |
try: | |
registry.start() | |
registry.wait_for_open_and_running(30) | |
assert registry.is_running() and registry.is_port_open() | |
registry.push(docker_name) | |
registry.create_singularity(docker_name, singularity_image, sandbox=args.sandbox) | |
finally: | |
registry.stop() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment