diff options
Diffstat (limited to 'roles/openshift_health_checker')
23 files changed, 318 insertions, 217 deletions
diff --git a/roles/openshift_health_checker/action_plugins/openshift_health_check.py b/roles/openshift_health_checker/action_plugins/openshift_health_check.py index 326176273..3ee3b132c 100644 --- a/roles/openshift_health_checker/action_plugins/openshift_health_check.py +++ b/roles/openshift_health_checker/action_plugins/openshift_health_check.py @@ -101,7 +101,8 @@ class ActionModule(ActionBase): execute_module=self._execute_module, tmp=tmp, task_vars=task_vars, - want_full_results=want_full_results + want_full_results=want_full_results, + templar=self._templar ) return known_checks diff --git a/roles/openshift_health_checker/openshift_checks/__init__.py b/roles/openshift_health_checker/openshift_checks/__init__.py index ce05b44a4..b7b16e0ea 100644 --- a/roles/openshift_health_checker/openshift_checks/__init__.py +++ b/roles/openshift_health_checker/openshift_checks/__init__.py @@ -65,12 +65,15 @@ class OpenShiftCheck(object): If the check can gather logs, tarballs, etc., do so when True; but no need to spend the time if they're not wanted (won't be written to output directory). """ - - def __init__(self, execute_module=None, task_vars=None, tmp=None, want_full_results=False): + # pylint: disable=too-many-arguments + def __init__(self, execute_module=None, task_vars=None, tmp=None, want_full_results=False, + templar=None): # store a method for executing ansible modules from the check self._execute_module = execute_module # the task variables and tmpdir passed into the health checker task self.task_vars = task_vars or {} + # We may need to template some task_vars + self._templar = templar self.tmp = tmp # a boolean for disabling the gathering of results (files, computations) that won't # actually be recorded/used diff --git a/roles/openshift_health_checker/openshift_checks/disk_availability.py b/roles/openshift_health_checker/openshift_checks/disk_availability.py index cdf56e959..87e6146d4 100644 --- a/roles/openshift_health_checker/openshift_checks/disk_availability.py +++ b/roles/openshift_health_checker/openshift_checks/disk_availability.py @@ -1,6 +1,7 @@ """Check that there is enough disk space in predefined paths.""" import tempfile +import os.path from openshift_checks import OpenShiftCheck, OpenShiftCheckException @@ -15,31 +16,31 @@ class DiskAvailability(OpenShiftCheck): # https://docs.openshift.org/latest/install_config/install/prerequisites.html#system-requirements recommended_disk_space_bytes = { '/var': { - 'masters': 40 * 10**9, - 'nodes': 15 * 10**9, - 'etcd': 20 * 10**9, + 'oo_masters_to_config': 40 * 10**9, + 'oo_nodes_to_config': 15 * 10**9, + 'oo_etcd_to_config': 20 * 10**9, }, # Used to copy client binaries into, # see roles/openshift_cli/library/openshift_container_binary_sync.py. '/usr/local/bin': { - 'masters': 1 * 10**9, - 'nodes': 1 * 10**9, - 'etcd': 1 * 10**9, + 'oo_masters_to_config': 1 * 10**9, + 'oo_nodes_to_config': 1 * 10**9, + 'oo_etcd_to_config': 1 * 10**9, }, # Used as temporary storage in several cases. tempfile.gettempdir(): { - 'masters': 1 * 10**9, - 'nodes': 1 * 10**9, - 'etcd': 1 * 10**9, + 'oo_masters_to_config': 1 * 10**9, + 'oo_nodes_to_config': 1 * 10**9, + 'oo_etcd_to_config': 1 * 10**9, }, } # recommended disk space for each location under an upgrade context recommended_disk_upgrade_bytes = { '/var': { - 'masters': 10 * 10**9, - 'nodes': 5 * 10 ** 9, - 'etcd': 5 * 10 ** 9, + 'oo_masters_to_config': 10 * 10**9, + 'oo_nodes_to_config': 5 * 10 ** 9, + 'oo_etcd_to_config': 5 * 10 ** 9, }, } @@ -61,9 +62,9 @@ class DiskAvailability(OpenShiftCheck): number = float(user_config) user_config = { '/var': { - 'masters': number, - 'nodes': number, - 'etcd': number, + 'oo_masters_to_config': number, + 'oo_nodes_to_config': number, + 'oo_etcd_to_config': number, }, } except TypeError: @@ -121,11 +122,21 @@ class DiskAvailability(OpenShiftCheck): return {} + def find_ansible_submounts(self, path): + """Return a list of ansible_mounts that are below the given path.""" + base = os.path.join(path, "") + return [ + mount + for mount in self.get_var("ansible_mounts") + if mount["mount"].startswith(base) + ] + def free_bytes(self, path): """Return the size available in path based on ansible_mounts.""" + submounts = sum(mnt.get('size_available', 0) for mnt in self.find_ansible_submounts(path)) mount = self.find_ansible_mount(path) try: - return mount['size_available'] + return mount['size_available'] + submounts except KeyError: raise OpenShiftCheckException( 'Unable to retrieve disk availability for "{path}".\n' 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 fa07c1dde..4f91f6bb3 100644 --- a/roles/openshift_health_checker/openshift_checks/docker_image_availability.py +++ b/roles/openshift_health_checker/openshift_checks/docker_image_availability.py @@ -1,5 +1,7 @@ """Check that required Docker images are available.""" +import re +from pipes import quote from ansible.module_utils import six from openshift_checks import OpenShiftCheck from openshift_checks.mixins import DockerHostMixin @@ -10,12 +12,16 @@ DEPLOYMENT_IMAGE_INFO = { "origin": { "namespace": "openshift", "name": "origin", - "registry_console_image": "cockpit/kubernetes", + "registry_console_prefix": "cockpit/", + "registry_console_basename": "kubernetes", + "registry_console_default_version": "latest", }, "openshift-enterprise": { "namespace": "openshift3", "name": "ose", - "registry_console_image": "registry.access.redhat.com/openshift3/registry-console", + "registry_console_prefix": "openshift3/", + "registry_console_basename": "registry-console", + "registry_console_default_version": "${short_version}", }, } @@ -33,10 +39,44 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck): # we use python-docker-py to check local docker for images, and skopeo # to look for images available remotely without waiting to pull them. dependencies = ["python-docker-py", "skopeo"] - skopeo_img_check_command = "timeout 10 skopeo inspect --tls-verify=false docker://{registry}/{image}" + # command for checking if remote registries have an image, without docker pull + skopeo_command = "timeout 10 skopeo inspect --tls-verify={tls} {creds} docker://{registry}/{image}" + skopeo_example_command = "skopeo inspect [--tls-verify=false] [--creds=<user>:<pass>] docker://<registry>/<image>" def __init__(self, *args, **kwargs): super(DockerImageAvailability, self).__init__(*args, **kwargs) + + self.registries = dict( + # set of registries that need to be checked insecurely (note: not accounting for CIDR entries) + insecure=set(self.ensure_list("openshift_docker_insecure_registries")), + # set of registries that should never be queried even if given in the image + blocked=set(self.ensure_list("openshift_docker_blocked_registries")), + ) + + # ordered list of registries (according to inventory vars) that docker will try for unscoped images + regs = self.ensure_list("openshift_docker_additional_registries") + # currently one of these registries is added whether the user wants it or not. + deployment_type = self.get_var("openshift_deployment_type") + if deployment_type == "origin" and "docker.io" not in regs: + regs.append("docker.io") + elif deployment_type == 'openshift-enterprise' and "registry.access.redhat.com" not in regs: + regs.append("registry.access.redhat.com") + self.registries["configured"] = regs + + # for the oreg_url registry there may be credentials specified + components = self.get_var("oreg_url", default="").split('/') + self.registries["oreg"] = "" if len(components) < 3 else components[0] + + # Retrieve and template registry credentials, if provided + self.skopeo_command_creds = "" + oreg_auth_user = self.get_var('oreg_auth_user', default='') + oreg_auth_password = self.get_var('oreg_auth_password', default='') + if oreg_auth_user != '' and oreg_auth_password != '': + if self._templar is not None: + oreg_auth_user = self._templar.template(oreg_auth_user) + oreg_auth_password = self._templar.template(oreg_auth_password) + self.skopeo_command_creds = "--creds={}:{}".format(quote(oreg_auth_user), quote(oreg_auth_password)) + # record whether we could reach a registry or not (and remember results) self.reachable_registries = {} @@ -62,26 +102,25 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck): if not missing_images: return {} - registries = self.known_docker_registries() - if not registries: - return {"failed": True, "msg": "Unable to retrieve any docker registries."} - - available_images = self.available_images(missing_images, registries) + available_images = self.available_images(missing_images) unavailable_images = set(missing_images) - set(available_images) if unavailable_images: - registries = [ - reg if self.reachable_registries.get(reg, True) else reg + " (unreachable)" - for reg in registries - ] + unreachable = [reg for reg, reachable in self.reachable_registries.items() if not reachable] + unreachable_msg = "Failed connecting to: {}\n".format(", ".join(unreachable)) + blocked_msg = "Blocked registries: {}\n".format(", ".join(self.registries["blocked"])) msg = ( - "One or more required Docker images are not available:\n {}\n" - "Configured registries: {}\n" - "Checked by: {}" + "One or more required container images are not available:\n {missing}\n" + "Checked with: {cmd}\n" + "Default registries searched: {registries}\n" + "{blocked}" + "{unreachable}" ).format( - ",\n ".join(sorted(unavailable_images)), - ", ".join(registries), - self.skopeo_img_check_command + missing=",\n ".join(sorted(unavailable_images)), + cmd=self.skopeo_example_command, + registries=", ".join(self.registries["configured"]), + blocked=blocked_msg if self.registries["blocked"] else "", + unreachable=unreachable_msg if unreachable else "", ) return dict(failed=True, msg=msg) @@ -114,35 +153,53 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck): # template for images that run on top of OpenShift image_url = "{}/{}-{}:{}".format(image_info["namespace"], image_info["name"], "${component}", "${version}") image_url = self.get_var("oreg_url", default="") or image_url - if 'nodes' in host_groups: + if 'oo_nodes_to_config' in host_groups: for suffix in NODE_IMAGE_SUFFIXES: required.add(image_url.replace("${component}", suffix).replace("${version}", image_tag)) - # The registry-console is for some reason not prefixed with ose- like the other components. - # Nor is it versioned the same, so just look for latest. - # Also a completely different name is used for Origin. - required.add(image_info["registry_console_image"]) + if self.get_var("osm_use_cockpit", default=True, convert=bool): + required.add(self._registry_console_image(image_tag, image_info)) # images for containerized components if self.get_var("openshift", "common", "is_containerized"): components = set() - if 'nodes' in host_groups: + if 'oo_nodes_to_config' in host_groups: components.update(["node", "openvswitch"]) - if 'masters' in host_groups: # name is "origin" or "ose" + if 'oo_masters_to_config' in host_groups: # name is "origin" or "ose" components.add(image_info["name"]) for component in components: required.add("{}/{}:{}".format(image_info["namespace"], component, image_tag)) - if 'etcd' in host_groups: # special case, note it is the same for origin/enterprise + if 'oo_etcd_to_config' in host_groups: # special case, note it is the same for origin/enterprise required.add("registry.access.redhat.com/rhel7/etcd") # and no image tag return required + def _registry_console_image(self, image_tag, image_info): + """Returns image with logic to parallel what happens with the registry-console template.""" + # The registry-console is for some reason not prefixed with ose- like the other components. + # Nor is it versioned the same. Also a completely different name is used for Origin. + prefix = self.get_var( + "openshift_cockpit_deployer_prefix", + default=image_info["registry_console_prefix"], + ) + basename = self.get_var( + "openshift_cockpit_deployer_basename", + default=image_info["registry_console_basename"], + ) + + # enterprise template just uses v3.6, v3.7, etc + match = re.match(r'v\d+\.\d+', image_tag) + short_version = match.group() if match else image_tag + version = image_info["registry_console_default_version"].replace("${short_version}", short_version) + version = self.get_var("openshift_cockpit_deployer_version", default=version) + + return prefix + basename + ':' + version + def local_images(self, images): """Filter a list of images and return those available locally.""" - registries = self.known_docker_registries() found_images = [] for image in images: # docker could have the image name as-is or prefixed with any registry - imglist = [image] + [reg + "/" + image for reg in registries] + imglist = [image] + [reg + "/" + image for reg in self.registries["configured"]] if self.is_image_local(imglist): found_images.append(image) return found_images @@ -152,37 +209,27 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck): result = self.execute_module("docker_image_facts", {"name": image}) return bool(result.get("images")) and not result.get("failed") - def known_docker_registries(self): - """Build a list of docker registries available according to inventory vars.""" - regs = self.get_var("openshift_docker_additional_registries", default=[]) + def ensure_list(self, registry_param): + """Return the task var as a list.""" # https://bugzilla.redhat.com/show_bug.cgi?id=1497274 - # if the result was a string type, place it into a list. We must do this + # If the result was a string type, place it into a list. We must do this # as using list() on a string will split the string into its characters. - if isinstance(regs, six.string_types): - regs = [regs] - else: - # Otherwise cast to a list as was done previously - regs = list(regs) + # Otherwise cast to a list as was done previously. + registry = self.get_var(registry_param, default=[]) + if not isinstance(registry, six.string_types): + return list(registry) + return self.normalize(registry) - deployment_type = self.get_var("openshift_deployment_type") - if deployment_type == "origin" and "docker.io" not in regs: - regs.append("docker.io") - elif deployment_type == 'openshift-enterprise' and "registry.access.redhat.com" not in regs: - regs.append("registry.access.redhat.com") - - return regs - - def available_images(self, images, default_registries): + def available_images(self, images): """Search remotely for images. Returns: list of images found.""" return [ image for image in images - if self.is_available_skopeo_image(image, default_registries) + if self.is_available_skopeo_image(image) ] - def is_available_skopeo_image(self, image, default_registries): + def is_available_skopeo_image(self, image): """Use Skopeo to determine if required image exists in known registry(s).""" - registries = default_registries - + registries = self.registries["configured"] # If image already includes a registry, only use that. # NOTE: This logic would incorrectly identify images that do not use a namespace, e.g. # registry.access.redhat.com/rhel7 as if the registry were a namespace. @@ -193,13 +240,18 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck): registries = [registry] for registry in registries: + if registry in self.registries["blocked"]: + continue # blocked will never be consulted if registry not in self.reachable_registries: self.reachable_registries[registry] = self.connect_to_registry(registry) if not self.reachable_registries[registry]: - continue + continue # do not keep trying unreachable registries + + args = dict(registry=registry, image=image) + args["tls"] = "false" if registry in self.registries["insecure"] else "true" + args["creds"] = self.skopeo_command_creds if registry == self.registries["oreg"] else "" - args = {"_raw_params": self.skopeo_img_check_command.format(registry=registry, image=image)} - result = self.execute_module_with_retries("command", args) + result = self.execute_module_with_retries("command", {"_raw_params": self.skopeo_command.format(**args)}) if result.get("rc", 0) == 0 and not result.get("failed"): return True if result.get("rc") == 124: # RC 124 == timed out; mark unreachable diff --git a/roles/openshift_health_checker/openshift_checks/docker_storage.py b/roles/openshift_health_checker/openshift_checks/docker_storage.py index 0558ddf14..6808d8b2f 100644 --- a/roles/openshift_health_checker/openshift_checks/docker_storage.py +++ b/roles/openshift_health_checker/openshift_checks/docker_storage.py @@ -14,7 +14,7 @@ class DockerStorage(DockerHostMixin, OpenShiftCheck): """ name = "docker_storage" - tags = ["pre-install", "health", "preflight"] + tags = ["health", "preflight"] dependencies = ["python-docker-py"] storage_drivers = ["devicemapper", "overlay", "overlay2"] diff --git a/roles/openshift_health_checker/openshift_checks/etcd_traffic.py b/roles/openshift_health_checker/openshift_checks/etcd_traffic.py index b4c8957e9..8b20ccb49 100644 --- a/roles/openshift_health_checker/openshift_checks/etcd_traffic.py +++ b/roles/openshift_health_checker/openshift_checks/etcd_traffic.py @@ -12,7 +12,7 @@ class EtcdTraffic(OpenShiftCheck): def is_active(self): """Skip hosts that do not have etcd in their group names.""" group_names = self.get_var("group_names", default=[]) - valid_group_names = "etcd" in group_names + valid_group_names = "oo_etcd_to_config" in group_names version = self.get_major_minor_version(self.get_var("openshift_image_tag")) valid_version = version in ((3, 4), (3, 5)) diff --git a/roles/openshift_health_checker/openshift_checks/etcd_volume.py b/roles/openshift_health_checker/openshift_checks/etcd_volume.py index 79955cb2f..3d75da6f9 100644 --- a/roles/openshift_health_checker/openshift_checks/etcd_volume.py +++ b/roles/openshift_health_checker/openshift_checks/etcd_volume.py @@ -15,7 +15,11 @@ class EtcdVolume(OpenShiftCheck): etcd_mount_path = "/var/lib/etcd" def is_active(self): - etcd_hosts = self.get_var("groups", "etcd", default=[]) or self.get_var("groups", "masters", default=[]) or [] + etcd_hosts = ( + self.get_var("groups", "oo_etcd_to_config", default=[]) or + self.get_var("groups", "oo_masters_to_config", default=[]) or + [] + ) is_etcd_host = self.get_var("ansible_host") in etcd_hosts return super(EtcdVolume, self).is_active() and is_etcd_host diff --git a/roles/openshift_health_checker/openshift_checks/logging/fluentd_config.py b/roles/openshift_health_checker/openshift_checks/logging/fluentd_config.py index d783e6760..e93cc9028 100644 --- a/roles/openshift_health_checker/openshift_checks/logging/fluentd_config.py +++ b/roles/openshift_health_checker/openshift_checks/logging/fluentd_config.py @@ -46,7 +46,7 @@ class FluentdConfig(LoggingCheck): # if check is running on a master, retrieve all running pods # and check any pod's container for the env var "USE_JOURNAL" group_names = self.get_var("group_names") - if "masters" in group_names: + if "oo_masters_to_config" in group_names: use_journald = self.check_fluentd_env_var() docker_info = self.execute_module("docker_info", {}) diff --git a/roles/openshift_health_checker/openshift_checks/memory_availability.py b/roles/openshift_health_checker/openshift_checks/memory_availability.py index 765ba072d..e7a8ec976 100644 --- a/roles/openshift_health_checker/openshift_checks/memory_availability.py +++ b/roles/openshift_health_checker/openshift_checks/memory_availability.py @@ -14,9 +14,9 @@ class MemoryAvailability(OpenShiftCheck): # Values taken from the official installation documentation: # https://docs.openshift.org/latest/install_config/install/prerequisites.html#system-requirements recommended_memory_bytes = { - "masters": 16 * GIB, - "nodes": 8 * GIB, - "etcd": 8 * GIB, + "oo_masters_to_config": 16 * GIB, + "oo_nodes_to_config": 8 * GIB, + "oo_etcd_to_config": 8 * GIB, } # https://access.redhat.com/solutions/3006511 physical RAM is partly reserved from memtotal memtotal_adjustment = 1 * GIB diff --git a/roles/openshift_health_checker/openshift_checks/mixins.py b/roles/openshift_health_checker/openshift_checks/mixins.py index b90ebf6dd..cfbdea303 100644 --- a/roles/openshift_health_checker/openshift_checks/mixins.py +++ b/roles/openshift_health_checker/openshift_checks/mixins.py @@ -21,9 +21,11 @@ class DockerHostMixin(object): def is_active(self): """Only run on hosts that depend on Docker.""" - is_containerized = self.get_var("openshift", "common", "is_containerized") - is_node = "nodes" in self.get_var("group_names", default=[]) - return super(DockerHostMixin, self).is_active() and (is_containerized or is_node) + group_names = set(self.get_var("group_names", default=[])) + needs_docker = set(["oo_nodes_to_config"]) + if self.get_var("openshift.common.is_containerized"): + needs_docker.update(["oo_masters_to_config", "oo_etcd_to_config"]) + return super(DockerHostMixin, self).is_active() and bool(group_names.intersection(needs_docker)) def ensure_dependencies(self): """ diff --git a/roles/openshift_health_checker/openshift_checks/ovs_version.py b/roles/openshift_health_checker/openshift_checks/ovs_version.py index 363c12def..0cad19842 100644 --- a/roles/openshift_health_checker/openshift_checks/ovs_version.py +++ b/roles/openshift_health_checker/openshift_checks/ovs_version.py @@ -16,7 +16,8 @@ class OvsVersion(NotContainerizedMixin, OpenShiftCheck): tags = ["health"] openshift_to_ovs_version = { - "3.6": ["2.6", "2.7"], + "3.7": ["2.6", "2.7", "2.8"], + "3.6": ["2.6", "2.7", "2.8"], "3.5": ["2.6", "2.7"], "3.4": "2.4", } @@ -24,7 +25,7 @@ class OvsVersion(NotContainerizedMixin, OpenShiftCheck): def is_active(self): """Skip hosts that do not have package requirements.""" group_names = self.get_var("group_names", default=[]) - master_or_node = 'masters' in group_names or 'nodes' in group_names + master_or_node = 'oo_masters_to_config' in group_names or 'oo_nodes_to_config' in group_names return super(OvsVersion, self).is_active() and master_or_node def run(self): diff --git a/roles/openshift_health_checker/openshift_checks/package_availability.py b/roles/openshift_health_checker/openshift_checks/package_availability.py index 21355c2f0..090e438ff 100644 --- a/roles/openshift_health_checker/openshift_checks/package_availability.py +++ b/roles/openshift_health_checker/openshift_checks/package_availability.py @@ -20,9 +20,9 @@ class PackageAvailability(NotContainerizedMixin, OpenShiftCheck): packages = set() - if "masters" in group_names: + if "oo_masters_to_config" in group_names: packages.update(self.master_packages(rpm_prefix)) - if "nodes" in group_names: + if "oo_nodes_to_config" in group_names: packages.update(self.node_packages(rpm_prefix)) args = {"packages": sorted(set(packages))} diff --git a/roles/openshift_health_checker/openshift_checks/package_version.py b/roles/openshift_health_checker/openshift_checks/package_version.py index d4aec3ed8..13a91dadf 100644 --- a/roles/openshift_health_checker/openshift_checks/package_version.py +++ b/roles/openshift_health_checker/openshift_checks/package_version.py @@ -16,7 +16,8 @@ class PackageVersion(NotContainerizedMixin, OpenShiftCheck): openshift_to_ovs_version = { (3, 4): "2.4", (3, 5): ["2.6", "2.7"], - (3, 6): ["2.6", "2.7"], + (3, 6): ["2.6", "2.7", "2.8"], + (3, 7): ["2.6", "2.7", "2.8"], } openshift_to_docker_version = { @@ -36,7 +37,7 @@ class PackageVersion(NotContainerizedMixin, OpenShiftCheck): def is_active(self): """Skip hosts that do not have package requirements.""" group_names = self.get_var("group_names", default=[]) - master_or_node = 'masters' in group_names or 'nodes' in group_names + master_or_node = 'oo_masters_to_config' in group_names or 'oo_nodes_to_config' in group_names return super(PackageVersion, self).is_active() and master_or_node def run(self): diff --git a/roles/openshift_health_checker/test/action_plugin_test.py b/roles/openshift_health_checker/test/action_plugin_test.py index f14887303..40ad27d5d 100644 --- a/roles/openshift_health_checker/test/action_plugin_test.py +++ b/roles/openshift_health_checker/test/action_plugin_test.py @@ -94,6 +94,7 @@ def skipped(result): {}, ]) def test_action_plugin_missing_openshift_facts(plugin, task_vars, monkeypatch): + monkeypatch.setattr(plugin, 'load_known_checks', lambda *_: {}) monkeypatch.setattr('openshift_health_check.resolve_checks', lambda *args: ['fake_check']) result = plugin.run(tmp=None, task_vars=task_vars) diff --git a/roles/openshift_health_checker/test/disk_availability_test.py b/roles/openshift_health_checker/test/disk_availability_test.py index 9ae679b79..7acdb40ec 100644 --- a/roles/openshift_health_checker/test/disk_availability_test.py +++ b/roles/openshift_health_checker/test/disk_availability_test.py @@ -4,11 +4,11 @@ from openshift_checks.disk_availability import DiskAvailability, OpenShiftCheckE @pytest.mark.parametrize('group_names,is_active', [ - (['masters'], True), - (['nodes'], True), - (['etcd'], True), - (['masters', 'nodes'], True), - (['masters', 'etcd'], True), + (['oo_masters_to_config'], True), + (['oo_nodes_to_config'], True), + (['oo_etcd_to_config'], True), + (['oo_masters_to_config', 'oo_nodes_to_config'], True), + (['oo_masters_to_config', 'oo_etcd_to_config'], True), ([], False), (['lb'], False), (['nfs'], False), @@ -39,7 +39,7 @@ def test_is_active(group_names, is_active): ]) def test_cannot_determine_available_disk(desc, ansible_mounts, expect_chunks): task_vars = dict( - group_names=['masters'], + group_names=['oo_masters_to_config'], ansible_mounts=ansible_mounts, ) @@ -52,7 +52,7 @@ def test_cannot_determine_available_disk(desc, ansible_mounts, expect_chunks): @pytest.mark.parametrize('group_names,configured_min,ansible_mounts', [ ( - ['masters'], + ['oo_masters_to_config'], 0, [{ 'mount': '/', @@ -60,7 +60,7 @@ def test_cannot_determine_available_disk(desc, ansible_mounts, expect_chunks): }], ), ( - ['nodes'], + ['oo_nodes_to_config'], 0, [{ 'mount': '/', @@ -68,7 +68,7 @@ def test_cannot_determine_available_disk(desc, ansible_mounts, expect_chunks): }], ), ( - ['etcd'], + ['oo_etcd_to_config'], 0, [{ 'mount': '/', @@ -76,7 +76,7 @@ def test_cannot_determine_available_disk(desc, ansible_mounts, expect_chunks): }], ), ( - ['etcd'], + ['oo_etcd_to_config'], 1, # configure lower threshold [{ 'mount': '/', @@ -84,7 +84,7 @@ def test_cannot_determine_available_disk(desc, ansible_mounts, expect_chunks): }], ), ( - ['etcd'], + ['oo_etcd_to_config'], 0, [{ # not enough space on / ... @@ -96,6 +96,24 @@ def test_cannot_determine_available_disk(desc, ansible_mounts, expect_chunks): 'size_available': 20 * 10**9 + 1, }], ), + ( + ['oo_masters_to_config'], + 0, + [{ + 'mount': '/', + 'size_available': 2 * 10**9, + }, { # not enough directly on /var + 'mount': '/var', + 'size_available': 10 * 10**9 + 1, + }, { + # but subdir mounts add up to enough + 'mount': '/var/lib/docker', + 'size_available': 20 * 10**9 + 1, + }, { + 'mount': '/var/lib/origin', + 'size_available': 20 * 10**9 + 1, + }], + ), ]) def test_succeeds_with_recommended_disk_space(group_names, configured_min, ansible_mounts): task_vars = dict( @@ -104,15 +122,16 @@ def test_succeeds_with_recommended_disk_space(group_names, configured_min, ansib ansible_mounts=ansible_mounts, ) - result = DiskAvailability(fake_execute_module, task_vars).run() + check = DiskAvailability(fake_execute_module, task_vars) + check.run() - assert not result.get('failed', False) + assert not check.failures @pytest.mark.parametrize('name,group_names,configured_min,ansible_mounts,expect_chunks', [ ( 'test with no space available', - ['masters'], + ['oo_masters_to_config'], 0, [{ 'mount': '/', @@ -122,7 +141,7 @@ def test_succeeds_with_recommended_disk_space(group_names, configured_min, ansib ), ( 'test with a higher configured required value', - ['masters'], + ['oo_masters_to_config'], 100, # set a higher threshold [{ 'mount': '/', @@ -132,7 +151,7 @@ def test_succeeds_with_recommended_disk_space(group_names, configured_min, ansib ), ( 'test with 1GB available, but "0" GB space requirement', - ['nodes'], + ['oo_nodes_to_config'], 0, [{ 'mount': '/', @@ -142,7 +161,7 @@ def test_succeeds_with_recommended_disk_space(group_names, configured_min, ansib ), ( 'test with no space available, but "0" GB space requirement', - ['etcd'], + ['oo_etcd_to_config'], 0, [{ 'mount': '/', @@ -152,7 +171,7 @@ def test_succeeds_with_recommended_disk_space(group_names, configured_min, ansib ), ( 'test with enough space for a node, but not for a master', - ['nodes', 'masters'], + ['oo_nodes_to_config', 'oo_masters_to_config'], 0, [{ 'mount': '/', @@ -162,7 +181,7 @@ def test_succeeds_with_recommended_disk_space(group_names, configured_min, ansib ), ( 'test failure with enough space on "/", but not enough on "/var"', - ['etcd'], + ['oo_etcd_to_config'], 0, [{ # enough space on / ... @@ -194,7 +213,7 @@ def test_fails_with_insufficient_disk_space(name, group_names, configured_min, a @pytest.mark.parametrize('name,group_names,context,ansible_mounts,failed,extra_words', [ ( 'test without enough space for master under "upgrade" context', - ['nodes', 'masters'], + ['oo_nodes_to_config', 'oo_masters_to_config'], "upgrade", [{ 'mount': '/', @@ -206,7 +225,7 @@ def test_fails_with_insufficient_disk_space(name, group_names, configured_min, a ), ( 'test with enough space for master under "upgrade" context', - ['nodes', 'masters'], + ['oo_nodes_to_config', 'oo_masters_to_config'], "upgrade", [{ 'mount': '/', @@ -218,7 +237,7 @@ def test_fails_with_insufficient_disk_space(name, group_names, configured_min, a ), ( 'test with not enough space for master, and non-upgrade context', - ['nodes', 'masters'], + ['oo_nodes_to_config', 'oo_masters_to_config'], "health", [{ 'mount': '/', 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 c523ffd5c..ec46c3b4b 100644 --- a/roles/openshift_health_checker/test/docker_image_availability_test.py +++ b/roles/openshift_health_checker/test/docker_image_availability_test.py @@ -1,6 +1,6 @@ import pytest -from openshift_checks.docker_image_availability import DockerImageAvailability +from openshift_checks.docker_image_availability import DockerImageAvailability, DEPLOYMENT_IMAGE_INFO @pytest.fixture() @@ -16,19 +16,19 @@ def task_vars(): ), openshift_deployment_type='origin', openshift_image_tag='', - group_names=['nodes', 'masters'], + group_names=['oo_nodes_to_config', 'oo_masters_to_config'], ) @pytest.mark.parametrize('deployment_type, is_containerized, group_names, expect_active', [ - ("origin", True, [], True), - ("openshift-enterprise", True, [], True), ("invalid", True, [], False), ("", True, [], False), ("origin", False, [], False), ("openshift-enterprise", False, [], False), - ("origin", False, ["nodes", "masters"], True), - ("openshift-enterprise", False, ["etcd"], False), + ("origin", False, ["oo_nodes_to_config", "oo_masters_to_config"], True), + ("openshift-enterprise", False, ["oo_etcd_to_config"], False), + ("origin", True, ["nfs"], False), + ("openshift-enterprise", True, ["lb"], False), ]) def test_is_active(task_vars, deployment_type, is_containerized, group_names, expect_active): task_vars['openshift_deployment_type'] = deployment_type @@ -98,40 +98,7 @@ def test_all_images_unavailable(task_vars): actual = check.run() assert actual['failed'] - assert "required Docker images are not available" in actual['msg'] - - -def test_no_known_registries(): - def execute_module(module_name=None, *_): - if module_name == "command": - return { - 'failed': True, - } - - return { - 'changed': False, - } - - def mock_known_docker_registries(): - return [] - - dia = DockerImageAvailability(execute_module, task_vars=dict( - openshift=dict( - common=dict( - service_type='origin', - is_containerized=False, - is_atomic=False, - ) - ), - openshift_docker_additional_registries=["docker.io"], - openshift_deployment_type="openshift-enterprise", - openshift_image_tag='latest', - group_names=['nodes', 'masters'], - )) - dia.known_docker_registries = mock_known_docker_registries - actual = dia.run() - assert actual['failed'] - assert "Unable to retrieve any docker registries." in actual['msg'] + assert "required container images are not available" in actual['msg'] @pytest.mark.parametrize("message,extra_words", [ @@ -172,13 +139,13 @@ def test_skopeo_update_failure(task_vars, message, extra_words): "spam/eggs:v1", ["test.reg"], True, True, False, - {"test.reg": False}, + {"test.reg": False, "docker.io": False}, ), ( "spam/eggs:v1", ["test.reg"], False, True, False, - {"test.reg": True}, + {"test.reg": True, "docker.io": True}, ), ( "eggs.reg/spam/eggs:v1", ["test.reg"], @@ -195,44 +162,46 @@ def test_registry_availability(image, registries, connection_test_failed, skopeo elif module_name == "command": return dict(msg="msg", failed=skopeo_failed) - check = DockerImageAvailability(execute_module, task_vars()) + tv = task_vars() + tv.update({"openshift_docker_additional_registries": registries}) + check = DockerImageAvailability(execute_module, tv) check._module_retry_interval = 0 - available = check.is_available_skopeo_image(image, registries) + available = check.is_available_skopeo_image(image) assert available == expect_success assert expect_registries_reached == check.reachable_registries @pytest.mark.parametrize("deployment_type, is_containerized, groups, oreg_url, expected", [ ( # standard set of stuff required on nodes - "origin", False, ['nodes'], None, + "origin", False, ['oo_nodes_to_config'], "", set([ 'openshift/origin-pod:vtest', 'openshift/origin-deployer:vtest', 'openshift/origin-docker-registry:vtest', 'openshift/origin-haproxy-router:vtest', - 'cockpit/kubernetes', # origin version of registry-console + 'cockpit/kubernetes:latest', # origin version of registry-console ]) ), ( # set a different URL for images - "origin", False, ['nodes'], 'foo.io/openshift/origin-${component}:${version}', + "origin", False, ['oo_nodes_to_config'], 'foo.io/openshift/origin-${component}:${version}', set([ 'foo.io/openshift/origin-pod:vtest', 'foo.io/openshift/origin-deployer:vtest', 'foo.io/openshift/origin-docker-registry:vtest', 'foo.io/openshift/origin-haproxy-router:vtest', - 'cockpit/kubernetes', # AFAICS this is not built from the URL + 'cockpit/kubernetes:latest', # AFAICS this is not built from the URL ]) ), ( - "origin", True, ['nodes', 'masters', 'etcd'], None, + "origin", True, ['oo_nodes_to_config', 'oo_masters_to_config', 'oo_etcd_to_config'], "", set([ # images running on top of openshift 'openshift/origin-pod:vtest', 'openshift/origin-deployer:vtest', 'openshift/origin-docker-registry:vtest', 'openshift/origin-haproxy-router:vtest', - 'cockpit/kubernetes', + 'cockpit/kubernetes:latest', # containerized component images 'openshift/origin:vtest', 'openshift/node:vtest', @@ -241,21 +210,21 @@ def test_registry_availability(image, registries, connection_test_failed, skopeo ]) ), ( # enterprise images - "openshift-enterprise", True, ['nodes'], 'foo.io/openshift3/ose-${component}:f13ac45', + "openshift-enterprise", True, ['oo_nodes_to_config'], 'foo.io/openshift3/ose-${component}:f13ac45', set([ 'foo.io/openshift3/ose-pod:f13ac45', 'foo.io/openshift3/ose-deployer:f13ac45', 'foo.io/openshift3/ose-docker-registry:f13ac45', 'foo.io/openshift3/ose-haproxy-router:f13ac45', # registry-console is not constructed/versioned the same as the others. - 'registry.access.redhat.com/openshift3/registry-console', + 'openshift3/registry-console:vtest', # containerized images aren't built from oreg_url 'openshift3/node:vtest', 'openshift3/openvswitch:vtest', ]) ), ( - "openshift-enterprise", True, ['etcd', 'lb'], 'foo.io/openshift3/ose-${component}:f13ac45', + "openshift-enterprise", True, ['oo_etcd_to_config', 'lb'], 'foo.io/openshift3/ose-${component}:f13ac45', set([ 'registry.access.redhat.com/rhel7/etcd', # lb does not yet come in a containerized version @@ -280,6 +249,42 @@ def test_required_images(deployment_type, is_containerized, groups, oreg_url, ex assert expected == DockerImageAvailability(task_vars=task_vars).required_images() +@pytest.mark.parametrize("task_vars, expected", [ + ( + dict( + openshift_deployment_type="origin", + openshift_image_tag="vtest", + ), + "cockpit/kubernetes:latest", + ), ( + dict( + openshift_deployment_type="openshift-enterprise", + openshift_image_tag="vtest", + ), + "openshift3/registry-console:vtest", + ), ( + dict( + openshift_deployment_type="openshift-enterprise", + openshift_image_tag="v3.7.0-alpha.0", + openshift_cockpit_deployer_prefix="registry.example.com/spam/", + ), + "registry.example.com/spam/registry-console:v3.7", + ), ( + dict( + openshift_deployment_type="origin", + openshift_image_tag="v3.7.0-alpha.0", + openshift_cockpit_deployer_prefix="registry.example.com/eggs/", + openshift_cockpit_deployer_version="spam", + ), + "registry.example.com/eggs/kubernetes:spam", + ), +]) +def test_registry_console_image(task_vars, expected): + info = DEPLOYMENT_IMAGE_INFO[task_vars["openshift_deployment_type"]] + tag = task_vars["openshift_image_tag"] + assert expected == DockerImageAvailability(task_vars=task_vars)._registry_console_image(tag, info) + + def test_containerized_etcd(): task_vars = dict( openshift=dict( @@ -288,7 +293,7 @@ def test_containerized_etcd(): ), ), openshift_deployment_type="origin", - group_names=['etcd'], + group_names=['oo_etcd_to_config'], ) expected = set(['registry.access.redhat.com/rhel7/etcd']) assert expected == DockerImageAvailability(task_vars=task_vars).required_images() diff --git a/roles/openshift_health_checker/test/docker_storage_test.py b/roles/openshift_health_checker/test/docker_storage_test.py index e0dccc062..8fa68c378 100644 --- a/roles/openshift_health_checker/test/docker_storage_test.py +++ b/roles/openshift_health_checker/test/docker_storage_test.py @@ -5,9 +5,9 @@ from openshift_checks.docker_storage import DockerStorage @pytest.mark.parametrize('is_containerized, group_names, is_active', [ - (False, ["masters", "etcd"], False), - (False, ["masters", "nodes"], True), - (True, ["etcd"], True), + (False, ["oo_masters_to_config", "oo_etcd_to_config"], False), + (False, ["oo_masters_to_config", "oo_nodes_to_config"], True), + (True, ["oo_etcd_to_config"], True), ]) def test_is_active(is_containerized, group_names, is_active): task_vars = dict( diff --git a/roles/openshift_health_checker/test/etcd_traffic_test.py b/roles/openshift_health_checker/test/etcd_traffic_test.py index fae3e578d..dd6f4ad81 100644 --- a/roles/openshift_health_checker/test/etcd_traffic_test.py +++ b/roles/openshift_health_checker/test/etcd_traffic_test.py @@ -4,14 +4,14 @@ from openshift_checks.etcd_traffic import EtcdTraffic @pytest.mark.parametrize('group_names,version,is_active', [ - (['masters'], "3.5", False), - (['masters'], "3.6", False), - (['nodes'], "3.4", False), - (['etcd'], "3.4", True), - (['etcd'], "1.5", True), - (['etcd'], "3.1", False), - (['masters', 'nodes'], "3.5", False), - (['masters', 'etcd'], "3.5", True), + (['oo_masters_to_config'], "3.5", False), + (['oo_masters_to_config'], "3.6", False), + (['oo_nodes_to_config'], "3.4", False), + (['oo_etcd_to_config'], "3.4", True), + (['oo_etcd_to_config'], "1.5", True), + (['oo_etcd_to_config'], "3.1", False), + (['oo_masters_to_config', 'oo_nodes_to_config'], "3.5", False), + (['oo_masters_to_config', 'oo_etcd_to_config'], "3.5", True), ([], "3.4", False), ]) def test_is_active(group_names, version, is_active): @@ -23,9 +23,9 @@ def test_is_active(group_names, version, is_active): @pytest.mark.parametrize('group_names,matched,failed,extra_words', [ - (["masters"], True, True, ["Higher than normal", "traffic"]), - (["masters", "etcd"], False, False, []), - (["etcd"], False, False, []), + (["oo_masters_to_config"], True, True, ["Higher than normal", "traffic"]), + (["oo_masters_to_config", "oo_etcd_to_config"], False, False, []), + (["oo_etcd_to_config"], False, False, []), ]) def test_log_matches_high_traffic_msg(group_names, matched, failed, extra_words): def execute_module(module_name, *_): diff --git a/roles/openshift_health_checker/test/fluentd_config_test.py b/roles/openshift_health_checker/test/fluentd_config_test.py index 10db253bc..b5b4858d6 100644 --- a/roles/openshift_health_checker/test/fluentd_config_test.py +++ b/roles/openshift_health_checker/test/fluentd_config_test.py @@ -82,7 +82,7 @@ def test_check_logging_config_non_master(name, use_journald, logging_driver, ext return {} task_vars = dict( - group_names=["nodes", "etcd"], + group_names=["oo_nodes_to_config", "oo_etcd_to_config"], openshift_logging_fluentd_use_journal=use_journald, openshift=dict( common=dict(config_base=""), @@ -128,7 +128,7 @@ def test_check_logging_config_non_master_failed(name, use_journald, logging_driv return {} task_vars = dict( - group_names=["nodes", "etcd"], + group_names=["oo_nodes_to_config", "oo_etcd_to_config"], openshift_logging_fluentd_use_journal=use_journald, openshift=dict( common=dict(config_base=""), @@ -192,7 +192,7 @@ def test_check_logging_config_master(name, pods, logging_driver, extra_words): return {} task_vars = dict( - group_names=["masters"], + group_names=["oo_masters_to_config"], openshift=dict( common=dict(config_base=""), ), @@ -274,7 +274,7 @@ def test_check_logging_config_master_failed(name, pods, logging_driver, words): return {} task_vars = dict( - group_names=["masters"], + group_names=["oo_masters_to_config"], openshift=dict( common=dict(config_base=""), ), @@ -331,7 +331,7 @@ def test_check_logging_config_master_fails_on_unscheduled_deployment(name, pods, return {} task_vars = dict( - group_names=["masters"], + group_names=["oo_masters_to_config"], openshift=dict( common=dict(config_base=""), ), diff --git a/roles/openshift_health_checker/test/memory_availability_test.py b/roles/openshift_health_checker/test/memory_availability_test.py index aee2f0416..5ec83dd79 100644 --- a/roles/openshift_health_checker/test/memory_availability_test.py +++ b/roles/openshift_health_checker/test/memory_availability_test.py @@ -4,11 +4,11 @@ from openshift_checks.memory_availability import MemoryAvailability @pytest.mark.parametrize('group_names,is_active', [ - (['masters'], True), - (['nodes'], True), - (['etcd'], True), - (['masters', 'nodes'], True), - (['masters', 'etcd'], True), + (['oo_masters_to_config'], True), + (['oo_nodes_to_config'], True), + (['oo_etcd_to_config'], True), + (['oo_masters_to_config', 'oo_nodes_to_config'], True), + (['oo_masters_to_config', 'oo_etcd_to_config'], True), ([], False), (['lb'], False), (['nfs'], False), @@ -22,32 +22,32 @@ def test_is_active(group_names, is_active): @pytest.mark.parametrize('group_names,configured_min,ansible_memtotal_mb', [ ( - ['masters'], + ['oo_masters_to_config'], 0, 17200, ), ( - ['nodes'], + ['oo_nodes_to_config'], 0, 8200, ), ( - ['nodes'], + ['oo_nodes_to_config'], 1, # configure lower threshold 2000, # too low for recommended but not for configured ), ( - ['nodes'], + ['oo_nodes_to_config'], 2, # configure threshold where adjustment pushes it over 1900, ), ( - ['etcd'], + ['oo_etcd_to_config'], 0, 8200, ), ( - ['masters', 'nodes'], + ['oo_masters_to_config', 'oo_nodes_to_config'], 0, 17000, ), @@ -66,43 +66,43 @@ def test_succeeds_with_recommended_memory(group_names, configured_min, ansible_m @pytest.mark.parametrize('group_names,configured_min,ansible_memtotal_mb,extra_words', [ ( - ['masters'], + ['oo_masters_to_config'], 0, 0, ['0.0 GiB'], ), ( - ['nodes'], + ['oo_nodes_to_config'], 0, 100, ['0.1 GiB'], ), ( - ['nodes'], + ['oo_nodes_to_config'], 24, # configure higher threshold 20 * 1024, # enough to meet recommended but not configured ['20.0 GiB'], ), ( - ['nodes'], + ['oo_nodes_to_config'], 24, # configure higher threshold 22 * 1024, # not enough for adjustment to push over threshold ['22.0 GiB'], ), ( - ['etcd'], + ['oo_etcd_to_config'], 0, 6 * 1024, ['6.0 GiB'], ), ( - ['etcd', 'masters'], + ['oo_etcd_to_config', 'oo_masters_to_config'], 0, 9 * 1024, # enough memory for etcd, not enough for a master ['9.0 GiB'], ), ( - ['nodes', 'masters'], + ['oo_nodes_to_config', 'oo_masters_to_config'], 0, # enough memory for a node, not enough for a master 11 * 1024, diff --git a/roles/openshift_health_checker/test/ovs_version_test.py b/roles/openshift_health_checker/test/ovs_version_test.py index 602f32989..6f0457549 100644 --- a/roles/openshift_health_checker/test/ovs_version_test.py +++ b/roles/openshift_health_checker/test/ovs_version_test.py @@ -38,8 +38,9 @@ def test_invalid_openshift_release_format(): @pytest.mark.parametrize('openshift_release,expected_ovs_version', [ + ("3.7", ["2.6", "2.7", "2.8"]), ("3.5", ["2.6", "2.7"]), - ("3.6", ["2.6", "2.7"]), + ("3.6", ["2.6", "2.7", "2.8"]), ("3.4", "2.4"), ("3.3", "2.4"), ("1.0", "2.4"), @@ -67,14 +68,14 @@ def test_ovs_package_version(openshift_release, expected_ovs_version): @pytest.mark.parametrize('group_names,is_containerized,is_active', [ - (['masters'], False, True), + (['oo_masters_to_config'], False, True), # ensure check is skipped on containerized installs - (['masters'], True, False), - (['nodes'], False, True), - (['masters', 'nodes'], False, True), - (['masters', 'etcd'], False, True), + (['oo_masters_to_config'], True, False), + (['oo_nodes_to_config'], False, True), + (['oo_masters_to_config', 'oo_nodes_to_config'], False, True), + (['oo_masters_to_config', 'oo_etcd_to_config'], False, True), ([], False, False), - (['etcd'], False, False), + (['oo_etcd_to_config'], False, False), (['lb'], False, False), (['nfs'], False, False), ]) diff --git a/roles/openshift_health_checker/test/package_availability_test.py b/roles/openshift_health_checker/test/package_availability_test.py index b34e8fbfc..9815acb38 100644 --- a/roles/openshift_health_checker/test/package_availability_test.py +++ b/roles/openshift_health_checker/test/package_availability_test.py @@ -26,7 +26,7 @@ def test_is_active(pkg_mgr, is_containerized, is_active): ( dict( openshift=dict(common=dict(service_type='origin')), - group_names=['masters'], + group_names=['oo_masters_to_config'], ), set(['origin-master']), set(['origin-node']), @@ -34,7 +34,7 @@ def test_is_active(pkg_mgr, is_containerized, is_active): ( dict( openshift=dict(common=dict(service_type='atomic-openshift')), - group_names=['nodes'], + group_names=['oo_nodes_to_config'], ), set(['atomic-openshift-node']), set(['atomic-openshift-master']), @@ -42,7 +42,7 @@ def test_is_active(pkg_mgr, is_containerized, is_active): ( dict( openshift=dict(common=dict(service_type='atomic-openshift')), - group_names=['masters', 'nodes'], + group_names=['oo_masters_to_config', 'oo_nodes_to_config'], ), set(['atomic-openshift-master', 'atomic-openshift-node']), set(), diff --git a/roles/openshift_health_checker/test/package_version_test.py b/roles/openshift_health_checker/test/package_version_test.py index 8564cd4db..3cf4ce033 100644 --- a/roles/openshift_health_checker/test/package_version_test.py +++ b/roles/openshift_health_checker/test/package_version_test.py @@ -97,14 +97,14 @@ def test_docker_package_version(deployment_type, openshift_release, expected_doc @pytest.mark.parametrize('group_names,is_containerized,is_active', [ - (['masters'], False, True), + (['oo_masters_to_config'], False, True), # ensure check is skipped on containerized installs - (['masters'], True, False), - (['nodes'], False, True), - (['masters', 'nodes'], False, True), - (['masters', 'etcd'], False, True), + (['oo_masters_to_config'], True, False), + (['oo_nodes_to_config'], False, True), + (['oo_masters_to_config', 'oo_nodes_to_config'], False, True), + (['oo_masters_to_config', 'oo_etcd_to_config'], False, True), ([], False, False), - (['etcd'], False, False), + (['oo_etcd_to_config'], False, False), (['lb'], False, False), (['nfs'], False, False), ]) |