示例#1
0
    def _check_mutually_exclusive(self, spec, param=None):
        if param is None:
            param = self.params

        try:
            check_mutually_exclusive(spec, param)
        except TypeError as e:
            msg = to_native(e)
            if self._options_context:
                msg += " found in %s" % " -> ".join(self._options_context)
            self.fail_json(msg=msg)
示例#2
0
def test_check_mutually_exclusive_found(mutually_exclusive_terms):
    params = {
        'string1': 'cat',
        'string2': 'hat',
        'fox': 'red',
        'socks': 'blue',
    }
    expected = "TypeError('parameters are mutually exclusive: string1|string2, box|fox|socks',)"

    with pytest.raises(TypeError) as e:
        check_mutually_exclusive(mutually_exclusive_terms, params)
        assert e.value == expected
示例#3
0
def test_check_mutually_exclusive_none():
    terms = None
    params = {
        'string1': 'cat',
        'fox': 'hat',
    }
    assert check_mutually_exclusive(terms, params) == []
def main():
    result = {}
    module = AnsibleModule(argument_spec=dict(category=dict(required=True),
                                              command=dict(required=True,
                                                           type='list',
                                                           elements='str'),
                                              baseuri=dict(required=True),
                                              username=dict(),
                                              password=dict(no_log=True),
                                              auth_token=dict(no_log=True),
                                              manager_attributes=dict(
                                                  type='dict', default={}),
                                              timeout=dict(type='int',
                                                           default=10),
                                              resource_id=dict()),
                           required_together=[
                               ('username', 'password'),
                           ],
                           required_one_of=[
                               ('username', 'auth_token'),
                           ],
                           mutually_exclusive=[
                               ('username', 'auth_token'),
                           ],
                           supports_check_mode=False)

    category = module.params['category']
    command_list = module.params['command']

    # admin credentials used for authentication
    creds = {
        'user': module.params['username'],
        'pswd': module.params['password'],
        'token': module.params['auth_token']
    }

    # timeout
    timeout = module.params['timeout']

    # System, Manager or Chassis ID to modify
    resource_id = module.params['resource_id']

    # Build root URI
    root_uri = "https://" + module.params['baseuri']
    rf_utils = IdracRedfishUtils(creds,
                                 root_uri,
                                 timeout,
                                 module,
                                 resource_id=resource_id,
                                 data_modification=True)

    # Check that Category is valid
    if category not in CATEGORY_COMMANDS_ALL:
        module.fail_json(
            msg=to_native("Invalid Category '%s'. Valid Categories = %s" %
                          (category, list(CATEGORY_COMMANDS_ALL.keys()))))

    # Check that all commands are valid
    for cmd in command_list:
        # Fail if even one command given is invalid
        if cmd not in CATEGORY_COMMANDS_ALL[category]:
            module.fail_json(
                msg=to_native("Invalid Command '%s'. Valid Commands = %s" %
                              (cmd, CATEGORY_COMMANDS_ALL[category])))

    # check for mutually exclusive commands
    try:
        # check_mutually_exclusive accepts a single list or list of lists that
        # are groups of terms that should be mutually exclusive with one another
        # and checks that against a dictionary
        check_mutually_exclusive(
            CATEGORY_COMMANDS_MUTUALLY_EXCLUSIVE[category],
            dict.fromkeys(command_list, True))

    except TypeError as e:
        module.fail_json(msg=to_native(e))

    # Organize by Categories / Commands

    if category == "Manager":
        # execute only if we find a Manager resource
        result = rf_utils._find_managers_resource()
        if result['ret'] is False:
            module.fail_json(msg=to_native(result['msg']))

        for command in command_list:
            if command in [
                    "SetManagerAttributes", "SetLifecycleControllerAttributes",
                    "SetSystemAttributes"
            ]:
                result = rf_utils.set_manager_attributes(command)

    # Return data back or fail with proper message
    if result['ret'] is True:
        module.exit_json(changed=result['changed'],
                         msg=to_native(result['msg']))
    else:
        module.fail_json(msg=to_native(result['msg']))
示例#5
0
    def validate(self, parameters, *args, **kwargs):
        """Validate ``parameters`` against argument spec.

        Error messages in the :class:`ValidationResult` may contain no_log values and should be
        sanitized with :func:`~ansible.module_utils.common.parameters.sanitize_keys` before logging or displaying.

        :arg parameters: Parameters to validate against the argument spec
        :type parameters: dict[str, dict]

        :return: :class:`ValidationResult` containing validated parameters.

        :Simple Example:

            .. code-block:: text

                argument_spec = {
                    'name': {'type': 'str'},
                    'age': {'type': 'int'},
                }

                parameters = {
                    'name': 'bo',
                    'age': '42',
                }

                validator = ArgumentSpecValidator(argument_spec)
                result = validator.validate(parameters)

                if result.error_messages:
                    sys.exit("Validation failed: {0}".format(", ".join(result.error_messages))

                valid_params = result.validated_parameters
        """

        result = ValidationResult(parameters)

        result._no_log_values.update(
            set_fallbacks(self.argument_spec, result._validated_parameters))

        alias_warnings = []
        alias_deprecations = []
        try:
            result._aliases.update(
                _handle_aliases(self.argument_spec,
                                result._validated_parameters, alias_warnings,
                                alias_deprecations))
        except (TypeError, ValueError) as e:
            result.errors.append(AliasError(to_native(e)))

        legal_inputs = _get_legal_inputs(self.argument_spec,
                                         result._validated_parameters,
                                         result._aliases)

        for option, alias in alias_warnings:
            result._warnings.append({'option': option, 'alias': alias})

        for deprecation in alias_deprecations:
            result._deprecations.append({
                'name':
                deprecation['name'],
                'version':
                deprecation.get('version'),
                'date':
                deprecation.get('date'),
                'collection_name':
                deprecation.get('collection_name'),
            })

        try:
            result._no_log_values.update(
                _list_no_log_values(self.argument_spec,
                                    result._validated_parameters))
        except TypeError as te:
            result.errors.append(NoLogError(to_native(te)))

        try:
            result._unsupported_parameters.update(
                _get_unsupported_parameters(self.argument_spec,
                                            result._validated_parameters,
                                            legal_inputs))
        except TypeError as te:
            result.errors.append(RequiredDefaultError(to_native(te)))
        except ValueError as ve:
            result.errors.append(AliasError(to_native(ve)))

        try:
            check_mutually_exclusive(self._mutually_exclusive,
                                     result._validated_parameters)
        except TypeError as te:
            result.errors.append(MutuallyExclusiveError(to_native(te)))

        result._no_log_values.update(
            _set_defaults(self.argument_spec, result._validated_parameters,
                          False))

        try:
            check_required_arguments(self.argument_spec,
                                     result._validated_parameters)
        except TypeError as e:
            result.errors.append(RequiredError(to_native(e)))

        _validate_argument_types(self.argument_spec,
                                 result._validated_parameters,
                                 errors=result.errors)
        _validate_argument_values(self.argument_spec,
                                  result._validated_parameters,
                                  errors=result.errors)

        for check in _ADDITIONAL_CHECKS:
            try:
                check['func'](getattr(self,
                                      "_{attr}".format(attr=check['attr'])),
                              result._validated_parameters)
            except TypeError as te:
                result.errors.append(check['err'](to_native(te)))

        result._no_log_values.update(
            _set_defaults(self.argument_spec, result._validated_parameters))

        _validate_sub_spec(
            self.argument_spec,
            result._validated_parameters,
            errors=result.errors,
            no_log_values=result._no_log_values,
            unsupported_parameters=result._unsupported_parameters)

        if result._unsupported_parameters:
            flattened_names = []
            for item in result._unsupported_parameters:
                if isinstance(item, tuple):
                    flattened_names.append(".".join(item))
                else:
                    flattened_names.append(item)

            unsupported_string = ", ".join(sorted(list(flattened_names)))
            supported_string = ", ".join(self._valid_parameter_names)
            result.errors.append(
                UnsupportedError(
                    "{0}. Supported parameters include: {1}.".format(
                        unsupported_string, supported_string)))

        return result
示例#6
0
def _validate_sub_spec(argument_spec,
                       parameters,
                       prefix='',
                       options_context=None,
                       errors=None,
                       no_log_values=None,
                       unsupported_parameters=None):
    """Validate sub argument spec.

    This function is recursive.
    """

    if options_context is None:
        options_context = []

    if errors is None:
        errors = AnsibleValidationErrorMultiple()

    if no_log_values is None:
        no_log_values = set()

    if unsupported_parameters is None:
        unsupported_parameters = set()

    for param, value in argument_spec.items():
        wanted = value.get('type')
        if wanted == 'dict' or (wanted == 'list'
                                and value.get('elements', '') == 'dict'):
            sub_spec = value.get('options')
            if value.get('apply_defaults', False):
                if sub_spec is not None:
                    if parameters.get(param) is None:
                        parameters[param] = {}
                else:
                    continue
            elif sub_spec is None or param not in parameters or parameters[
                    param] is None:
                continue

            # Keep track of context for warning messages
            options_context.append(param)

            # Make sure we can iterate over the elements
            if not isinstance(parameters[param], Sequence) or isinstance(
                    parameters[param], string_types):
                elements = [parameters[param]]
            else:
                elements = parameters[param]

            for idx, sub_parameters in enumerate(elements):
                no_log_values.update(set_fallbacks(sub_spec, sub_parameters))

                if not isinstance(sub_parameters, dict):
                    errors.append(
                        SubParameterTypeError(
                            "value of '%s' must be of type dict or list of dicts"
                            % param))
                    continue

                # Set prefix for warning messages
                new_prefix = prefix + param
                if wanted == 'list':
                    new_prefix += '[%d]' % idx
                new_prefix += '.'

                alias_warnings = []
                alias_deprecations = []
                try:
                    options_aliases = _handle_aliases(sub_spec, sub_parameters,
                                                      alias_warnings,
                                                      alias_deprecations)
                except (TypeError, ValueError) as e:
                    options_aliases = {}
                    errors.append(AliasError(to_native(e)))

                for option, alias in alias_warnings:
                    warn('Both option %s and its alias %s are set.' %
                         (option, alias))

                try:
                    no_log_values.update(
                        _list_no_log_values(sub_spec, sub_parameters))
                except TypeError as te:
                    errors.append(NoLogError(to_native(te)))

                legal_inputs = _get_legal_inputs(sub_spec, sub_parameters,
                                                 options_aliases)
                unsupported_parameters.update(
                    _get_unsupported_parameters(sub_spec, sub_parameters,
                                                legal_inputs, options_context))

                try:
                    check_mutually_exclusive(value.get('mutually_exclusive'),
                                             sub_parameters, options_context)
                except TypeError as e:
                    errors.append(MutuallyExclusiveError(to_native(e)))

                no_log_values.update(
                    _set_defaults(sub_spec, sub_parameters, False))

                try:
                    check_required_arguments(sub_spec, sub_parameters,
                                             options_context)
                except TypeError as e:
                    errors.append(RequiredError(to_native(e)))

                _validate_argument_types(sub_spec,
                                         sub_parameters,
                                         new_prefix,
                                         options_context,
                                         errors=errors)
                _validate_argument_values(sub_spec,
                                          sub_parameters,
                                          options_context,
                                          errors=errors)

                for check in _ADDITIONAL_CHECKS:
                    try:
                        check['func'](value.get(check['attr']), sub_parameters,
                                      options_context)
                    except TypeError as e:
                        errors.append(check['err'](to_native(e)))

                no_log_values.update(_set_defaults(sub_spec, sub_parameters))

                # Handle nested specs
                _validate_sub_spec(sub_spec, sub_parameters, new_prefix,
                                   options_context, errors, no_log_values,
                                   unsupported_parameters)

            options_context.pop()
示例#7
0
def validate_sub_spec(argument_spec, parameters, prefix='', options_context=None, errors=None, no_log_values=None, unsupported_parameters=None):
    """Validate sub argument spec. This function is recursive."""

    if options_context is None:
        options_context = []

    if errors is None:
        errors = []

    if no_log_values is None:
        no_log_values = set()

    if unsupported_parameters is None:
        unsupported_parameters = set()

    for param, value in argument_spec.items():
        wanted = value.get('type')
        if wanted == 'dict' or (wanted == 'list' and value.get('elements', '') == dict):
            sub_spec = value.get('options')
            if value.get('apply_defaults', False):
                if sub_spec is not None:
                    if parameters.get(value) is None:
                        parameters[param] = {}
                    else:
                        continue
            elif sub_spec is None or param not in parameters or parameters[param] is None:
                continue

            # Keep track of context for warning messages
            options_context.append(param)

            # Make sure we can iterate over the elements
            if isinstance(parameters[param], dict):
                elements = [parameters[param]]
            else:
                elements = parameters[param]

            for idx, sub_parameters in enumerate(elements):
                if not isinstance(sub_parameters, dict):
                    errors.append("value of '%s' must be of type dict or list of dicts" % param)

                # Set prefix for warning messages
                new_prefix = prefix + param
                if wanted == 'list':
                    new_prefix += '[%d]' % idx
                new_prefix += '.'

                no_log_values.update(set_fallbacks(sub_spec, sub_parameters))

                alias_warnings = []
                try:
                    options_aliases, legal_inputs = handle_aliases(sub_spec, sub_parameters, alias_warnings)
                except (TypeError, ValueError) as e:
                    options_aliases = {}
                    legal_inputs = None
                    errors.append(to_native(e))

                for option, alias in alias_warnings:
                    warn('Both option %s and its alias %s are set.' % (option, alias))

                no_log_values.update(list_no_log_values(sub_spec, sub_parameters))

                if legal_inputs is None:
                    legal_inputs = list(options_aliases.keys()) + list(sub_spec.keys())
                unsupported_parameters.update(get_unsupported_parameters(sub_spec, sub_parameters, legal_inputs))

                try:
                    check_mutually_exclusive(value.get('mutually_exclusive'), sub_parameters)
                except TypeError as e:
                    errors.append(to_native(e))

                no_log_values.update(set_defaults(sub_spec, sub_parameters, False))

                try:
                    check_required_arguments(sub_spec, sub_parameters)
                except TypeError as e:
                    errors.append(to_native(e))

                validate_argument_types(sub_spec, sub_parameters, new_prefix, options_context, errors=errors)
                validate_argument_values(sub_spec, sub_parameters, options_context, errors=errors)

                checks = [
                    (check_required_together, 'required_together'),
                    (check_required_one_of, 'required_one_of'),
                    (check_required_if, 'required_if'),
                    (check_required_by, 'required_by'),
                ]

                for check in checks:
                    try:
                        check[0](value.get(check[1]), parameters)
                    except TypeError as e:
                        errors.append(to_native(e))

                no_log_values.update(set_defaults(sub_spec, sub_parameters))

                # Handle nested specs
                validate_sub_spec(sub_spec, sub_parameters, new_prefix, options_context, errors, no_log_values, unsupported_parameters)

            options_context.pop()
示例#8
0
    def validate(self, parameters, *args, **kwargs):
        """Validate module parameters against argument spec. Returns a
        ValidationResult object.

        Error messages in the ValidationResult may contain no_log values and should be
        sanitized before logging or displaying.

        :Example:

        validator = ArgumentSpecValidator(argument_spec)
        result = validator.validate(parameters)

        if result.error_messages:
            sys.exit("Validation failed: {0}".format(", ".join(result.error_messages))

        valid_params = result.validated_parameters

        :param argument_spec: Specification of parameters, type, and valid values
        :type argument_spec: dict

        :param parameters: Parameters provided to the role
        :type parameters: dict

        :return: Object containing validated parameters.
        :rtype: ValidationResult
        """

        result = ValidationResult(parameters)

        result._no_log_values.update(
            set_fallbacks(self.argument_spec, result._validated_parameters))

        alias_warnings = []
        alias_deprecations = []
        try:
            aliases = _handle_aliases(self.argument_spec,
                                      result._validated_parameters,
                                      alias_warnings, alias_deprecations)
        except (TypeError, ValueError) as e:
            aliases = {}
            result.errors.append(AliasError(to_native(e)))

        legal_inputs = _get_legal_inputs(self.argument_spec,
                                         result._validated_parameters, aliases)

        for option, alias in alias_warnings:
            result._warnings.append({'option': option, 'alias': alias})

        for deprecation in alias_deprecations:
            result._deprecations.append({
                'name':
                deprecation['name'],
                'version':
                deprecation.get('version'),
                'date':
                deprecation.get('date'),
                'collection_name':
                deprecation.get('collection_name'),
            })

        try:
            result._no_log_values.update(
                _list_no_log_values(self.argument_spec,
                                    result._validated_parameters))
        except TypeError as te:
            result.errors.append(NoLogError(to_native(te)))

        try:
            result._unsupported_parameters.update(
                _get_unsupported_parameters(self.argument_spec,
                                            result._validated_parameters,
                                            legal_inputs))
        except TypeError as te:
            result.errors.append(RequiredDefaultError(to_native(te)))
        except ValueError as ve:
            result.errors.append(AliasError(to_native(ve)))

        try:
            check_mutually_exclusive(self._mutually_exclusive,
                                     result._validated_parameters)
        except TypeError as te:
            result.errors.append(MutuallyExclusiveError(to_native(te)))

        result._no_log_values.update(
            _set_defaults(self.argument_spec, result._validated_parameters,
                          False))

        try:
            check_required_arguments(self.argument_spec,
                                     result._validated_parameters)
        except TypeError as e:
            result.errors.append(RequiredError(to_native(e)))

        _validate_argument_types(self.argument_spec,
                                 result._validated_parameters,
                                 errors=result.errors)
        _validate_argument_values(self.argument_spec,
                                  result._validated_parameters,
                                  errors=result.errors)

        for check in _ADDITIONAL_CHECKS:
            try:
                check['func'](getattr(self,
                                      "_{attr}".format(attr=check['attr'])),
                              result._validated_parameters)
            except TypeError as te:
                result.errors.append(check['err'](to_native(te)))

        result._no_log_values.update(
            _set_defaults(self.argument_spec, result._validated_parameters))

        _validate_sub_spec(
            self.argument_spec,
            result._validated_parameters,
            errors=result.errors,
            no_log_values=result._no_log_values,
            unsupported_parameters=result._unsupported_parameters)

        if result._unsupported_parameters:
            flattened_names = []
            for item in result._unsupported_parameters:
                if isinstance(item, tuple):
                    flattened_names.append(".".join(item))
                else:
                    flattened_names.append(item)

            unsupported_string = ", ".join(sorted(list(flattened_names)))
            supported_string = ", ".join(self._valid_parameter_names)
            result.errors.append(
                UnsupportedError(
                    "{0}. Supported parameters include: {1}.".format(
                        unsupported_string, supported_string)))

        return result
def run_module():
    module_args = dict(cert_not_after=dict(type="str"),
                       cert_not_before=dict(type="str"),
                       force=dict(type="bool"),
                       host=dict(type="bool"),
                       k8ssa_token_path=dict(type="path"),
                       key=dict(type="path"),
                       kid=dict(type="str"),
                       name=dict(aliases=["subject"],
                                 type="str",
                                 required=True),
                       not_after=dict(type="str"),
                       not_before=dict(type="str"),
                       output_file=dict(type="path"),
                       principal=dict(type="list", elements="str"),
                       provisioner=dict(type="str", aliases=["issuer"]),
                       provisioner_password_file=dict(type="path",
                                                      no_log=False),
                       return_token=dict(type="bool"),
                       revoke=dict(type="bool"),
                       renew=dict(type="bool"),
                       rekey=dict(type="bool"),
                       san=dict(type="list", elements="str"),
                       ssh=dict(type="bool"),
                       sshpop_cert=dict(type="str"),
                       sshpop_key=dict(type="path"),
                       x5c_cert=dict(type="str"),
                       x5c_key=dict(type="path"),
                       step_cli_executable=dict(type="path",
                                                default="step-cli"))

    result = dict(changed=False, stdout="", stderr="", msg="")
    module = AnsibleModule(argument_spec={
        **module_args,
        **connection_argspec
    },
                           supports_check_mode=True)

    check_mutually_exclusive(["return_token", "output_file"], module.params)
    check_required_one_of(["return_token", "output_file"], module.params)

    check_step_cli_install(module, module.params["step_cli_executable"],
                           result)

    # Positional Parameters
    params = ["ca", "token", module.params["name"]]
    # Regular args
    args = [
        "cert_not_after", "cert_not_before", "force", "host",
        "k8ssa_token_path", "key", "kid", "not_after", "not_before",
        "output_file", "principal", "provisioner", "provisioner_password_file",
        "revoke", "renew", "rekey", "san", "ssh", "sshpop_cert", "sshpop_key",
        "x5c_cert", "x5c_key"
    ]
    # All parameters can be converted to a mapping by just appending -- and replacing the underscores
    args = {arg: "--{a}".format(a=arg.replace("_", "-")) for arg in args}

    result = run_step_cli_command(module.params["step_cli_executable"], params,
                                  module, result, {
                                      **args,
                                      **connection_run_args
                                  })
    result["changed"] = True
    if module.params["return_token"]:
        result["token"] = result["stdout"]
        result["stdout"] = ""
        result["stdout_lines"] = ""
    module.exit_json(**result)
示例#10
0
def test_check_mutually_exclusive_no_params(mutually_exclusive_terms):
    with pytest.raises(TypeError) as te:
        check_mutually_exclusive(mutually_exclusive_terms, None)
        assert "TypeError: 'NoneType' object is not iterable" in to_native(
            te.error)
示例#11
0
def test_check_mutually_exclusive(mutually_exclusive_terms):
    params = {
        'string1': 'cat',
        'fox': 'hat',
    }
    assert check_mutually_exclusive(mutually_exclusive_terms, params) == []