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