From 7e33475c9c3a1fa5d6125550ba35875a37bc9b5c Mon Sep 17 00:00:00 2001 From: Randy Barlow Date: Thu, 15 Feb 2018 15:41:10 -0500 Subject: [PATCH] Add support for composing containers. fixes #2028 Signed-off-by: Randy Barlow --- bodhi/server/config.py | 8 ++++++ bodhi/server/consumers/masher.py | 47 +++++++++++++++++++++++++++++++- production.ini | 5 ++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/bodhi/server/config.py b/bodhi/server/config.py index 6b6b242b1c..f7fead6e04 100644 --- a/bodhi/server/config.py +++ b/bodhi/server/config.py @@ -544,6 +544,14 @@ class BodhiConfig(dict): 'site_requirements': { 'value': 'dist.rpmdeplint dist.upgradepath', 'validator': six.text_type}, + 'skopeo.cmd': { + 'value': '/usr/bin/skopeo', + 'validator': six.text_type, + }, + 'skopeo.extra_copy_flags': { + 'value': '', + 'validator': six.text_type, + }, 'smtp_server': { 'value': None, 'validator': _validate_none_or(six.text_type)}, diff --git a/bodhi/server/consumers/masher.py b/bodhi/server/consumers/masher.py index 149160955e..8e178947f8 100644 --- a/bodhi/server/consumers/masher.py +++ b/bodhi/server/consumers/masher.py @@ -304,7 +304,7 @@ def get_masher(content_type): ComposerThread or None: Either a ContainerComposerThread, RPMComposerThread, or a ModuleComposerThread, as appropriate, or None if no masher is found. """ - mashers = [RPMComposerThread, ModuleComposerThread] + mashers = [ContainerComposerThread, RPMComposerThread, ModuleComposerThread] for possible in mashers: if possible.ctype is content_type: return possible @@ -851,6 +851,51 @@ def sort_by_days_in_testing(self, updates): return updates +class ContainerComposerThread(ComposerThread): + """Use skopeo to copy and tag container images.""" + + ctype = ContentType.container + + def _compose_updates(self): + """Use skopeo to copy images to the correct repos and tags.""" + destination_registry = config['container.production_registry'] + + for update in self.compose.updates: + if update.state is UpdateState.pending: + source_registry = config['container.candidate_registry'] + else: + source_registry = destination_registry + + for build in update.builds: + source_url = '{}/{}:{}'.format(source_registry, build.name, build.tag) + destination_url = '{}/{}:{}'.format(destination_registry, build.name, build.tag) + # Credentials should be stored in $HOME/.docker/config.json + # https://github.com/projectatomic/skopeo#private-registries-with-authentication + # For development, you can run a simple registry with: + # sudo docker run -it -d -p 5000:5000 --restart=always --name registry registry:2 + # You can get skopeo to not care about TLS by setting skopeo.extra_copy_flags to + # --dest-tls-verify=false + skopeo_cmd = [config.get('skopeo.cmd'), 'copy', + config.get('skopeo.extra_copy_flags'), source_url, destination_url] + out, err, code = util.cmd(skopeo_cmd) + skopeo_process = subprocess.Popen( + skopeo_cmd, + # Nope. No shell for you + shell=False, + # Should be useless, but just to set something predictable + cwd=self.mash_dir, + # Pungi will logs its stdout into pungi.global.log + stdout=self.devnull, + # Stderr should also go to pungi.global.log if it starts + stderr=subprocess.PIPE, + # We will never have additional input + stdin=self.devnull) + out, err = skopeo_process.communicate() + + if skopeo_process.returncode: + raise Exception(out + err) + + class PungiComposerThread(ComposerThread): """Compose update with Pungi.""" diff --git a/production.ini b/production.ini index 605ac2fbc2..2d101e7820 100644 --- a/production.ini +++ b/production.ini @@ -153,6 +153,11 @@ use = egg:bodhi-server # What to pass to Pungi's --label flag, which is metadata included in its composeinfo.json. # pungi.labeltype = Update +# The skopeo executable to use to copy container images. +# skopeo.cmd = /usr/bin/skopeo + +# Extra flags to pass to the skopeo copy command. +# skopeo.extra_copy_flags = ## ## Mirror settings