Browse Source

Merge pull request #3461 from juanvallejo/jvallejo/add-docker-image-check

Merged by openshift-bot
OpenShift Bot 8 năm trước cách đây
mục cha
commit
8751f883b2

+ 9 - 0
Dockerfile

@@ -14,6 +14,15 @@ LABEL name="openshift-ansible" \
       io.openshift.expose-services="" \
       io.openshift.tags="openshift,install,upgrade,ansible"
 
+USER root
+
+RUN INSTALL_PKGS="skopeo" && \
+    yum install -y --setopt=tsflags=nodocs $INSTALL_PKGS && \
+    rpm -V $INSTALL_PKGS && \
+    yum clean all
+
+USER ${USER_UID}
+
 # The playbook to be run is specified via the PLAYBOOK_FILE env var.
 # This sets a default of openshift_facts.yml as it's an informative playbook
 # that can help test that everything is set properly (inventory, sshkeys)

+ 1 - 0
roles/openshift_health_checker/action_plugins/openshift_health_check.py

@@ -74,6 +74,7 @@ class ActionModule(ActionBase):
                 result["failed"] = True
                 result["msg"] = "One or more checks failed"
 
+        result["changed"] = any(r.get("changed", False) for r in check_results.values())
         return result
 
     def load_known_checks(self):

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2036 - 0
roles/openshift_health_checker/library/docker_container.py


+ 24 - 0
roles/openshift_health_checker/library/docker_info.py

@@ -0,0 +1,24 @@
+# pylint: disable=missing-docstring
+"""
+Ansible module for determining information about the docker host.
+
+While there are several ansible modules that make use of the docker
+api to expose container and image facts in a remote host, they
+are unable to return specific information about the host machine
+itself. This module exposes the same information obtained through
+executing the `docker info` command on a docker host, in json format.
+"""
+
+from ansible.module_utils.docker_common import AnsibleDockerClient
+
+
+def main():
+    client = AnsibleDockerClient()
+
+    client.module.exit_json(
+        info=client.info(),
+    )
+
+
+if __name__ == '__main__':
+    main()

+ 168 - 0
roles/openshift_health_checker/openshift_checks/docker_image_availability.py

@@ -0,0 +1,168 @@
+# pylint: disable=missing-docstring
+from openshift_checks import OpenShiftCheck, get_var
+
+
+class DockerImageAvailability(OpenShiftCheck):
+    """Check that required Docker images are available.
+
+    This check attempts to ensure that required docker images are
+    either present locally, or able to be pulled down from available
+    registries defined in a host machine.
+    """
+
+    name = "docker_image_availability"
+    tags = ["preflight"]
+
+    skopeo_image = "openshift/openshift-ansible"
+
+    docker_image_base = {
+        "origin": {
+            "repo": "openshift",
+            "image": "origin",
+        },
+        "openshift-enterprise": {
+            "repo": "openshift3",
+            "image": "ose",
+        },
+    }
+
+    def run(self, tmp, task_vars):
+        required_images = self.required_images(task_vars)
+        missing_images = set(required_images) - set(self.local_images(required_images, task_vars))
+
+        # exit early if all images were found locally
+        if not missing_images:
+            return {"changed": False}
+
+        msg, 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 ({img_name}). {msg}".format(img_name=self.skopeo_image, msg=msg),
+            }
+
+        registries = self.known_docker_registries(task_vars)
+        available_images = self.available_images(missing_images, registries, task_vars)
+        unavailable_images = set(missing_images) - set(available_images)
+
+        if unavailable_images:
+            return {
+                "failed": True,
+                "msg": (
+                    "One or more required images are not available: {}.\n"
+                    "Configured registries: {}"
+                ).format(", ".join(sorted(unavailable_images)), ", ".join(registries)),
+                "changed": changed,
+            }
+
+        return {"changed": changed}
+
+    def required_images(self, task_vars):
+        deployment_type = get_var(task_vars, "deployment_type")
+        image_base_name = self.docker_image_base[deployment_type]
+
+        openshift_release = get_var(task_vars, "openshift_release")
+        openshift_image_tag = get_var(task_vars, "openshift_image_tag")
+
+        is_containerized = get_var(task_vars, "openshift", "common", "is_containerized")
+
+        if is_containerized:
+            images = set(self.containerized_docker_images(image_base_name, openshift_release))
+        else:
+            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.
+        images.update(
+            self.qualified_docker_images(self.image_from_base_name(image_base_name), "v" + openshift_image_tag)
+        )
+
+        return images
+
+    def local_images(self, images, task_vars):
+        """Filter a list of images and return those available locally."""
+        return [
+            image for image in images
+            if self.is_image_local(image, task_vars)
+        ]
+
+    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):
+        result = self.module_executor("docker_info", {}, task_vars)
+
+        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, 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
+
+        return False
+
+    def is_available_skopeo_image(self, image, registry, task_vars):
+        """Uses Skopeo to determine if required image exists in a given registry."""
+
+        cmd_str = "skopeo inspect docker://{registry}/{image}".format(
+            registry=registry,
+            image=image,
+        )
+
+        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 [
+            "{image}:{version}".format(image=self.image_from_base_name(base_name), version=version)
+        ]
+
+    @staticmethod
+    def rpm_docker_images(base, version):
+        return [
+            "{image_repo}/registry-console:{version}".format(image_repo=base["repo"], version=version)
+        ]
+
+    @staticmethod
+    def qualified_docker_images(image_name, version):
+        return [
+            "{}-{}:{}".format(image_name, component, version)
+            for component in "haproxy-router docker-registry deployer pod".split()
+        ]
+
+    @staticmethod
+    def image_from_base_name(base):
+        return "".join([base["repo"], "/", base["image"]])
+
+    # 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):
+        result = self.module_executor("docker_image", {"name": self.skopeo_image}, task_vars)
+        return result.get("msg", ""), result.get("failed", False), result.get("changed", False)