def check_supported_ocp_version(self, hostvars, host,
                                 openshift_deployment_type):
     """Checks that the OCP version supported"""
     if openshift_deployment_type == 'origin':
         return None
     openshift_version = self.template_var(hostvars, host,
                                           'openshift_version')
     for regex_to_match, error_msg in UNSUPPORTED_OCP_VERSIONS.items():
         res = re.match(regex_to_match, str(openshift_version))
         if res is not None:
             raise errors.AnsibleModuleError(error_msg)
     return None
示例#2
0
 def check_pkg_version_format(self, hostvars, host):
     """Ensure openshift_pkg_version is formatted correctly"""
     openshift_pkg_version = self.template_var(hostvars, host,
                                               'openshift_pkg_version')
     if not openshift_pkg_version:
         return None
     regex_to_match = PKG_VERSION_REGEX['re']
     res = re.match(regex_to_match, str(openshift_pkg_version))
     if res is None:
         msg = PKG_VERSION_REGEX['error_msg']
         msg = msg.format(str(openshift_pkg_version))
         raise errors.AnsibleModuleError(msg)
示例#3
0
 def check_release_format(self, hostvars, host):
     """Ensure openshift_release is formatted correctly"""
     openshift_release = self.template_var(hostvars, host,
                                           'openshift_release')
     if not openshift_release:
         return None
     regex_to_match = RELEASE_REGEX['re']
     res = re.match(regex_to_match, str(openshift_release))
     if res is None:
         msg = RELEASE_REGEX['error_msg']
         msg = msg.format(str(openshift_release))
         raise errors.AnsibleModuleError(msg)
示例#4
0
    def get_allowed_registries(self, hostvars, host):
        """Returns a list of configured allowedRegistriesForImport as a list of patterns"""
        allowed_registries_for_import = self.template_var(hostvars, host, ALLOWED_REGISTRIES_VAR)
        if allowed_registries_for_import is None:
            image_policy_config = self.template_var(hostvars, host, IMAGE_POLICY_CONFIG_VAR)
            if not image_policy_config:
                return image_policy_config

            if isinstance(image_policy_config, str):
                try:
                    image_policy_config = json.loads(image_policy_config)
                except Exception:
                    raise errors.AnsibleModuleError(
                        "{} is not a valid json string".format(IMAGE_POLICY_CONFIG_VAR))

            if not isinstance(image_policy_config, dict):
                raise errors.AnsibleModuleError(
                    "expected dictionary for {}, not {}".format(
                        IMAGE_POLICY_CONFIG_VAR, type(image_policy_config)))

            detailed = image_policy_config.get("allowedRegistriesForImport", None)
            if not detailed:
                return detailed

            if not isinstance(detailed, list):
                raise errors.AnsibleModuleError("expected list for {}['{}'], not {}".format(
                    IMAGE_POLICY_CONFIG_VAR, "allowedRegistriesForImport",
                    type(allowed_registries_for_import)))

            try:
                return [i["domainName"] for i in detailed]
            except Exception:
                raise errors.AnsibleModuleError(
                    "each item of allowedRegistriesForImport must be a dictionary with 'domainName' key")

        if not isinstance(allowed_registries_for_import, list):
            raise errors.AnsibleModuleError("expected list for {}, not {}".format(
                IMAGE_POLICY_CONFIG_VAR, type(allowed_registries_for_import)))

        return allowed_registries_for_import
    def return_config_overrides_ini(self, config_overrides, resultant):
        """Returns string value from a modified config file.

        :param config_overrides: ``dict``
        :param resultant: ``str`` || ``unicode``
        :returns: ``str``
        """
        # If there is an exception loading the RawConfigParser The config obj
        #  is loaded again without the extra option. This is being done to
        #  support older python.
        try:
            config = ConfigTemplateParser(allow_no_value=True,
                                          dict_type=MultiKeyDict)
            config.optionxform = str
        except Exception:
            config = ConfigTemplateParser(dict_type=MultiKeyDict)

        config_object = io.BytesIO(str(resultant))
        config.readfp(config_object)
        for section, items in config_overrides.items():
            # If the items value is not a dictionary it is assumed that the
            #  value is a default item for this config type.
            if not isinstance(items, dict):
                if isinstance(items, list):
                    items = ','.join(_convert_2_string(items))
                self._option_write(config, 'DEFAULT', str(section), items)
            else:
                # Attempt to add a section to the config file passing if
                #  an error is raised that is related to the section
                #  already existing.
                try:
                    config.add_section(section.encode('utf-8'))
                except (ConfigParser.DuplicateSectionError, ValueError):
                    pass
                for key, value in items.items():
                    try:
                        self._option_write(config, section, key, value)
                    except ConfigParser.NoSectionError as exp:
                        error_msg = str(exp)
                        error_msg += (
                            ' Try being more explicit with your override'
                            'data. Sections are case sensitive.')
                        raise errors.AnsibleModuleError(error_msg)
        else:
            config_object.close()

        resultant_bytesio = io.BytesIO()
        try:
            config.write(resultant_bytesio)
            return resultant_bytesio.getvalue()
        finally:
            resultant_bytesio.close()
示例#6
0
def check_for_removed_vars(hostvars, host):
    """Fails if removed variables are found"""
    found_removed = []
    for item in REMOVED_VARIABLES:
        if item in hostvars[host]:
            found_removed.append(item)

    if found_removed:
        msg = "Found removed variables: "
        for item in found_removed:
            msg += "{} is replaced by {}; ".format(item[0], item[1])
        raise errors.AnsibleModuleError(msg)
    return None
def check_strings(strings_to_check):
    """Check the strings we found to see if they look like file paths and if
    they are, fail if not start with /etc/origin/master"""
    for item in strings_to_check:
        if item.startswith('/') or item.startswith('../'):
            matches = 0
            for allowed in ALLOWED_DIRS:
                if item.startswith(allowed):
                    matches += 1
            if matches == 0:
                raise errors.AnsibleModuleError(
                    FAIL_MSG.format(ALLOWED_DIRS_STRING, ALLOWED_DIRS_STRING,
                                    item, MIGRATED_ITEMS))
示例#8
0
 def check_image_tag_format(self, hostvars, host,
                            openshift_deployment_type):
     """Ensure openshift_image_tag is formatted correctly"""
     openshift_image_tag = self.template_var(hostvars, host,
                                             'openshift_image_tag')
     if not openshift_image_tag or openshift_image_tag == 'latest':
         return None
     regex_to_match = IMAGE_TAG_REGEX[openshift_deployment_type]['re']
     res = re.match(regex_to_match, str(openshift_image_tag))
     if res is None:
         msg = IMAGE_TAG_REGEX[openshift_deployment_type]['error_msg']
         msg = msg.format(str(openshift_image_tag))
         raise errors.AnsibleModuleError(msg)
    def check_for_oreg_password(self, hostvars, host, odt):
        """Ensure oreg_password is defined when using registry.redhat.io"""
        reg_to_check = 'registry.redhat.io'
        err_msg = ("oreg_auth_user and oreg_auth_password must be provided when"
                   "deploying openshift-enterprise")
        err_msg2 = ("oreg_auth_user and oreg_auth_password must be provided when using"
                    "{}".format(reg_to_check))

        oreg_password = self.template_var(hostvars, host, 'oreg_auth_password')
        if oreg_password is not None:
            # A password is defined, so we're good to go.
            return None

        oreg_url = self.template_var(hostvars, host, 'oreg_url')

        if oreg_url is not None:
            if reg_to_check in oreg_url:
                raise errors.AnsibleModuleError(err_msg2)

        elif odt == 'openshift-enterprise':
            # We're not using an oreg_url, we're using default enterprise
            # registry.  We require oreg_auth_user and oreg_auth_password
            raise errors.AnsibleModuleError(err_msg)
示例#10
0
 def check_python_version(self, hostvars, host, distro):
     """Ensure python version is 3 for Fedora and python 2 for others"""
     ansible_python = self.template_var(hostvars, host, 'ansible_python')
     if distro == "Fedora":
         if ansible_python['version']['major'] != 3:
             msg = "openshift-ansible requires Python 3 for {};".format(
                 distro)
             msg += " For information on enabling Python 3 with Ansible,"
             msg += " see https://docs.ansible.com/ansible/python_3_support.html"
             raise errors.AnsibleModuleError(msg)
     else:
         if ansible_python['version']['major'] != 2:
             msg = "openshift-ansible requires Python 2 for {};".format(
                 distro)
示例#11
0
 def build_pv_hostpath(self, varname=None):
     """Build pv dictionary for hostpath storage type"""
     volume, size, labels, _, access_modes = self.build_common(
         varname=varname)
     # hostpath only supports ReadWriteOnce
     if access_modes[0] != 'ReadWriteOnce':
         msg = "Hostpath storage only supports 'ReadWriteOnce' Was given {}."
         raise errors.AnsibleModuleError(msg.format(
             access_modes.join(', ')))
     path = self.get_templated(str(varname) + '_hostpath_path')
     return dict(name="{0}-volume".format(volume),
                 capacity=size,
                 labels=labels,
                 access_modes=access_modes,
                 storage=dict(hostPath=dict(path=path)))
示例#12
0
    def network_plugin_check(self, hostvars, host):
        """Ensure only one type of network plugin is enabled"""
        res = []
        # Loop through each possible network plugin boolean, determine the
        # actual boolean value, and append results into a list.
        for plugin, default_val in NET_PLUGIN_LIST:
            res_temp = self.template_var(hostvars, host, plugin)
            if res_temp is None:
                res_temp = default_val
            res.append(to_bool(res_temp))

        if sum(res) not in (0, 1):
            plugin_str = list(zip([x[0] for x in NET_PLUGIN_LIST], res))

            msg = "Host Checked: {} Only one of must be true. Found: {}".format(host, plugin_str)
            raise errors.AnsibleModuleError(msg)
示例#13
0
 def no_origin_image_version(self, hostvars, host, openshift_deployment_type):
     """Ensure we can determine what image version to use with origin
       fail when:
       - openshift_is_containerized
       - openshift_deployment_type == 'origin'
       - openshift_release is not defined
       - openshift_image_tag is not defined"""
     if not openshift_deployment_type == 'origin':
         return None
     oic = self.template_var(hostvars, host, 'openshift_is_containerized')
     if not to_bool(oic):
         return None
     orelease = self.template_var(hostvars, host, 'openshift_release')
     oitag = self.template_var(hostvars, host, 'openshift_image_tag')
     if not orelease and not oitag:
         raise errors.AnsibleModuleError(CONTAINERIZED_NO_TAG_ERROR_MSG)
    def validate_json_format_vars(self, hostvars, host):
        """Fails if invalid json format are found"""
        found_invalid_json = []
        for var in JSON_FORMAT_VARIABLES:
            if var in hostvars[host]:
                json_var = self.template_var(hostvars, host, var)
                try:
                    json.loads(json_var)
                except ValueError as json_err:
                    found_invalid_json.append([var, json_var, json_err])
                except BaseException:
                    pass

        if found_invalid_json:
            msg = "Found invalid json format variables:\n"
            for item in found_invalid_json:
                msg += "    {} specified in {} is invalid json format\n    {}".format(item[1], item[0], item[2])
            raise errors.AnsibleModuleError(msg)
        return None
示例#15
0
    def check_unsupported_nfs_configs(self, hostvars, host):
        """Fails if nfs storage is in use for any components. This check is
           ignored if openshift_enable_unsupported_configurations=True"""

        enable_unsupported = self.template_var(
            hostvars, host, 'openshift_enable_unsupported_configurations')

        if to_bool(enable_unsupported):
            return None

        for storage in STORAGE_KIND_TUPLE:
            kind = self.template_var(hostvars, host, storage)
            if kind == 'nfs':
                raise errors.AnsibleModuleError(
                    'nfs is an unsupported type for {}. '
                    'openshift_enable_unsupported_configurations=True must'
                    'be specified to continue with this configuration.'
                    ''.format(storage))
        return None
示例#16
0
 def update_nested_conf(conf, update, extend_lists=False):
     for k, v in update.items():
         if isinstance(v, dict):
             conf[k] = Utils.update_nested_conf(
                 conf.get(k, {}), v, extend_lists)
         elif k in conf and isinstance(conf[k], list) and extend_lists:
             if not isinstance(v, list):
                 errmsg = (
                     "Failure merging key `%(key)s` in dictionary "
                     "`%(dictionary)s`. Expecting a list, but received: "
                     "`%(value)s`, which is of type: `%(type)s`" % {
                         "key": k, "dictionary": conf,
                         "value": v, "type": type(v)}
                 )
                 raise ansible_errors.AnsibleModuleError(errmsg)
             conf[k].extend(v)
         else:
             conf[k] = v
     return conf
示例#17
0
    def check_contains_version(self, hostvars, host):
        """Fails if variable has old format not containing image version"""
        found_incorrect = []
        for img_var in CHANGED_IMAGE_VARS:
            img_string = self.template_var(hostvars, host, img_var)
            if not img_string:
                return None
            # split the image string by '/' to account for something like docker://
            img_string_parts = img_string.split('/')
            if ':' not in img_string_parts[-1]:
                found_incorrect.append((img_var, img_string))

        if found_incorrect:
            msg = ("Found image variables without version.  Please ensure any image"
                   "defined contains ':someversion'; ")
            for item in found_incorrect:
                msg += "{} was: {}; ".format(item[0], item[1])
            raise errors.AnsibleModuleError(msg)
        return None
示例#18
0
    def build_pv_dict(self, varname=None):
        """Check for the existence of PV variables"""
        kind = self.task_vars.get(str(varname) + '_kind')
        if kind:
            kind = self._templar.template(kind)
            create_pv = self.task_vars.get(str(varname) + '_create_pv')
            if create_pv and self._templar.template(create_pv):
                if kind == 'nfs':
                    return self.build_pv_nfs(varname=varname)

                elif kind == 'openstack':
                    return self.build_pv_openstack(varname=varname)

                elif kind == 'glusterfs':
                    return self.build_pv_glusterfs(varname=varname)

                elif not (kind == 'object' or kind == 'dynamic'):
                    msg = "|failed invalid storage kind '{0}' for component '{1}'".format(
                        kind, varname)
                    raise errors.AnsibleModuleError(msg)
        return None
示例#19
0
 def build_pv_nfs(self, varname=None):
     """Build pv dictionary for nfs storage type"""
     host = self.task_vars.get(str(varname) + '_host')
     if host:
         self._templar.template(host)
     elif host is None:
         groups = self.task_vars.get('groups')
         if groups and 'oo_nfs_to_config' in groups and len(
                 groups['oo_nfs_to_config']) > 0:
             host = groups['oo_nfs_to_config'][0]
         else:
             raise errors.AnsibleModuleError(
                 "|failed no storage host detected")
     volume, size, labels, access_modes = self.build_common(varname=varname)
     directory = self.get_templated(str(varname) + '_nfs_directory')
     path = directory + '/' + volume
     return dict(name="{0}-volume".format(volume),
                 capacity=size,
                 labels=labels,
                 access_modes=access_modes,
                 storage=dict(nfs=dict(server=host, path=path)))
示例#20
0
    def return_config_overrides_ini(self,
                                    config_overrides,
                                    resultant,
                                    list_extend=True,
                                    ignore_none_type=True,
                                    default_section='DEFAULT',
                                    yml_multilines=False):
        """Returns string value from a modified config file and dict of
        merged config

        :param config_overrides: ``dict``
        :param resultant: ``str`` || ``unicode``
        :returns: ``str``, ``dict``
        """
        def _add_section(section_name):
            # Attempt to add a section to the config file passing if
            #  an error is raised that is related to the section
            #  already existing.
            try:
                config.add_section(section_name)
            except (ConfigParser.DuplicateSectionError, ValueError):
                pass

        # If there is an exception loading the RawConfigParser The config obj
        #  is loaded again without the extra option. This is being done to
        #  support older python.
        try:
            config = ConfigTemplateParser(allow_no_value=True,
                                          dict_type=MultiKeyDict,
                                          ignore_none_type=ignore_none_type,
                                          default_section=default_section,
                                          yml_multilines=yml_multilines,
                                          comment_prefixes='/')
            config.optionxform = str
        except Exception:
            config = ConfigTemplateParser(allow_no_value=True,
                                          dict_type=MultiKeyDict,
                                          comment_prefixes='/')

        config_object = StringIO(resultant)
        try:
            config.read_file(config_object)
        except AttributeError:
            config.readfp(config_object)

        if default_section != 'DEFAULT':
            _add_section(section_name=default_section)

        for section, items in config_overrides.items():
            # If the items value is not a dictionary it is assumed that the
            #  value is a default item for this config type.
            if not isinstance(items, dict):
                if isinstance(items, list):
                    items = ','.join(to_text(i) for i in items)

                self._option_write(config, default_section, section, items)
            else:
                _add_section(section_name=section)
                for key, value in items.items():
                    try:
                        self._option_write(config, section, key, value)
                    except ConfigParser.NoSectionError as exp:
                        error_msg = str(exp)
                        error_msg += (
                            ' Try being more explicit with your override'
                            'data. Sections are case sensitive.')
                        raise errors.AnsibleModuleError(error_msg)

        config_object.close()

        config_dict_new = OrderedDict()
        config_defaults = config.defaults()
        for s in config.sections():
            config_dict_new[s] = OrderedDict()
            for k, v in config.items(s):
                if k not in config_defaults or config_defaults[k] != v:
                    config_dict_new[s][k] = v
                else:
                    if default_section in config_dict_new:
                        config_dict_new[default_section][k] = v
                    else:
                        config_dict_new[default_section] = {k: v}

        resultant_stringio = StringIO()
        try:
            config.write(resultant_stringio)
            return resultant_stringio.getvalue(), config_dict_new
        finally:
            resultant_stringio.close()
示例#21
0
    msg: >-
         One or more incompatibilities were found in {{ config_filename }}.
         They were {{ compatibility.explanations }}
  when:
    - compatibility.incompatible

'''

from ansible.module_utils.basic import *
from ansible import errors

try:
    import yaml
    from semver import parse_version_info
except ImportError as e:
    raise errors.AnsibleModuleError(e)

REGISTERED_CHECKS = []


# All checks decorated by @register_check will be run by check_compatibility().
def register_check(check):
    REGISTERED_CHECKS.append(check)
    return check


def get_version(version):
    '''Return the VersionInfo for the version string, but strip the leading
    character if it is a v, since that's not strictly semver.
    '''
    if version[0] == 'v':