Merge "Set property required flag to true as default"
This commit is contained in:
@@ -506,12 +506,14 @@ tosca.capabilities.Endpoint:
|
|||||||
properties:
|
properties:
|
||||||
protocol:
|
protocol:
|
||||||
type: string
|
type: string
|
||||||
|
required: true
|
||||||
default: tcp
|
default: tcp
|
||||||
port:
|
port:
|
||||||
type: tosca.datatypes.network.PortDef
|
type: tosca.datatypes.network.PortDef
|
||||||
required: false
|
required: false
|
||||||
secure:
|
secure:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
required: false
|
||||||
default: false
|
default: false
|
||||||
url_path:
|
url_path:
|
||||||
type: string
|
type: string
|
||||||
@@ -524,6 +526,7 @@ tosca.capabilities.Endpoint:
|
|||||||
required: false
|
required: false
|
||||||
initiator:
|
initiator:
|
||||||
type: string
|
type: string
|
||||||
|
required: false
|
||||||
default: source
|
default: source
|
||||||
constraints:
|
constraints:
|
||||||
- valid_values: [source, target, peer]
|
- valid_values: [source, target, peer]
|
||||||
@@ -792,14 +795,18 @@ tosca.datatypes.network.PortSpec:
|
|||||||
- valid_values: [ udp, tcp, igmp ]
|
- valid_values: [ udp, tcp, igmp ]
|
||||||
target:
|
target:
|
||||||
type: PortDef
|
type: PortDef
|
||||||
|
required: false
|
||||||
target_range:
|
target_range:
|
||||||
type: range
|
type: range
|
||||||
|
required: false
|
||||||
constraints:
|
constraints:
|
||||||
- in_range: [ 1, 65535 ]
|
- in_range: [ 1, 65535 ]
|
||||||
source:
|
source:
|
||||||
type: PortDef
|
type: PortDef
|
||||||
|
required: false
|
||||||
source_range:
|
source_range:
|
||||||
type: range
|
type: range
|
||||||
|
required: false
|
||||||
constraints:
|
constraints:
|
||||||
- in_range: [ 1, 65535 ]
|
- in_range: [ 1, 65535 ]
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ class NodeType(StatefulEntityType):
|
|||||||
if caps is None:
|
if caps is None:
|
||||||
caps = self.get_value(self.CAPABILITIES, None, True)
|
caps = self.get_value(self.CAPABILITIES, None, True)
|
||||||
if caps:
|
if caps:
|
||||||
|
# 'name' is symbolic name of the capability
|
||||||
|
# 'value' is a dict { 'type': <capability type name> }
|
||||||
for name, value in caps.items():
|
for name, value in caps.items():
|
||||||
ctype = value.get('type')
|
ctype = value.get('type')
|
||||||
cap = CapabilityTypeDef(name, ctype, self.type,
|
cap = CapabilityTypeDef(name, ctype, self.type,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class PropertyDef(object):
|
|||||||
PROPERTY_KEYNAME_STATUS) = \
|
PROPERTY_KEYNAME_STATUS) = \
|
||||||
('default', 'required', 'status')
|
('default', 'required', 'status')
|
||||||
|
|
||||||
PROPERTY_REQUIRED_DEFAULT = False
|
PROPERTY_REQUIRED_DEFAULT = True
|
||||||
|
|
||||||
VALID_REQUIRED_VALUES = ['true', 'false']
|
VALID_REQUIRED_VALUES = ['true', 'false']
|
||||||
VALID_STATUS_VALUES = (PROPERTY_STATUS_SUPPORTED,
|
VALID_STATUS_VALUES = (PROPERTY_STATUS_SUPPORTED,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ data_types:
|
|||||||
- min_length: 2
|
- min_length: 2
|
||||||
gender:
|
gender:
|
||||||
type: string
|
type: string
|
||||||
|
required: false
|
||||||
default: unknown
|
default: unknown
|
||||||
|
|
||||||
tosca.my.datatypes.People:
|
tosca.my.datatypes.People:
|
||||||
@@ -27,10 +28,12 @@ data_types:
|
|||||||
properties:
|
properties:
|
||||||
addresses:
|
addresses:
|
||||||
type: map
|
type: map
|
||||||
|
required: false
|
||||||
entry_schema:
|
entry_schema:
|
||||||
type: string
|
type: string
|
||||||
contacts:
|
contacts:
|
||||||
type: list
|
type: list
|
||||||
|
required: false
|
||||||
entry_schema:
|
entry_schema:
|
||||||
type: tosca.my.datatypes.ContactInfo
|
type: tosca.my.datatypes.ContactInfo
|
||||||
|
|
||||||
@@ -44,5 +47,7 @@ data_types:
|
|||||||
- min_length: 2
|
- min_length: 2
|
||||||
contact_email:
|
contact_email:
|
||||||
type: string
|
type: string
|
||||||
|
required: false
|
||||||
contact_phone:
|
contact_phone:
|
||||||
type: string
|
type: string
|
||||||
|
required: false
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ data_types:
|
|||||||
- min_length: 2
|
- min_length: 2
|
||||||
gender:
|
gender:
|
||||||
type: string
|
type: string
|
||||||
|
required: false
|
||||||
default: unknown
|
default: unknown
|
||||||
|
|
||||||
tosca.my.datatypes.People:
|
tosca.my.datatypes.People:
|
||||||
@@ -27,10 +28,12 @@ data_types:
|
|||||||
properties:
|
properties:
|
||||||
addresses:
|
addresses:
|
||||||
type: map
|
type: map
|
||||||
|
required: false
|
||||||
entry_schema:
|
entry_schema:
|
||||||
type: string
|
type: string
|
||||||
contacts:
|
contacts:
|
||||||
type: list
|
type: list
|
||||||
|
required: false
|
||||||
entry_schema:
|
entry_schema:
|
||||||
type: tosca.my.datatypes.ContactInfo
|
type: tosca.my.datatypes.ContactInfo
|
||||||
|
|
||||||
@@ -44,8 +47,10 @@ data_types:
|
|||||||
- min_length: 2
|
- min_length: 2
|
||||||
contact_email:
|
contact_email:
|
||||||
type: string
|
type: string
|
||||||
|
required: false
|
||||||
contact_phone:
|
contact_phone:
|
||||||
type: string
|
type: string
|
||||||
|
required: false
|
||||||
|
|
||||||
topology_template:
|
topology_template:
|
||||||
node_templates:
|
node_templates:
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ topology_template:
|
|||||||
trans1:
|
trans1:
|
||||||
type: example.TransactionSubsystem
|
type: example.TransactionSubsystem
|
||||||
properties:
|
properties:
|
||||||
# to be updated when substitution_mapping is implemented
|
# TODO to be updated when substitution_mapping is implemented
|
||||||
# mq_server_ip: { get_attribute: [ mq, server_ip ] }
|
# mq_server_ip: { get_attribute: [ mq, server_ip ] }
|
||||||
|
# for now, we will use the loopback address to avoid errors as
|
||||||
|
# this property is required in the schema
|
||||||
|
mq_server_ip: 127.0.0.1
|
||||||
receiver_port: 8080
|
receiver_port: 8080
|
||||||
# capabilities:
|
# capabilities:
|
||||||
# message_receiver:
|
# message_receiver:
|
||||||
@@ -33,8 +36,11 @@ topology_template:
|
|||||||
trans2:
|
trans2:
|
||||||
type: example.TransactionSubsystem
|
type: example.TransactionSubsystem
|
||||||
properties:
|
properties:
|
||||||
# to be updated when substitution_mapping is implemented
|
# TODO to be updated when substitution_mapping is implemented
|
||||||
# mq_server_ip: { get_attribute: [ mq, server_ip ] }
|
# mq_server_ip: { get_attribute: [ mq, server_ip ] }
|
||||||
|
# for now, we will use the loopback address to avoid errors as
|
||||||
|
# this property is required in the schema
|
||||||
|
mq_server_ip: 127.0.0.1
|
||||||
receiver_port: 8080
|
receiver_port: 8080
|
||||||
# capabilities:
|
# capabilities:
|
||||||
# message_receiver:
|
# message_receiver:
|
||||||
|
|||||||
@@ -42,10 +42,12 @@ class DataTypeTest(TestCase):
|
|||||||
properties:
|
properties:
|
||||||
addresses:
|
addresses:
|
||||||
type: map
|
type: map
|
||||||
|
required: false
|
||||||
entry_schema:
|
entry_schema:
|
||||||
type: string
|
type: string
|
||||||
contacts:
|
contacts:
|
||||||
type: list
|
type: list
|
||||||
|
required: false
|
||||||
entry_schema:
|
entry_schema:
|
||||||
type: tosca.my.datatypes.ContactInfo
|
type: tosca.my.datatypes.ContactInfo
|
||||||
|
|
||||||
@@ -69,6 +71,15 @@ class DataTypeTest(TestCase):
|
|||||||
value = yamlparser.simple_parse(value_snippet)
|
value = yamlparser.simple_parse(value_snippet)
|
||||||
self.assertEqual(value, {})
|
self.assertEqual(value, {})
|
||||||
|
|
||||||
|
# TODO(Matt) - opened as bug 1555300
|
||||||
|
# Need a test for PortSpec normative data type
|
||||||
|
# that tests the spec. requirement: "A valid PortSpec
|
||||||
|
# must have at least one of the following properties:
|
||||||
|
# target, target_range, source or source_range."
|
||||||
|
# TODO(Matt) - opened as bug 1555310
|
||||||
|
# test PortSpec value for source and target
|
||||||
|
# against the source_range and target_range
|
||||||
|
# when specified.
|
||||||
def test_built_in_datatype(self):
|
def test_built_in_datatype(self):
|
||||||
value_snippet = '''
|
value_snippet = '''
|
||||||
private_network:
|
private_network:
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from testtools import matchers
|
||||||
|
|
||||||
from toscaparser.common import exception
|
from toscaparser.common import exception
|
||||||
from toscaparser.elements.property_definition import PropertyDef
|
from toscaparser.elements.property_definition import PropertyDef
|
||||||
from toscaparser.nodetemplate import NodeTemplate
|
from toscaparser.nodetemplate import NodeTemplate
|
||||||
@@ -180,10 +182,12 @@ class PropertyTest(TestCase):
|
|||||||
def test_timestamp_invalid(self):
|
def test_timestamp_invalid(self):
|
||||||
test_property_schema = {'type': 'timestamp'}
|
test_property_schema = {'type': 'timestamp'}
|
||||||
# invalid timestamp - day out of range
|
# invalid timestamp - day out of range
|
||||||
propertyInstance = Property('test_property', '2015-04-115T02:59:43.1Z',
|
value = '2015-04-115T02:59:43.1Z'
|
||||||
|
propertyInstance = Property('test_property', value,
|
||||||
test_property_schema)
|
test_property_schema)
|
||||||
error = self.assertRaises(ValueError, propertyInstance.validate)
|
error = self.assertRaises(ValueError, propertyInstance.validate)
|
||||||
self.assertEqual(_('day is out of range for month'), str(error))
|
expected_message = (_('"%s" is not a valid timestamp.') % value)
|
||||||
|
self.assertThat(str(error), matchers.StartsWith(expected_message))
|
||||||
|
|
||||||
def test_required(self):
|
def test_required(self):
|
||||||
test_property_schema = {'type': 'string'}
|
test_property_schema = {'type': 'string'}
|
||||||
|
|||||||
@@ -63,6 +63,11 @@ class ToscaDefTest(TestCase):
|
|||||||
self.assertIn(ifaces.LIFECYCLE_SHORTNAME, group_type.interfaces)
|
self.assertIn(ifaces.LIFECYCLE_SHORTNAME, group_type.interfaces)
|
||||||
|
|
||||||
def test_capabilities(self):
|
def test_capabilities(self):
|
||||||
|
# Assure the normative Compute node type
|
||||||
|
# has all the required Capability types
|
||||||
|
# regardless of symbloc name
|
||||||
|
# TODO(Matt) - since Compute IS a normative node type
|
||||||
|
# we SHOULD test symbolic capability names as well
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['tosca.capabilities.Container',
|
['tosca.capabilities.Container',
|
||||||
'tosca.capabilities.Node',
|
'tosca.capabilities.Node',
|
||||||
@@ -70,34 +75,29 @@ class ToscaDefTest(TestCase):
|
|||||||
'tosca.capabilities.Scalable',
|
'tosca.capabilities.Scalable',
|
||||||
'tosca.capabilities.network.Bindable'],
|
'tosca.capabilities.network.Bindable'],
|
||||||
sorted([c.type for c in compute_type.get_capabilities_objects()]))
|
sorted([c.type for c in compute_type.get_capabilities_objects()]))
|
||||||
|
# Assure the normative Network node type
|
||||||
|
# hsa all the required Capability types
|
||||||
|
# TODO(Matt) - since Network IS a normative node type
|
||||||
|
# we SHOULD test symbolic capability names as well
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['tosca.capabilities.Node',
|
['tosca.capabilities.Node',
|
||||||
'tosca.capabilities.network.Linkable'],
|
'tosca.capabilities.network.Linkable'],
|
||||||
sorted([c.type for c in network_type.get_capabilities_objects()]))
|
sorted([c.type for c in network_type.get_capabilities_objects()]))
|
||||||
endpoint_properties = ['initiator', 'network_name', 'port',
|
|
||||||
'port_name', 'ports', 'protocol',
|
# Assure the normative WebServer node type's
|
||||||
'secure', 'url_path']
|
# Endpoint cap. has all required property names
|
||||||
|
# Note: we are testing them in alphabetic sort order
|
||||||
endpoint_props_def_objects = \
|
endpoint_props_def_objects = \
|
||||||
self._get_capability_properties_def_objects(
|
self._get_capability_properties_def_objects(
|
||||||
webserver_type.get_capabilities_objects(),
|
webserver_type.get_capabilities_objects(),
|
||||||
'tosca.capabilities.Endpoint')
|
'tosca.capabilities.Endpoint')
|
||||||
|
# Assure WebServer's Endpoint capability's properties have their
|
||||||
|
# required keyname value set correctly
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
endpoint_properties,
|
[('initiator', False), ('network_name', False), ('port', False),
|
||||||
sorted([p.name for p in endpoint_props_def_objects]))
|
('port_name', False), ('ports', False), ('protocol', True),
|
||||||
for p in endpoint_props_def_objects:
|
('secure', False), ('url_path', False)],
|
||||||
if p.name in endpoint_properties:
|
sorted([(p.name, p.required) for p in endpoint_props_def_objects]))
|
||||||
self.assertFalse(p.required)
|
|
||||||
endpoint_props_def = self._get_capability_properties_def(
|
|
||||||
webserver_type.get_capabilities_objects(),
|
|
||||||
'tosca.capabilities.Endpoint')
|
|
||||||
self.assertEqual(
|
|
||||||
endpoint_properties,
|
|
||||||
sorted(endpoint_props_def.keys()))
|
|
||||||
endpoint_prop_def = self._get_capability_property_def(
|
|
||||||
webserver_type.get_capabilities_objects(),
|
|
||||||
'tosca.capabilities.Endpoint',
|
|
||||||
'initiator')
|
|
||||||
self.assertEqual(None, endpoint_prop_def)
|
|
||||||
|
|
||||||
os_props = self._get_capability_properties_def_objects(
|
os_props = self._get_capability_properties_def_objects(
|
||||||
compute_type.get_capabilities_objects(),
|
compute_type.get_capabilities_objects(),
|
||||||
@@ -139,14 +139,6 @@ class ToscaDefTest(TestCase):
|
|||||||
break
|
break
|
||||||
return properties_def
|
return properties_def
|
||||||
|
|
||||||
def _get_capability_property_def(self, caps, type, property):
|
|
||||||
property_def = None
|
|
||||||
for cap in caps:
|
|
||||||
if cap.type == type:
|
|
||||||
property_def = cap.get_property_def_value(property)
|
|
||||||
break
|
|
||||||
return property_def
|
|
||||||
|
|
||||||
def test_properties_def(self):
|
def test_properties_def(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['name', 'password', 'port', 'user'],
|
['name', 'password', 'port', 'user'],
|
||||||
|
|||||||
@@ -348,6 +348,11 @@ class ToscaTemplateTest(TestCase):
|
|||||||
NotImplementedError,
|
NotImplementedError,
|
||||||
lambda: NodeTemplate(tpl_name, nodetemplates).relationships)
|
lambda: NodeTemplate(tpl_name, nodetemplates).relationships)
|
||||||
|
|
||||||
|
# Test the following:
|
||||||
|
# 1. Custom node type derived from 'WebApplication' named 'TestApp'
|
||||||
|
# with a custom Capability Type 'TestCapability'
|
||||||
|
# 2. Same as #1, but referencing a custom 'TestCapability' Capability Type
|
||||||
|
# that is not defined
|
||||||
def test_custom_capability_type_definition(self):
|
def test_custom_capability_type_definition(self):
|
||||||
tpl_snippet = '''
|
tpl_snippet = '''
|
||||||
node_templates:
|
node_templates:
|
||||||
@@ -358,7 +363,7 @@ class ToscaTemplateTest(TestCase):
|
|||||||
properties:
|
properties:
|
||||||
test: 1
|
test: 1
|
||||||
'''
|
'''
|
||||||
# custom definition with capability type definition
|
# custom node type definition with custom capability type definition
|
||||||
custom_def = '''
|
custom_def = '''
|
||||||
tosca.nodes.WebApplication.TestApp:
|
tosca.nodes.WebApplication.TestApp:
|
||||||
derived_from: tosca.nodes.WebApplication
|
derived_from: tosca.nodes.WebApplication
|
||||||
@@ -383,7 +388,7 @@ class ToscaTemplateTest(TestCase):
|
|||||||
expected_capabilities,
|
expected_capabilities,
|
||||||
sorted(tpl.get_capabilities().keys()))
|
sorted(tpl.get_capabilities().keys()))
|
||||||
|
|
||||||
# custom definition without capability type definition
|
# custom definition without valid capability type definition
|
||||||
custom_def = '''
|
custom_def = '''
|
||||||
tosca.nodes.WebApplication.TestApp:
|
tosca.nodes.WebApplication.TestApp:
|
||||||
derived_from: tosca.nodes.WebApplication
|
derived_from: tosca.nodes.WebApplication
|
||||||
|
|||||||
@@ -89,7 +89,19 @@ def validate_boolean(value):
|
|||||||
|
|
||||||
|
|
||||||
def validate_timestamp(value):
|
def validate_timestamp(value):
|
||||||
return dateutil.parser.parse(value)
|
try:
|
||||||
|
# Note: we must return our own exception message
|
||||||
|
# as dateutil's parser returns different types / values on
|
||||||
|
# different systems. OSX, for example, returns a tuple
|
||||||
|
# containing a different error message than Linux
|
||||||
|
dateutil.parser.parse(value)
|
||||||
|
except Exception as e:
|
||||||
|
original_err_msg = str(e)
|
||||||
|
log.error(original_err_msg)
|
||||||
|
ExceptionCollector.appendException(
|
||||||
|
ValueError(_('"%(val)s" is not a valid timestamp. "%(msg)s"') %
|
||||||
|
{'val': value, 'msg': original_err_msg}))
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class TOSCAVersionProperty(object):
|
class TOSCAVersionProperty(object):
|
||||||
|
|||||||
Reference in New Issue
Block a user