Exemple #1
0
    def validate(self):
        if len(self.args) < 2:
            ExceptionCollector.appendException(
                ValueError(
                    _('Illegal arguments for function "{0}". Expected '
                      'arguments: "node-template-name", "req-or-cap"'
                      '(optional), "property name"').format(GET_ATTRIBUTE)))
            return
        elif len(self.args) == 2:
            self._find_node_template_containing_attribute()
        else:
            node_tpl = self._find_node_template(self.args[0])
            if node_tpl is None:
                return
            index = 2
            attrs = node_tpl.type_definition.get_attributes_def()
            found = [attrs[self.args[1]]] if self.args[1] in attrs else []
            if found:
                attr = found[0]
            else:
                index = 3
                # then check the req or caps
                attr = self._find_req_or_cap_attribute(self.args[1],
                                                       self.args[2])
                if not attr:
                    return

            value_type = attr.schema['type']
            if len(self.args) > index:
                for elem in self.args[index:]:
                    if value_type == "list":
                        if not isinstance(elem, int):
                            ExceptionCollector.appendException(
                                ValueError(
                                    _('Illegal arguments for function'
                                      ' "{0}". "{1}" Expected positive'
                                      ' integer argument').format(
                                          GET_ATTRIBUTE, elem)))
                        value_type = attr.schema['entry_schema']['type']
                    elif value_type == "map":
                        value_type = attr.schema['entry_schema']['type']
                    elif value_type in Schema.PROPERTY_TYPES:
                        ExceptionCollector.appendException(
                            ValueError(
                                _('Illegal arguments for function'
                                  ' "{0}". Unexpected attribute/'
                                  'index value "{1}"').format(
                                      GET_ATTRIBUTE, elem)))
                        return
                    else:  # It is a complex type
                        data_type = DataType(value_type)
                        props = data_type.get_properties_def()
                        found = [props[elem]] if elem in props else []
                        if found:
                            prop = found[0]
                            value_type = prop.schema['type']
                        else:
                            ExceptionCollector.appendException(
                                KeyError(
                                    _('Illegal arguments for function'
                                      ' "{0}". Attribute name "{1}" not'
                                      ' found in "{2}"').format(
                                          GET_ATTRIBUTE, elem, value_type)))
class DataEntity(object):
    """A complex data value entity."""

    def __init__(self, datatypename, value, custom_def=None, prop_name=None):
        self.custom_def = custom_def
        self.type = datatypename
        if datatypename in Schema.PROPERTY_TYPES:
            self.datatype = ValueDataType(datatypename)
            self.schema = {}
        else:
            self.datatype = DataType(datatypename, custom_def)
            if self.datatype.value_type:
                # "type" and "properties" are mutually exclusive
                self.schema = {}
            else:
                self.schema = self.datatype.get_properties_def()
        self.value = value
        self.property_name = prop_name
        self._properties = None

    @property
    def properties(self):
        if self._properties is None:
            from toscaparser.properties import Property

            values = self.value or {}
            self._properties = {
                name: Property(
                    name, values.get(name, aDef.default), aDef.schema, self.custom_def
                )
                for name, aDef in self.schema.items()
            }
        return self._properties

    def validate(self):
        """Validate the value by the definition of the datatype."""

        # A datatype can not have both 'type' and 'properties' definitions.
        # If the datatype has 'type' definition:
        if self.datatype.value_type:
            self.value = DataEntity.validate_datatype(
                self.datatype.value_type, self.value, None, self.custom_def, None, self
            )
            schema = Schema(self.property_name, self.datatype.defs)
            for constraint in schema.constraints:
                constraint.validate(self.value)
        # If the datatype has 'properties' definition:
        else:
            if not isinstance(self.value, dict):
                ExceptionCollector.appendException(
                    TypeMismatchError(what=self.value, type=self.datatype.type)
                )
            allowed_props = []
            required_props = []
            default_props = {}
            if self.schema:
                allowed_props = self.schema.keys()
                for name, prop_def in self.schema.items():
                    if prop_def.required:
                        required_props.append(name)
                    if prop_def.default:
                        default_props[name] = prop_def.default

            # check allowed field
            for value_key in list(self.value.keys()):
                if value_key not in allowed_props:
                    ExceptionCollector.appendException(
                        UnknownFieldError(
                            what=(_('Data value of type "%s"') % self.datatype.type),
                            field=value_key,
                        )
                    )

            # check default field
            for def_key, def_value in list(default_props.items()):
                if def_key not in list(self.value.keys()):
                    self.value[def_key] = def_value

            # check missing field
            missingprop = []
            for req_key in required_props:
                if req_key not in list(self.value.keys()):
                    missingprop.append(req_key)
            if missingprop:
                ExceptionCollector.appendException(
                    MissingRequiredFieldError(
                        what=(_('Data value of type "%s"') % self.datatype.type),
                        required=missingprop,
                    )
                )

            # check every field
            for name, value in list(self.value.items()):
                schema_name = self._find_schema(name)
                if not schema_name:
                    continue
                prop_schema = Schema(name, schema_name)
                # check if field value meets type defined
                DataEntity.validate_datatype(
                    prop_schema.type, value, prop_schema.entry_schema, self.custom_def
                )
                # check if field value meets constraints defined
                if prop_schema.constraints:
                    for constraint in prop_schema.constraints:
                        if isinstance(value, list):
                            for val in value:
                                constraint.validate(val)
                        else:
                            constraint.validate(value)

        return self.value

    def _find_schema(self, name):
        if self.schema and name in self.schema.keys():
            return self.schema[name].schema

    @staticmethod
    def validate_datatype(
        type, value, entry_schema=None, custom_def=None, prop_name=None, self=None
    ):
        """Validate value with given type.

        If type is list or map, validate its entry by entry_schema(if defined)
        If type is a user-defined complex datatype, custom_def is required.
        """
        from toscaparser.functions import is_function

        if is_function(value):
            return value
        if type == Schema.ANY:
            return value
        if type == Schema.STRING:
            return validateutils.validate_string(value)
        elif type == Schema.INTEGER:
            return validateutils.validate_integer(value)
        elif type == Schema.FLOAT:
            return validateutils.validate_float(value)
        elif type == Schema.NUMBER:
            return validateutils.validate_numeric(value)
        elif type == Schema.BOOLEAN:
            return validateutils.validate_boolean(value)
        elif type == Schema.RANGE:
            return validateutils.validate_range(value)
        elif type == Schema.TIMESTAMP:
            validateutils.validate_timestamp(value)
            return value
        elif type == Schema.LIST:
            validateutils.validate_list(value)
            if entry_schema:
                DataEntity.validate_entry(value, entry_schema, custom_def)
            return value
        elif type == Schema.SCALAR_UNIT_SIZE:
            return ScalarUnit_Size(value).validate_scalar_unit()
        elif type == Schema.SCALAR_UNIT_FREQUENCY:
            return ScalarUnit_Frequency(value).validate_scalar_unit()
        elif type == Schema.SCALAR_UNIT_TIME:
            return ScalarUnit_Time(value).validate_scalar_unit()
        elif type == Schema.VERSION:
            return validateutils.TOSCAVersionProperty(value).get_version()
        elif type == Schema.MAP:
            validateutils.validate_map(value)
            if entry_schema:
                DataEntity.validate_entry(value, entry_schema, custom_def)
            return value
        elif type == Schema.PORTSPEC:
            ps = PortSpec(value)
            ps.validate()
            return ps
        elif type == Schema.PORTDEF:
            return validateutils.validate_portdef(value, prop_name)
        elif not self:
            return DataEntity(type, value, custom_def).validate()
        else:  # avoid infinite recursion
            return value

    @staticmethod
    def validate_entry(value, entry_schema, custom_def=None):
        """Validate entries for map and list."""
        schema = Schema(None, entry_schema)
        valuelist = value
        if isinstance(value, dict):
            valuelist = list(value.values())
        for v in valuelist:
            DataEntity.validate_datatype(
                schema.type, v, schema.entry_schema, custom_def
            )
            if schema.constraints:
                for constraint in schema.constraints:
                    constraint.validate(v)
        return value