summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjuanvallejo <jvallejo@redhat.com>2017-03-28 12:09:38 -0400
committerjuanvallejo <jvallejo@redhat.com>2017-05-19 13:38:17 -0400
commit694a5460f9195903823e703168b7cd7f0f46697e (patch)
treea1de2afb8418b2362bbdfa0e85aa1a42b5c77ec5
parent177beab3244eb9bfd581dc2cb52955dea81cba09 (diff)
downloadopenshift-694a5460f9195903823e703168b7cd7f0f46697e.tar.gz
openshift-694a5460f9195903823e703168b7cd7f0f46697e.tar.bz2
openshift-694a5460f9195903823e703168b7cd7f0f46697e.tar.xz
openshift-694a5460f9195903823e703168b7cd7f0f46697e.zip
improve error handling for missing vars
-rw-r--r--roles/openshift_health_checker/meta/main.yml1
-rw-r--r--roles/openshift_health_checker/openshift_checks/docker_image_availability.py104
-rw-r--r--roles/openshift_health_checker/test/docker_image_availability_test.py187
3 files changed, 226 insertions, 66 deletions
diff --git a/roles/openshift_health_checker/meta/main.yml b/roles/openshift_health_checker/meta/main.yml
index cd9b55902..4d141974c 100644
--- a/roles/openshift_health_checker/meta/main.yml
+++ b/roles/openshift_health_checker/meta/main.yml
@@ -2,3 +2,4 @@
dependencies:
- role: openshift_facts
- role: openshift_repos
+ - role: openshift_version
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 cce289b95..00c670287 100644
--- a/roles/openshift_health_checker/openshift_checks/docker_image_availability.py
+++ b/roles/openshift_health_checker/openshift_checks/docker_image_availability.py
@@ -15,20 +15,25 @@ class DockerImageAvailability(OpenShiftCheck):
skopeo_image = "openshift/openshift-ansible"
- # FIXME(juanvallejo): we should consider other possible values of
- # `deployment_type` (the key here). See
- # https://github.com/openshift/openshift-ansible/blob/8e26f8c/roles/openshift_repos/vars/main.yml#L7
- docker_image_base = {
+ deployment_image_info = {
"origin": {
- "repo": "openshift",
- "image": "origin",
+ "namespace": "openshift",
+ "name": "origin",
},
"openshift-enterprise": {
- "repo": "openshift3",
- "image": "ose",
+ "namespace": "openshift3",
+ "name": "ose",
},
}
+ @classmethod
+ def is_active(cls, task_vars):
+ """Skip hosts with unsupported deployment types."""
+ deployment_type = get_var(task_vars, "openshift_deployment_type")
+ has_valid_deployment_type = deployment_type in cls.deployment_image_info
+
+ return super(DockerImageAvailability, cls).is_active(task_vars) and has_valid_deployment_type
+
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))
@@ -41,13 +46,34 @@ class DockerImageAvailability(OpenShiftCheck):
# exit early if Skopeo update fails
if failed:
+ if "Error connecting: Error while fetching server API version" in msg:
+ msg = (
+ "It appears Docker is not running.\n"
+ "Please start Docker on this host before running this check.\n"
+ "The full error reported was:\n " + msg
+ )
+
+ elif "Failed to import docker-py" in msg:
+ msg = (
+ "The required Python docker-py module is not installed.\n"
+ "Suggestion: install the python-docker-py package on this host."
+ )
+ else:
+ msg = "The full message reported by the docker_image module was:\n" + msg
return {
"failed": True,
"changed": changed,
- "msg": "Failed to update Skopeo image ({img_name}). {msg}".format(img_name=self.skopeo_image, msg=msg),
+ "msg": (
+ "Unable to update the {img_name} image on this host;\n"
+ "This is required in order to check Docker image availability.\n"
+ "{msg}"
+ ).format(img_name=self.skopeo_image, msg=msg),
}
registries = self.known_docker_registries(task_vars)
+ if not registries:
+ return {"failed": True, "msg": "Unable to retrieve any docker registries."}
+
available_images = self.available_images(missing_images, registries, task_vars)
unavailable_images = set(missing_images) - set(available_images)
@@ -64,31 +90,24 @@ class DockerImageAvailability(OpenShiftCheck):
return {"changed": changed}
def required_images(self, task_vars):
- deployment_type = get_var(task_vars, "deployment_type")
- # FIXME(juanvallejo): we should handle gracefully with a proper error
- # message when given an unexpected value for `deployment_type`.
- image_base_name = self.docker_image_base[deployment_type]
-
- openshift_release = get_var(task_vars, "openshift_release")
- # FIXME(juanvallejo): this variable is not required when the
- # installation is non-containerized. The example inventories have it
- # commented out. We should handle gracefully and with a proper error
- # message when this variable is required and not set.
- openshift_image_tag = get_var(task_vars, "openshift_image_tag")
+ deployment_type = get_var(task_vars, "openshift_deployment_type")
+ image_info = self.deployment_image_info[deployment_type]
- is_containerized = get_var(task_vars, "openshift", "common", "is_containerized")
+ openshift_release = get_var(task_vars, "openshift_release", default="latest")
+ openshift_image_tag = get_var(task_vars, "openshift_image_tag", default=openshift_release)
+ if openshift_image_tag and openshift_image_tag[0] != 'v':
+ openshift_image_tag = 'v' + openshift_image_tag
- 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))
+ is_containerized = get_var(task_vars, "openshift", "common", "is_containerized")
+ images = set(self.non_qualified_docker_images(image_info["namespace"], image_info["name"], openshift_release,
+ is_containerized))
# 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)
+ self.qualified_docker_images(image_info["namespace"], image_info["name"], openshift_image_tag)
)
return images
@@ -109,13 +128,10 @@ class DockerImageAvailability(OpenShiftCheck):
def known_docker_registries(self, task_vars):
result = self.module_executor("docker_info", {}, task_vars)
-
if result.get("failed", False):
- return []
+ return False
- # FIXME(juanvallejo): wrong default type, result["info"] is expected to
- # contain a dictionary (see how we call `docker_info.get` below).
- docker_info = result.get("info", "")
+ docker_info = result.get("info", {})
return [registry.get("Name", "") for registry in docker_info.get("Registries", {})]
def available_images(self, images, registries, task_vars):
@@ -148,30 +164,22 @@ class DockerImageAvailability(OpenShiftCheck):
"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)
- ]
+ return not result.get("failed", False)
@staticmethod
- def rpm_docker_images(base, version):
- return [
- "{image_repo}/registry-console:{version}".format(image_repo=base["repo"], version=version)
- ]
+ def non_qualified_docker_images(namespace, name, version, is_containerized):
+ if is_containerized:
+ return ["{}/{}:{}".format(namespace, name, version)] if name else []
+
+ return ["{}/{}:{}".format(namespace, name, version)] if name else []
@staticmethod
- def qualified_docker_images(image_name, version):
+ def qualified_docker_images(namespace, name, version):
return [
- "{}-{}:{}".format(image_name, component, version)
- for component in "haproxy-router docker-registry deployer pod".split()
+ "{}/{}-{}:{}".format(namespace, name, suffix, version)
+ for suffix in ["haproxy-router", "docker-registry", "deployer", "pod"]
]
- @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):
diff --git a/roles/openshift_health_checker/test/docker_image_availability_test.py b/roles/openshift_health_checker/test/docker_image_availability_test.py
index 2a9c32f77..f054b9ccc 100644
--- a/roles/openshift_health_checker/test/docker_image_availability_test.py
+++ b/roles/openshift_health_checker/test/docker_image_availability_test.py
@@ -3,26 +3,177 @@ import pytest
from openshift_checks.docker_image_availability import DockerImageAvailability
-@pytest.mark.xfail(strict=True) # TODO: remove this once this test is fully implemented.
-@pytest.mark.parametrize('task_vars,expected_result', [
+@pytest.mark.parametrize('deployment_type,is_active', [
+ ("origin", True),
+ ("openshift-enterprise", True),
+ ("enterprise", False),
+ ("online", False),
+ ("invalid", False),
+ ("", False),
+])
+def test_is_active(deployment_type, is_active):
+ task_vars = dict(
+ openshift_deployment_type=deployment_type,
+ )
+ assert DockerImageAvailability.is_active(task_vars=task_vars) == is_active
+
+
+@pytest.mark.parametrize("is_containerized", [
+ True,
+ False,
+])
+def test_all_images_available_locally(is_containerized):
+ def execute_module(module_name, args, task_vars):
+ assert module_name == "docker_image_facts"
+ assert 'name' in args
+ assert args['name']
+ return {
+ 'images': [args['name']],
+ }
+
+ result = DockerImageAvailability(execute_module=execute_module).run(tmp=None, task_vars=dict(
+ openshift=dict(common=dict(
+ service_type='origin',
+ is_containerized=is_containerized,
+ )),
+ openshift_deployment_type='origin',
+ openshift_release='v3.4',
+ openshift_image_tag='3.4',
+ ))
+
+ assert not result.get('failed', False)
+
+
+@pytest.mark.parametrize("module_failure", [
+ True,
+ False,
+])
+def test_all_images_available_remotely(module_failure):
+ def execute_module(module_name, args, task_vars):
+ return {
+ 'docker_image_facts': {'images': [], 'failed': module_failure},
+ 'docker_info': {'info': {'Registries': [{'Name': 'docker.io'}, {'Name': 'registry.access.redhat.com'}]}},
+ }.get(module_name, {'changed': False})
+
+ result = DockerImageAvailability(execute_module=execute_module).run(tmp=None, task_vars=dict(
+ openshift=dict(common=dict(
+ service_type='origin',
+ is_containerized=False,
+ )),
+ openshift_deployment_type='origin',
+ openshift_release='3.4'
+ ))
+
+ assert not result.get('failed', False)
+
+
+def test_all_images_unavailable():
+ def execute_module(module_name=None, module_args=None, tmp=None, task_vars=None):
+ if module_name == "docker_info":
+ return {
+ 'info': {
+ 'Registries': [
+ {
+ 'Name': 'docker.io'
+ },
+ {
+ 'Name': 'registry.access.redhat.com'
+ }
+ ]
+ }
+ }
+
+ if module_name == "docker_container":
+ return {
+ 'failed': True,
+ }
+
+ return {
+ 'changed': False,
+ }
+
+ check = DockerImageAvailability(execute_module=execute_module)
+ actual = check.run(tmp=None, task_vars=dict(
+ openshift=dict(common=dict(
+ service_type='origin',
+ is_containerized=False,
+ )),
+ openshift_deployment_type="openshift-enterprise",
+ openshift_release=None,
+ ))
+
+ assert actual['failed']
+ assert "required images are not available" in actual['msg']
+
+
+@pytest.mark.parametrize("message,extra_words", [
(
- dict(
- openshift=dict(common=dict(
- service_type='origin',
- is_containerized=False,
- )),
- openshift_release='v3.5',
- deployment_type='origin',
- openshift_image_tag='', # FIXME: should not be required
- ),
- {'changed': False},
+ "docker image update failure",
+ ["docker image update failure"],
),
- # TODO: add more parameters here to test the multiple possible inputs that affect behavior.
+ (
+ "Error connecting: Error while fetching server API version",
+ ["Docker is not running"]
+ ),
+ (
+ "Failed to import docker-py",
+ ["docker-py module is not installed", "install the python docker-py package"]
+ )
])
-def test_docker_image_availability(task_vars, expected_result):
+def test_skopeo_update_failure(message, extra_words):
def execute_module(module_name=None, module_args=None, tmp=None, task_vars=None):
- return {'info': {}} # TODO: this will vary depending on input parameters.
+ if module_name == "docker_image":
+ return {
+ "failed": True,
+ "msg": message,
+ "changed": False,
+ }
- check = DockerImageAvailability(execute_module=execute_module)
- result = check.run(tmp=None, task_vars=task_vars)
- assert result == expected_result
+ return {
+ 'changed': False,
+ }
+
+ actual = DockerImageAvailability(execute_module=execute_module).run(tmp=None, task_vars=dict(
+ openshift=dict(common=dict(
+ service_type='origin',
+ is_containerized=False,
+ )),
+ openshift_deployment_type="openshift-enterprise",
+ openshift_release='',
+ ))
+
+ assert actual["failed"]
+ for word in extra_words:
+ assert word in actual["msg"]
+
+
+@pytest.mark.parametrize("module_failure", [
+ True,
+ False,
+])
+def test_no_registries_available(module_failure):
+ def execute_module(module_name=None, module_args=None, tmp=None, task_vars=None):
+ if module_name == "docker_info":
+ return {
+ 'changed': False,
+ 'failed': module_failure,
+ 'info': {
+ 'Registries': [],
+ }
+ }
+
+ return {
+ 'changed': False,
+ }
+
+ actual = DockerImageAvailability(execute_module=execute_module).run(tmp=None, task_vars=dict(
+ openshift=dict(common=dict(
+ service_type='origin',
+ is_containerized=False,
+ )),
+ openshift_deployment_type="openshift-enterprise",
+ openshift_release='',
+ ))
+
+ assert actual['failed']
+ assert "docker registries" in actual['msg']