Exemple #1
0
    def clean(self):
        if self.type == "static" and not isinstance(self.value, (list, dict)):
            raise ModelValidationError(
                "Error saving choices '%s' - type was 'static' "
                "but the value was not a list or dictionary" % self.value)
        elif self.type == "url" and not isinstance(self.value,
                                                   six.string_types):
            raise ModelValidationError(
                "Error saving choices '%s' - type was 'url' but "
                "the value was not a string" % self.value)
        elif self.type == "command" and not isinstance(
                self.value, (six.string_types, dict)):
            raise ModelValidationError(
                "Error saving choices '%s' - type was 'command' "
                "but the value was not a string or dict" % self.value)

        if self.type == "command" and isinstance(self.value, dict):
            value_keys = self.value.keys()
            for required_key in ("command", "system", "version"):
                if required_key not in value_keys:
                    raise ModelValidationError(
                        "Error saving choices '%s' - specifying "
                        "value as a dictionary requires a '%s' "
                        "item" % (self.value, required_key))

        try:
            if self.details == {}:
                if isinstance(self.value, six.string_types):
                    self.details = parse(self.value)
                elif isinstance(self.value, dict):
                    self.details = parse(self.value["command"])
        except (LarkError, ParseError):
            raise ModelValidationError(
                "Error saving choices '%s' - unable to parse" % self.value)
Exemple #2
0
    def clean(self):
        if self.type == "static" and not isinstance(self.value, (list, dict)):
            raise ModelValidationError(
                f"Can not save choices '{self}': type is 'static' but the value is "
                "not a list or dictionary")
        elif self.type == "url" and not isinstance(self.value,
                                                   six.string_types):
            raise ModelValidationError(
                f"Can not save choices '{self}': type is 'url' but the value is "
                "not a string")
        elif self.type == "command" and not isinstance(
                self.value, (six.string_types, dict)):
            raise ModelValidationError(
                f"Can not save choices '{self}': type is 'command' but the value is "
                "not a string or dict")

        if self.type == "command" and isinstance(self.value, dict):
            value_keys = self.value.keys()
            for required_key in ("command", "system", "version"):
                if required_key not in value_keys:
                    raise ModelValidationError(
                        f"Can not save choices '{self}': specifying value as a "
                        f"dictionary requires a '{required_key}' item")

        try:
            if self.details == {}:
                if isinstance(self.value, six.string_types):
                    self.details = parse(self.value)
                elif isinstance(self.value, dict):
                    self.details = parse(self.value["command"])
        except (LarkError, ParseError):
            raise ModelValidationError(
                f"Can not save choices '{self}': Unable to parse")
Exemple #3
0
 def test_parse_func_error(self, input_string):
     with pytest.raises(ParseError):
         parse(input_string, parse_as="func")
Exemple #4
0
 def test_parse_func(self, input_string, expected):
     assert expected == parse(input_string, parse_as="func")
Exemple #5
0
 def test_parse_no_hint(self, input_string, expected):
     assert expected == parse(input_string)
Exemple #6
0
 def test_parse_empty(self):
     with pytest.raises(ParseError):
         parse("")
Exemple #7
0
 def test_parse_reference_error(self, input_string):
     with pytest.raises(ParseError):
         parse(input_string, parse_as="reference")
Exemple #8
0
 def test_parse_reference(self):
     assert "index" == parse("${index}", parse_as="reference")
Exemple #9
0
 def test_parse_url_error(self, input_string):
     with pytest.raises(ParseError):
         parse(input_string, parse_as="url")
Exemple #10
0
 def test_parse_url(self, input_string, expected):
     assert expected == parse(input_string, parse_as="url")
Exemple #11
0
    def _validate_value_in_choices(self, request, value, command_parameter):
        """Validate that the value(s) are valid according to the choice constraints"""
        if (value is not None and not command_parameter.optional
                and command_parameter.choices
                and command_parameter.choices.strict):

            choices = command_parameter.choices

            def map_param_values(kv_pair_list):
                param_map = {}
                for param_name, param_ref in kv_pair_list:
                    if param_ref == "instance_name":
                        param_map[param_name] = request.instance_name
                    else:
                        param_map[param_name] = request.parameters[param_ref]

                return param_map

            if choices.type == "static":
                if isinstance(choices.value, list):
                    raw_allowed = choices.value
                elif isinstance(choices.value, dict):
                    key = choices.details.get("key_reference")
                    if key is None:
                        raise ModelValidationError(
                            "Unable to validate choices for parameter '%s' - Choices"
                            " with a dictionary value must specify a key_reference"
                            % command_parameter.key)

                    if key == "instance_name":
                        key_reference_value = request.instance_name
                    else:
                        # Mongoengine stores None keys as 'null', use instead of None
                        key_reference_value = request.parameters.get(
                            key) or "null"

                    raw_allowed = choices.value.get(key_reference_value)
                    if raw_allowed is None:
                        raise ModelValidationError(
                            "Unable to validate choices for parameter '%s' - Choices"
                            " dictionary doesn't contain an entry with key '%s'"
                            % (command_parameter.key, key_reference_value))
                else:
                    raise ModelValidationError(
                        "Unable to validate choices for parameter '%s' - Choices value"
                        " must be a list or dictionary " %
                        command_parameter.key)
            elif choices.type == "url":
                parsed_value = parse(choices.value, parse_as="url")
                query_params = map_param_values(parsed_value["args"])

                raw_allowed = json.loads(
                    self._session.get(parsed_value["address"],
                                      params=query_params).text)
            elif choices.type == "command":

                if isinstance(choices.value, six.string_types):
                    parsed_value = parse(choices.value, parse_as="func")

                    choices_request = Request(
                        system=request.system,
                        system_version=request.system_version,
                        instance_name=request.instance_name,
                        namespace=request.namespace,
                        command=parsed_value["name"],
                        parameters=map_param_values(parsed_value["args"]),
                    )
                elif isinstance(choices.value, dict):
                    parsed_value = parse(choices.value["command"],
                                         parse_as="func")
                    choices_request = Request(
                        system=choices.value.get("system"),
                        system_version=choices.value.get("version"),
                        namespace=choices.value.get("namespace",
                                                    config.get("garden.name")),
                        instance_name=choices.value.get(
                            "instance_name", "default"),
                        command=parsed_value["name"],
                        parameters=map_param_values(parsed_value["args"]),
                    )
                else:
                    raise ModelValidationError(
                        "Unable to validate choices for parameter '%s' - Choices value"
                        " must be a string or dictionary " %
                        command_parameter.key)

                try:
                    response = process_wait(choices_request,
                                            self._command_timeout)
                except TimeoutError:
                    raise ModelValidationError(
                        "Unable to validate choices for parameter '%s' - Choices "
                        "request took too long to complete" %
                        command_parameter.key)

                raw_allowed = json.loads(response.output)

                if isinstance(raw_allowed, list):
                    if len(raw_allowed) < 1:
                        raise ModelValidationError(
                            "Unable to validate choices for parameter '%s' - Result "
                            "of choices query was empty list" %
                            command_parameter.key)
                else:
                    raise ModelValidationError(
                        "Unable to validate choices for parameter '%s' - Result of "
                        " choices query must be a list" %
                        command_parameter.key)
            else:
                raise ModelValidationError(
                    "Unable to validate choices for parameter '%s' - No valid type "
                    "specified (valid types are %s)" %
                    (command_parameter.key, Choices.TYPES))

            # At this point raw_allowed is a list, but that list can potentially contain
            # {"value": "", "text": ""} dicts. Need to collapse those to strings
            allowed_values = []
            for allowed in raw_allowed:
                if isinstance(allowed, dict):
                    allowed_values.append(allowed["value"])
                else:
                    allowed_values.append(allowed)

            if command_parameter.multi:
                for single_value in value:
                    if single_value not in allowed_values:
                        raise ModelValidationError(
                            "Value '%s' is not a valid choice for parameter with key "
                            "'%s'. Valid choices are: %s" %
                            (single_value, command_parameter.key,
                             allowed_values))
            else:
                if value not in allowed_values:
                    raise ModelValidationError(
                        "Value '%s' is not a valid choice for parameter with key '%s'. "
                        "Valid choices are: %s" %
                        (value, command_parameter.key, allowed_values))
Exemple #12
0
def _format_choices(choices):
    def determine_display(display_value):
        if isinstance(display_value, six.string_types):
            return 'typeahead'

        return 'select' if len(display_value) <= 50 else 'typeahead'

    def determine_type(type_value):
        if isinstance(type_value, (list, dict)):
            return 'static'
        elif type_value.startswith('http'):
            return 'url'
        else:
            return 'command'

    if not choices:
        return None

    if not isinstance(choices, (list, six.string_types, dict)):
        raise PluginParamError(
            "Invalid 'choices' provided. Must be a list, dictionary or string."
        )

    elif isinstance(choices, dict):
        if not choices.get('value'):
            raise PluginParamError(
                "No 'value' provided for choices. You must at least "
                "provide valid values.")

        value = choices.get('value')
        display = choices.get('display', determine_display(value))
        choice_type = choices.get('type')
        strict = choices.get('strict', True)

        if choice_type is None:
            choice_type = determine_type(value)
        elif choice_type not in Choices.TYPES:
            raise PluginParamError(
                "Invalid choices type '%s' - Valid type options are %s" %
                (choice_type, Choices.TYPES))
        else:
            if (choice_type == 'command' and not isinstance(value, (six.string_types, dict))) \
                    or (choice_type == 'url' and not isinstance(value, six.string_types)) \
                    or (choice_type == 'static' and not isinstance(value, (list, dict))):
                allowed_types = {
                    'command': "('string', 'dictionary')",
                    'url': "('string')",
                    'static': "('list', 'dictionary)"
                }
                raise PluginParamError(
                    "Invalid choices value type '%s' - Valid value types for "
                    "choice type '%s' are %s" %
                    (type(value), choice_type, allowed_types[choice_type]))

        if display not in Choices.DISPLAYS:
            raise PluginParamError(
                "Invalid choices display '%s' - Valid display options are %s" %
                (display, Choices.DISPLAYS))
    else:
        value = choices
        display = determine_display(value)
        choice_type = determine_type(value)
        strict = True

    # Now parse out type-specific aspects
    unparsed_value = ''
    try:
        if choice_type == 'command':
            if isinstance(value, six.string_types):
                unparsed_value = value
            else:
                unparsed_value = value['command']

            details = parse(unparsed_value, parse_as='func')
        elif choice_type == 'url':
            unparsed_value = value
            details = parse(unparsed_value, parse_as='url')
        else:
            if isinstance(value, dict):
                unparsed_value = choices.get('key_reference')
                if unparsed_value is None:
                    raise PluginParamError(
                        'Specifying a static choices dictionary requires a '
                        '"key_reference" field with a reference to another '
                        'parameter ("key_reference": "${param_key}")')

                details = {
                    'key_reference': parse(unparsed_value,
                                           parse_as='reference')
                }
            else:
                details = {}
    except ParseError:
        raise PluginParamError(
            "Invalid choices definition - Unable to parse '%s'" %
            unparsed_value)

    return Choices(type=choice_type,
                   display=display,
                   value=value,
                   strict=strict,
                   details=details)
Exemple #13
0
 def test_parse_reference(self):
     assert 'index' == parse('${index}', parse_as='reference')
Exemple #14
0
def _format_choices(choices):
    def determine_display(display_value):
        if isinstance(display_value, six.string_types):
            return "typeahead"

        return "select" if len(display_value) <= 50 else "typeahead"

    def determine_type(type_value):
        if isinstance(type_value, (list, dict)):
            return "static"
        elif type_value.startswith("http"):
            return "url"
        else:
            return "command"

    if not choices:
        return None

    if not isinstance(choices, (list, six.string_types, dict)):
        raise PluginParamError(
            "Invalid 'choices' provided. Must be a list, dictionary or string."
        )

    elif isinstance(choices, dict):
        if not choices.get("value"):
            raise PluginParamError(
                "No 'value' provided for choices. You must at least "
                "provide valid values.")

        value = choices.get("value")
        display = choices.get("display", determine_display(value))
        choice_type = choices.get("type")
        strict = choices.get("strict", True)

        if choice_type is None:
            choice_type = determine_type(value)
        elif choice_type not in Choices.TYPES:
            raise PluginParamError(
                "Invalid choices type '%s' - Valid type options are %s" %
                (choice_type, Choices.TYPES))
        else:
            if ((choice_type == "command"
                 and not isinstance(value, (six.string_types, dict)))
                    or (choice_type == "url"
                        and not isinstance(value, six.string_types))
                    or (choice_type == "static"
                        and not isinstance(value, (list, dict)))):
                allowed_types = {
                    "command": "('string', 'dictionary')",
                    "url": "('string')",
                    "static": "('list', 'dictionary)",
                }
                raise PluginParamError(
                    "Invalid choices value type '%s' - Valid value types for "
                    "choice type '%s' are %s" %
                    (type(value), choice_type, allowed_types[choice_type]))

        if display not in Choices.DISPLAYS:
            raise PluginParamError(
                "Invalid choices display '%s' - Valid display options are %s" %
                (display, Choices.DISPLAYS))
    else:
        value = choices
        display = determine_display(value)
        choice_type = determine_type(value)
        strict = True

    # Now parse out type-specific aspects
    unparsed_value = ""
    try:
        if choice_type == "command":
            if isinstance(value, six.string_types):
                unparsed_value = value
            else:
                unparsed_value = value["command"]

            details = parse(unparsed_value, parse_as="func")
        elif choice_type == "url":
            unparsed_value = value
            details = parse(unparsed_value, parse_as="url")
        else:
            if isinstance(value, dict):
                unparsed_value = choices.get("key_reference")
                if unparsed_value is None:
                    raise PluginParamError(
                        "Specifying a static choices dictionary requires a "
                        '"key_reference" field with a reference to another '
                        'parameter ("key_reference": "${param_key}")')

                details = {
                    "key_reference": parse(unparsed_value,
                                           parse_as="reference")
                }
            else:
                details = {}
    except ParseError:
        raise PluginParamError(
            "Invalid choices definition - Unable to parse '%s'" %
            unparsed_value)

    return Choices(type=choice_type,
                   display=display,
                   value=value,
                   strict=strict,
                   details=details)