Skip to content

Instantly share code, notes, and snippets.

@jkbjh
Last active October 9, 2019 05:53
Show Gist options
  • Save jkbjh/fb2825c7ba4036592e4213fc327d7851 to your computer and use it in GitHub Desktop.
Save jkbjh/fb2825c7ba4036592e4213fc327d7851 to your computer and use it in GitHub Desktop.
#!/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