diff --git a/roles/openshift_health_checker/library/docker_info.py b/roles/openshift_health_checker/library/docker_info.py index 84079b57ea2..7f712bcff1d 100644 --- a/roles/openshift_health_checker/library/docker_info.py +++ b/roles/openshift_health_checker/library/docker_info.py @@ -16,7 +16,6 @@ def main(): client = AnsibleDockerClient() client.module.exit_json( - changed=False, info=client.info(), ) diff --git a/roles/openshift_health_checker/openshift_checks/docker_image_availability.py b/roles/openshift_health_checker/openshift_checks/docker_image_availability.py index be6f2f23301..910cd8a70be 100644 --- a/roles/openshift_health_checker/openshift_checks/docker_image_availability.py +++ b/roles/openshift_health_checker/openshift_checks/docker_image_availability.py @@ -13,7 +13,7 @@ class DockerImageAvailability(OpenShiftCheck): name = "docker_image_availability" tags = ["preflight"] - skopeo_image = "juanvallejo/skopeo:v3.4" + skopeo_image = "openshift/openshift-ansible" docker_image_base = { "origin": { @@ -34,8 +34,18 @@ def run(self, tmp, task_vars): if not missing_images: return {"changed": False} + failed, changed = self.update_skopeo_image(task_vars) + + # exit early if Skopeo update fails + if failed: + return { + "failed": True, + "changed": changed, + "msg": "Failed to update Skopeo image.", + } + registries = self.known_docker_registries(task_vars) - available_images, changed = self.available_images(missing_images, registries, task_vars) + available_images = self.available_images(missing_images, registries, task_vars) unavailable_images = set(missing_images) - set(available_images) if unavailable_images: @@ -63,51 +73,79 @@ def required_images(self, task_vars): is_containerized = get_var(task_vars, "openshift", "common", "is_containerized") if is_containerized: - docker_or_rpm_images = set(self.containerized_docker_images(image_base_name, openshift_release)) + images = set(self.containerized_docker_images(image_base_name, openshift_release)) else: - docker_or_rpm_images = set(self.rpm_docker_images(image_base_name, openshift_release)) + images = set(self.rpm_docker_images(image_base_name, openshift_release)) # append images with qualified image tags to our list of required images. # these are images with a (v0.0.0.0) tag, rather than a standard release # format tag (v0.0). We want to check this set in both containerized and # non-containerized installations. - docker_or_rpm_images.update(self.qualified_docker_images(self.image_from_base_name(image_base_name), - "v" + openshift_image_tag)) + images.update( + self.qualified_docker_images(self.image_from_base_name(image_base_name), "v" + openshift_image_tag) + ) - return docker_or_rpm_images + return images def local_images(self, required_images, task_vars): - """ Return all found local docker images """ - found = set() - for image in required_images: - cmd = self.module_executor("docker_image_facts", {"name": image}, task_vars) - if cmd.get("images", None): - found.add(image) + """Filter a list of images and return those available locally.""" + return [ + image for image in required_images + if self.is_image_local(image, task_vars) + ] - return found + def is_image_local(self, image, task_vars): + result = self.module_executor("docker_image_facts", {"name": image}, task_vars) + if result.get("failed", False): + return False + + return bool(result.get("images", [])) def known_docker_registries(self, task_vars): - docker_info = self.module_executor("docker_info", {}, task_vars).get("info", "") + result = self.module_executor("docker_info", {}, task_vars) + + # do test on module exception - see if this line is useful + if result.get("failed", False): + return [] + + docker_info = result.get("info", "") return [registry.get("Name", "") for registry in docker_info.get("Registries", {})] - def available_images(self, missing_images, registries, task_vars): - """ Inspect existing images using Skopeo and return all images successfully inspected """ - missing_images_copy = list(missing_images) - registries_copy = list(registries) + def available_images(self, images, registries, task_vars): + """Inspect existing images using Skopeo and return all images successfully inspected.""" + return [ + image for image in images + if self.is_image_available(image, registries, task_vars) + ] + + def is_image_available(self, image, registries, task_vars): + for registry in registries: + if self.is_available_skopeo_image(image, registry, task_vars): + return True - skopeo_update = self.update_skopeo_image(task_vars) - changed = skopeo_update.get("changed", False) + return False - # exit early if Skopeo update fails - if skopeo_update.get("failed", False): - return missing_images, changed + def is_available_skopeo_image(self, image, registry, task_vars): + """Uses Skopeo to determine if required image exists in a given registry. - while registries_copy and missing_images_copy: - registry = registries_copy.pop(0) - # pylint: disable=redefined-variable-type - missing_images_copy = self.missing_skopeo_images(registry, missing_images_copy, task_vars) + Returns the set of images not found in the given registry.""" - return set(missing_images) - set(missing_images_copy), changed + cmd_str = "skopeo inspect docker://{registry}/{image}".format( + registry=registry, + image=image, + ) + + # check how container name collisions are handled + # make sure container is removed by module + args = { + "name": "skopeo_inspect", + "image": self.skopeo_image, + "command": cmd_str, + "detach": False, + "cleanup": True, + } + result = self.module_executor("docker_container", args, task_vars) + return result.get("failed", False) def containerized_docker_images(self, base_name, version): return [ @@ -122,10 +160,8 @@ def rpm_docker_images(base, version): @staticmethod def qualified_docker_images(image_name, version): - # pylint: disable=unused-argument - # pylint: disable=unused-variable return [ - "{image_name}-{component}:{version}".format(**locals()) + "{}-{}:{}".format(image_name, component, version) for component in "haproxy-router docker-registry deployer pod".split() ] @@ -133,29 +169,8 @@ def qualified_docker_images(image_name, version): def image_from_base_name(base): return "".join([base["repo"], "/", base["image"]]) - def missing_skopeo_images(self, registry, tagged_images, task_vars): - """ Uses Skopeo to determine if required images exist in a given registry. - Returns the set of images not found in the given registry.""" - failed = set() - for image in tagged_images: - cmd_str = "skopeo inspect docker://{registry}/{tagged_image}".format( - registry=registry, - tagged_image=image, - ) - args = { - "name": "skopeo_inspect", - "image": self.skopeo_image, - "command": cmd_str, - "detach": False, - } - - # the module's status will always be "1" if an image was not found - if self.module_executor("docker_container", args, task_vars).get("status") == 1: - failed.add(image) - - return failed - # ensures that the skopeo docker image exists, and updates it # with latest if image was already present locally. def update_skopeo_image(self, task_vars): - return self.module_executor("docker_image", {"name": self.skopeo_image}, task_vars) + result = self.module_executor("docker_image", {"name": self.skopeo_image}, task_vars) + return result.get("failed", False), result.get("changed", False)