Add full support for PortDef data type

Add translation support for tosca.datatypes.network.PortDef
data type and create unit tests for it.

Change-Id: Iec56590d2d00cfb1a36f03339bd041b9ab35dd12
Closes-Bug: #1477735
This commit is contained in:
Vahid Hashemian 2015-07-24 14:36:57 -07:00
parent a951b93c16
commit 1d096b3852
13 changed files with 64 additions and 17 deletions

View File

@ -85,7 +85,7 @@ def parse_parameters(parameter_list):
def translate(sourcetype, path, parsed_params):
output = None
if sourcetype == "tosca":
tosca = ToscaTemplate(path)
tosca = ToscaTemplate(path, parsed_params)
translator = TOSCATranslator(tosca, parsed_params)
output = translator.translate()
return output

View File

@ -211,7 +211,7 @@ class TranslationUtils(object):
expected_hot_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)), hot_file)
tosca = ToscaTemplate(tosca_tpl)
tosca = ToscaTemplate(tosca_tpl, params)
translate = translator.hot.tosca_translator.TOSCATranslator(tosca,
params)
output = translate.translate()

View File

@ -46,7 +46,8 @@ TOSCA_TO_HOT_INPUT_TYPES = {'string': 'string',
'float': 'number',
'boolean': 'boolean',
'timestamp': 'string',
'null': 'string'}
'null': 'string',
'PortDef': 'number'}
class TranslateInputs(object):

View File

@ -24,7 +24,7 @@ class ToscaMongoNodejsTest(TestCase):
tosca_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"../toscalib/tests/data/tosca_nodejs_mongodb_two_instances.yaml")
tosca = ToscaTemplate(tosca_tpl)
tosca = ToscaTemplate(tosca_tpl, parsed_params)
def test_relationship_def(self):
expected_relationship = ['tosca.relationships.HostedOn']

View File

@ -38,8 +38,10 @@ class DataEntity(object):
# A datatype can not have both 'type' and 'properties' definitions.
# If the datatype has 'type' definition
if self.datatype.value_type:
DataEntity.validate_datatype(self.datatype.value_type, self.value,
None, self.custom_def)
self.value = DataEntity.validate_datatype(self.datatype.value_type,
self.value,
None,
self.custom_def)
schema = Schema(None, self.datatype.defs)
for constraint in schema.constraints:
constraint.validate(self.value)

View File

@ -34,11 +34,13 @@ class Schema(collections.Mapping):
PROPERTY_TYPES = (
INTEGER, STRING, BOOLEAN, FLOAT,
NUMBER, TIMESTAMP, LIST, MAP,
SCALAR_UNIT_SIZE, SCALAR_UNIT_FREQUENCY, SCALAR_UNIT_TIME
SCALAR_UNIT_SIZE, SCALAR_UNIT_FREQUENCY, SCALAR_UNIT_TIME,
PORTDEF
) = (
'integer', 'string', 'boolean', 'float',
'number', 'timestamp', 'list', 'map',
'scalar-unit.size', 'scalar-unit.frequency', 'scalar-unit.time'
'scalar-unit.size', 'scalar-unit.frequency', 'scalar-unit.time',
'PortDef'
)
SCALAR_UNIT_SIZE_DEFAULT = 'B'

View File

@ -15,7 +15,10 @@ import logging
from translator.toscalib.common.exception import MissingRequiredFieldError
from translator.toscalib.common.exception import UnknownFieldError
from translator.toscalib.dataentity import DataEntity
from translator.toscalib.elements.constraints import Schema
from translator.toscalib.elements.entitytype import EntityType
from translator.toscalib.utils.gettextutils import _
log = logging.getLogger('tosca')
@ -46,9 +49,11 @@ class Input(object):
def constraints(self):
return self.schema.constraints
def validate(self):
def validate(self, value=None):
self._validate_field()
self.validate_type(self.type)
if value:
self._validate_value(value)
def _validate_field(self):
for name in self.schema:
@ -60,6 +65,16 @@ class Input(object):
if input_type not in Schema.PROPERTY_TYPES:
raise ValueError(_('Invalid type %s') % type)
def _validate_value(self, value):
tosca = EntityType.TOSCA_DEF
datatype = None
if self.type in tosca:
datatype = tosca[self.type]
elif EntityType.DATATYPE_PREFIX + self.type in tosca:
datatype = tosca[EntityType.DATATYPE_PREFIX + self.type]
DataEntity.validate_datatype(self.type, value, None, datatype)
class Output(object):

View File

@ -26,7 +26,7 @@ topology_template:
type: string
description: Root password for MySQL.
db_port:
type: integer
type: PortDef
description: Port for the MySQL database.
node_templates:

View File

@ -30,7 +30,7 @@ topology_template:
type: string
description: Root password for MySQL.
db_port:
type: integer
type: PortDef
description: Port for the MySQL database.
default: 3306

View File

@ -16,6 +16,7 @@ from testtools.testcase import skip
from translator.toscalib.common import exception
from translator.toscalib.dataentity import DataEntity
from translator.toscalib.elements.datatype import DataType
from translator.toscalib.parameters import Input
from translator.toscalib.tests.base import TestCase
from translator.toscalib.tosca_template import ToscaTemplate
from translator.toscalib.utils import yamlparser
@ -114,6 +115,24 @@ class DataTypeTest(TestCase):
data = DataEntity('PortSpec', value.get('user_port'))
self.assertIsNotNone(data.validate())
def test_built_in_nested_datatype_portdef(self):
tpl_snippet = '''
inputs:
db_port:
type: PortDef
description: Port for the MySQL database
'''
inputs = yamlparser.simple_parse(tpl_snippet)['inputs']
name, attrs = list(inputs.items())[0]
input = Input(name, attrs)
self.assertIsNone(input.validate(3360))
try:
input.validate(336000)
except Exception as err:
self.assertTrue(isinstance(err, exception.ValidationError))
self.assertEqual('None: 336000 is out of range (min:1, '
'max:65535).', err.__str__())
def test_custom_datatype(self):
value_snippet = '''
name: Mike

View File

@ -37,10 +37,12 @@ log = logging.getLogger("tosca.model")
class TopologyTemplate(object):
'''Load the template data.'''
def __init__(self, template, custom_defs, rel_types=None):
def __init__(self, template, custom_defs,
rel_types=None, parsed_params=None):
self.tpl = template
self.custom_defs = custom_defs
self.rel_types = rel_types
self.parsed_params = parsed_params
self._validate_field()
self.description = self._tpl_description()
self.inputs = self._inputs()
@ -55,7 +57,8 @@ class TopologyTemplate(object):
inputs = []
for name, attrs in self._tpl_inputs().items():
input = Input(name, attrs)
input.validate()
if self.parsed_params and name in self.parsed_params:
input.validate(self.parsed_params[name])
inputs.append(input)
return inputs

View File

@ -44,9 +44,10 @@ class ToscaTemplate(object):
VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0']
'''Load the template data.'''
def __init__(self, path):
def __init__(self, path, parsed_params=None):
self.tpl = YAML_LOADER(path)
self.path = path
self.parsed_params = parsed_params
self._validate_field()
self.version = self._tpl_version()
self.relationship_types = self._tpl_relationship_types()
@ -61,7 +62,8 @@ class ToscaTemplate(object):
def _topology_template(self):
return TopologyTemplate(self._tpl_topology_template(),
self._get_all_custom_defs(),
self.relationship_types)
self.relationship_types,
self.parsed_params)
def _inputs(self):
return self.topology_template.inputs

View File

@ -34,8 +34,11 @@ def validate_number(value):
def validate_integer(value):
if not isinstance(value, int):
raise ValueError(_('"%s" is not an integer') % value)
return validate_number(value)
try:
value = int(value)
except Exception:
raise ValueError(_('"%s" is not an integer') % value)
return value
def validate_float(value):