diff --git a/docs/job/deployments.md b/docs/job/deployments.md index 8e7724313..89b53304c 100644 --- a/docs/job/deployments.md +++ b/docs/job/deployments.md @@ -14,6 +14,7 @@ You would add a deployment to your job: "repository": "repo-name", "tag": "some optional tag", "target": "target build stage", + "always_push": "true or false", "username": "your_username", "password": { "$secret": "SECRET_NAME_FOR_YOUR_PASSWORD" } }] @@ -29,6 +30,7 @@ Deployments are currently only supported for `docker` job types. |repository|true|string||Name of the repository| |tag|false|string|build\_\|The tag of the image| |target|false|string||When building a Dockerfile with multiple build stages `target` can be used to specify an intermediate build stage by name as a final stage for the resulting image which should be deployed| +|always_push|false|bool|false|Always deploy image, even if container run failed.| |username|false|string||Username to be used with the registry| |password|false|[Secret](/docs/job/secrets.md)||Secret containing the password| diff --git a/src/job/job.py b/src/job/job.py index 080c780b6..716255985 100755 --- a/src/job/job.py +++ b/src/job/job.py @@ -44,6 +44,7 @@ def __init__(self, console): Job.__init__(self) self.console = console self.storage_dir = '/data/tmp/storage' + self.error = None if os.path.exists(self.storage_dir): shutil.rmtree(self.storage_dir) @@ -738,13 +739,15 @@ def deploy_images(self, image_name): c = self.console if not self.deployments: return - - c.header("Deploying", show=True) + header = False for dep in self.deployments: - target = dep.get('target', None) - - if not target: + if dep.get('target', None): + continue + if dep.get("always_push", False) or not self.error: + if not header: + c.header("Deploying", show=True) + header = True self.deploy_image(image_name, dep) def login_docker_registry(self): @@ -848,7 +851,7 @@ def run_docker_container(self, image_name): raise Failure("Could not get exit code of container") c.print_failure("Container run exited with error (exit code=%s)" % exit_code) - c.header("Finalize", show=True) + c.header("Error", show=True) logger.exception(e) raise Failure("Container run exited with error (exit code=%s)" % exit_code) @@ -903,16 +906,21 @@ def build_docker_image(self, image_name, cache_image, target=None): def run_job_docker_image(self, c): image_name = self.job['definition']['image'].replace('$INFRABOX_BUILD_NUMBER', str(self.build['build_number'])) - if self.job.get('definition', {}).get('run', True): - self._login_source_registries() - self.run_docker_container(image_name) - self._logout_source_registries() - else: - self._login_source_registries() - self.run_docker_pull(image_name) - self._logout_source_registries() + try: + if self.job.get('definition', {}).get('run', True): + self._login_source_registries() + self.run_docker_container(image_name) + self._logout_source_registries() + else: + self._login_source_registries() + self.run_docker_pull(image_name) + self._logout_source_registries() + except Exception as e: + self.error = e self.deploy_images(image_name) + if self.error: + raise self.error c.header("Finalize", show=True) def _login_registry(self, reg): @@ -970,7 +978,7 @@ def run_job_docker(self, c): for d in self.deployments: target = d.get('target', None) - if not target and not self.job.get('build_only', True): + if not target: continue self.build_docker_image(image_name_build, image_name_latest, target=target) @@ -979,12 +987,19 @@ def run_job_docker(self, c): self.build_docker_image(image_name_build, image_name_latest) - if not self.job.get('build_only', True): - self.run_docker_container(image_name_build) + try: + if not self.job.get('build_only', True): + self.run_docker_container(image_name_build) + except Exception as e: + self.error = e self.deploy_images(image_name_build) c.header("Finalize", show=True) + if self.error: + raise self.error + + def get_cached_image(self, image_name_latest): c = self.console diff --git a/src/pyinfrabox/infrabox/__init__.py b/src/pyinfrabox/infrabox/__init__.py index 6220f636e..ad5ca80b6 100644 --- a/src/pyinfrabox/infrabox/__init__.py +++ b/src/pyinfrabox/infrabox/__init__.py @@ -340,7 +340,7 @@ def parse_wait(d, path): parse_depends_on(d['depends_on'], path + ".depends_on") def parse_deployment_docker_registry(d, path): - check_allowed_properties(d, path, ("type", "host", "repository", "username", "password", "tag", "target")) + check_allowed_properties(d, path, ("type", "host", "repository", "username", "password", "tag", "target", "always_push")) check_required_properties(d, path, ("type", "host", "repository")) check_text(d['host'], path + ".host") check_text(d['repository'], path + ".repository")