Validate occurrences in relationships
Check that the number of occurences of the relationships of a template is correct related with the definition of the type. Also fix other tests that do not pass this new test. Related-Bug: 2044266 Change-Id: I3dfa56d4e48454983daacc4b210017be1123683a
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -41,4 +41,8 @@ topology_template:
|
||||
num_cpus: 1
|
||||
disk_size: 10 GB
|
||||
mem_size: 2 MB
|
||||
requirements:
|
||||
- host: my_server
|
||||
|
||||
my_server:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
tosca_definitions_version: tosca_simple_yaml_1_0
|
||||
|
||||
imports:
|
||||
- elasticsearch: data/custom_types/elasticsearch.yaml
|
||||
|
||||
description: >
|
||||
Logstash is a tool for receiving, processing and outputting logs. All kinds
|
||||
of logs. System logs, webserver logs, error logs, application logs, and just
|
||||
|
||||
@@ -13,6 +13,8 @@ topology_template:
|
||||
id: vnf1
|
||||
vendor: acmetelco
|
||||
version: 1.0
|
||||
requirements:
|
||||
- virtualLink: PrivateNetwork
|
||||
|
||||
VDU1:
|
||||
type: tosca.nodes.nfv.VDU
|
||||
@@ -24,6 +26,11 @@ topology_template:
|
||||
requirements:
|
||||
- virtualLink: PrivateNetwork
|
||||
- virtualBinding: VDU1
|
||||
# Added to pass the requirement validation
|
||||
# as the tosca.nodes.nfv.CP inherits from tosca.nodes.Port
|
||||
# This type was removed from the final version of the NFV profile
|
||||
- link: PrivateNetwork
|
||||
- binding: VDU1
|
||||
|
||||
PrivateNetwork:
|
||||
type: tosca.nodes.nfv.VL
|
||||
|
||||
@@ -19,6 +19,11 @@ topology_template:
|
||||
type: ServerNode
|
||||
properties:
|
||||
notification_port: 8000
|
||||
requirements:
|
||||
- host: my_server_host
|
||||
|
||||
my_server_host:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
outputs:
|
||||
ip_address:
|
||||
|
||||
@@ -21,3 +21,8 @@ topology_template:
|
||||
inputs:
|
||||
param3:
|
||||
type: string
|
||||
requirements:
|
||||
- host: my_server
|
||||
|
||||
my_server:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
@@ -17,3 +17,8 @@ topology_template:
|
||||
inputs:
|
||||
param3:
|
||||
type: string
|
||||
requirements:
|
||||
- host: compute
|
||||
|
||||
compute:
|
||||
type: tosca.nodes.Compute
|
||||
@@ -15,6 +15,11 @@ topology_template:
|
||||
CustomOp:
|
||||
notifications:
|
||||
CustomNo:
|
||||
requirements:
|
||||
- host: compute
|
||||
|
||||
compute:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
interface_types:
|
||||
tosca.interfaces.CustomInterface:
|
||||
|
||||
@@ -14,6 +14,11 @@ topology_template:
|
||||
operations:
|
||||
CustomOp: # operation from interface_type with additional outputs
|
||||
outputs:
|
||||
requirements:
|
||||
- host: compute
|
||||
|
||||
compute:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
interface_types:
|
||||
tosca.interfaces.CustomInterface:
|
||||
|
||||
@@ -30,6 +30,11 @@ topology_template:
|
||||
node: VL1
|
||||
- virtualBinding:
|
||||
node: VDU1
|
||||
# Added to pass the requirement validation
|
||||
# as the tosca.nodes.nfv.CP inherits from tosca.nodes.Port
|
||||
# This type was removed from the final version of the NFV profile
|
||||
- link: VL1
|
||||
- binding: VDU1
|
||||
|
||||
VDU2:
|
||||
type: tosca.nodes.nfv.VDU.Tacker
|
||||
@@ -50,7 +55,11 @@ topology_template:
|
||||
node: VL1
|
||||
- virtualBinding:
|
||||
node: VDU2
|
||||
|
||||
# Added to pass the requirement validation
|
||||
# as the tosca.nodes.nfv.CP inherits from tosca.nodes.Port
|
||||
# This type was removed from the final version of the NFV profile
|
||||
- link: VL1
|
||||
- binding: VDU2
|
||||
VL1:
|
||||
type: tosca.nodes.nfv.VL
|
||||
properties:
|
||||
|
||||
@@ -22,6 +22,8 @@ topology_template:
|
||||
node: mysql_database
|
||||
relationship:
|
||||
type: tosca.relationships.ConnectsTo
|
||||
- host: my_webserver
|
||||
- database_endpoint: mysql_database
|
||||
mysql_database:
|
||||
description: Specify requirement via a capability as an implicit relationship.
|
||||
type: tosca.nodes.Database
|
||||
@@ -31,8 +33,14 @@ topology_template:
|
||||
relationship: tosca.relationships.HostedOn
|
||||
my_dbms:
|
||||
type: tosca.nodes.DBMS
|
||||
requirements:
|
||||
- host:
|
||||
node: my_server
|
||||
my_webserver:
|
||||
type: tosca.nodes.WebServer
|
||||
requirements:
|
||||
- host:
|
||||
node: my_server
|
||||
my_server:
|
||||
description: >
|
||||
Specify requirement via a relationship template, as an explicit relationship.
|
||||
|
||||
@@ -34,3 +34,8 @@ topology_template:
|
||||
test_cap:
|
||||
properties:
|
||||
test: 1
|
||||
requirements:
|
||||
- host: test_server
|
||||
|
||||
test_server:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
@@ -10,4 +10,8 @@ topology_template:
|
||||
node_templates:
|
||||
test:
|
||||
type: tosca.nodes.SomeNode
|
||||
requirements:
|
||||
- host: my_server
|
||||
|
||||
my_server:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
@@ -10,3 +10,8 @@ topology_template:
|
||||
node_templates:
|
||||
test:
|
||||
type: tosca.nodes.SomeNode
|
||||
requirements:
|
||||
- host: test_server
|
||||
|
||||
test_server:
|
||||
type: tosca.nodes.Compute
|
||||
@@ -12,15 +12,43 @@ topology_template:
|
||||
node_templates:
|
||||
wordpress:
|
||||
type: tosca.nodes.WebApplication.WordPress
|
||||
requirements:
|
||||
- host: server
|
||||
- database_endpoint: wordpress_db
|
||||
|
||||
testrsyslogtype:
|
||||
type: tosca.nodes.SoftwareComponent.Rsyslog.TestRsyslogType
|
||||
requirements:
|
||||
- log_endpoint: logstash
|
||||
- host: server
|
||||
|
||||
rsyslog:
|
||||
type: Test2ndRsyslogType
|
||||
requirements:
|
||||
- log_endpoint: logstash
|
||||
- host: server
|
||||
|
||||
logstash:
|
||||
type: tosca.nodes.SoftwareComponent.Logstash
|
||||
requirements:
|
||||
- search_endpoint: elasticsearch
|
||||
- host: server
|
||||
|
||||
kibana:
|
||||
type: tosca.nodes.SoftwareComponent.Kibana
|
||||
requirements:
|
||||
- search_endpoint: elasticsearch
|
||||
- host: server
|
||||
|
||||
elasticsearch:
|
||||
type: tosca.nodes.SoftwareComponent.Elasticsearch
|
||||
requirements:
|
||||
- host: server
|
||||
|
||||
server:
|
||||
type: tosca.nodes.Compute
|
||||
|
||||
wordpress_db:
|
||||
type: tosca.nodes.Database
|
||||
requirements:
|
||||
- host: server
|
||||
@@ -17,6 +17,7 @@ topology_template:
|
||||
type: sample.SC
|
||||
requirements:
|
||||
- custom_host: Compute1
|
||||
- host: Compute1
|
||||
Compute1:
|
||||
type: tosca.nodes.Compute
|
||||
SC2:
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
tosca_definitions_version: tosca_simple_yaml_1_0
|
||||
|
||||
description: >
|
||||
Webserver without host requirement
|
||||
|
||||
topology_template:
|
||||
node_templates:
|
||||
webserver:
|
||||
type: tosca.nodes.WebServer
|
||||
@@ -30,6 +30,7 @@ topology_template:
|
||||
requirements:
|
||||
- receiver1: trans1
|
||||
- receiver2: trans2
|
||||
- host: server
|
||||
|
||||
trans1:
|
||||
type: example.TransactionSubsystem
|
||||
@@ -60,3 +61,8 @@ topology_template:
|
||||
# capabilities:
|
||||
# database_endpoint:
|
||||
# to be updated when substitution_mapping is validated later
|
||||
requirements:
|
||||
- host: server
|
||||
|
||||
server:
|
||||
type: tosca.nodes.Compute
|
||||
@@ -47,6 +47,14 @@ topology_template:
|
||||
requirements:
|
||||
- host:
|
||||
node: websrv
|
||||
- database:
|
||||
node: db
|
||||
|
||||
db:
|
||||
type: example.DatabaseSubsystem
|
||||
requirements:
|
||||
- host:
|
||||
node: server
|
||||
|
||||
websrv:
|
||||
type: tosca.nodes.WebServer
|
||||
|
||||
@@ -83,7 +83,7 @@ class NodeTemplate(EntityTemplate):
|
||||
' can not be full-filled.') \
|
||||
% {'node': node, 'name': self.name}
|
||||
if (node in list(self.type_definition.TOSCA_DEF.keys())
|
||||
or node in self.custom_def):
|
||||
or (self.custom_def and node in self.custom_def)):
|
||||
ExceptionCollector.appendException(NotImplementedError(msg))
|
||||
return
|
||||
|
||||
@@ -221,6 +221,51 @@ class NodeTemplate(EntityTemplate):
|
||||
self._common_validate_field(req, allowed_reqs,
|
||||
'requirements')
|
||||
|
||||
def _validate_relationship_occurrences(self):
|
||||
type_requires = self.type_definition.get_all_requirements()
|
||||
requires = self.type_definition.get_value(self.REQUIREMENTS,
|
||||
self.entity_tpl)
|
||||
if requires is None:
|
||||
requires = []
|
||||
# in case of substitution mapping, we need to get also the substitution
|
||||
if self.sub_mapping_tosca_template:
|
||||
mapping_reqs = self.sub_mapping_tosca_template.requirements
|
||||
if mapping_reqs:
|
||||
if isinstance(mapping_reqs, list):
|
||||
requires.extend(mapping_reqs)
|
||||
else:
|
||||
requires.append(mapping_reqs)
|
||||
for tpl in self.sub_mapping_tosca_template.nodetemplates:
|
||||
if tpl.type == self.type:
|
||||
if tpl.requirements:
|
||||
if isinstance(tpl.requirements, list):
|
||||
requires.extend(tpl.requirements)
|
||||
else:
|
||||
requires.append(tpl.requirements)
|
||||
break
|
||||
|
||||
if type_requires:
|
||||
for treq in type_requires:
|
||||
for key, value in treq.items():
|
||||
occurrences = value.get('occurrences', [1, 'UNBOUNDED'])
|
||||
min_occurrences = occurrences[0]
|
||||
max_occurrences = occurrences[1]
|
||||
if max_occurrences == "UNBOUNDED":
|
||||
max_occurrences = 9999999999
|
||||
|
||||
count = 0
|
||||
for req in requires:
|
||||
for req_name in list(req.keys()):
|
||||
if req_name == key:
|
||||
count += 1
|
||||
|
||||
if count < min_occurrences or count > max_occurrences:
|
||||
ExceptionCollector.appendException(
|
||||
ValidationError(
|
||||
message='Relationship "%s" in template "%s"'
|
||||
' has a wrong number of '
|
||||
'occurrences' % (key, self.name)))
|
||||
|
||||
def _validate_requirements_properties(self, requirements):
|
||||
# TODO(anyone): Only occurrences property of the requirements is
|
||||
# validated here. Validation of other requirement properties are being
|
||||
|
||||
@@ -213,6 +213,11 @@ class PropertyTest(TestCase):
|
||||
type: tosca.nodes.SoftwareComponent.MySoftware
|
||||
properties:
|
||||
component_version: 3.1
|
||||
requirements:
|
||||
- host: my_server_host
|
||||
|
||||
my_server_host:
|
||||
type: tosca.nodes.Compute
|
||||
'''
|
||||
|
||||
expected_properties = ['component_version',
|
||||
|
||||
@@ -84,16 +84,18 @@ class TopologyTemplateTest(TestCase):
|
||||
def test_node_tpls(self):
|
||||
'''Test nodetemplate names.'''
|
||||
self.assertEqual(
|
||||
['app', 'server', 'websrv'],
|
||||
['app', 'db', 'server', 'websrv'],
|
||||
sorted([tpl.name for tpl in self.topo.nodetemplates]))
|
||||
|
||||
tpl_name = "app"
|
||||
expected_type = "example.SomeApp"
|
||||
expected_properties = ['admin_user', 'pool_size']
|
||||
expected_capabilities = ['app_endpoint', 'feature', 'message_receiver']
|
||||
expected_requirements = [{'host': {'node': 'websrv'}}]
|
||||
expected_relationshp = ['tosca.relationships.HostedOn']
|
||||
expected_host = ['websrv']
|
||||
expected_requirements = [{'host': {'node': 'websrv'}},
|
||||
{'database': {'node': 'db'}}]
|
||||
expected_relationshp = ['tosca.relationships.HostedOn',
|
||||
'tosca.relationships.ConnectsTo']
|
||||
expected_host = ['websrv', 'db']
|
||||
for tpl in self.topo.nodetemplates:
|
||||
if tpl_name == tpl.name:
|
||||
'''Test node type.'''
|
||||
|
||||
@@ -154,12 +154,12 @@ class ToscaTemplateTest(TestCase):
|
||||
# Nodes that contain "relationship" in "requirements"
|
||||
depend_node_types = (
|
||||
"tosca.nodes.SoftwareComponent",
|
||||
"sample.SC",
|
||||
)
|
||||
|
||||
# Nodes that do not contain "relationship" in "requirements"
|
||||
non_depend_node_types = (
|
||||
"tosca.nodes.Compute",
|
||||
"sample.SC",
|
||||
)
|
||||
|
||||
tosca_tpl = utils.get_sample_test_path(
|
||||
@@ -327,6 +327,8 @@ class ToscaTemplateTest(TestCase):
|
||||
if node_tpl.name == 'my_app':
|
||||
expected_relationship = [
|
||||
('tosca.relationships.ConnectsTo', 'mysql_database'),
|
||||
('tosca.relationships.ConnectsTo', 'mysql_database'),
|
||||
('tosca.relationships.HostedOn', 'my_webserver'),
|
||||
('tosca.relationships.HostedOn', 'my_webserver')]
|
||||
actual_relationship = sorted([
|
||||
(relation.type, node.name) for
|
||||
@@ -487,8 +489,14 @@ class ToscaTemplateTest(TestCase):
|
||||
"test": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
{
|
||||
"host": "test_server"
|
||||
}
|
||||
]
|
||||
},
|
||||
'test_server': {'type': 'tosca.nodes.Compute'}
|
||||
}
|
||||
|
||||
tosca_tpl = utils.get_sample_test_path(
|
||||
@@ -618,7 +626,8 @@ class ToscaTemplateTest(TestCase):
|
||||
tosca_tpl = utils.get_sample_test_path(
|
||||
"data/test_instance_nested_imports.yaml")
|
||||
tosca = ToscaTemplate(tosca_tpl)
|
||||
expected_custom_types = ['tosca.nodes.SoftwareComponent.Kibana',
|
||||
expected_custom_types = ['tosca.nodes.SoftwareComponent.Elasticsearch',
|
||||
'tosca.nodes.SoftwareComponent.Kibana',
|
||||
'tosca.nodes.WebApplication.WordPress',
|
||||
'test_namespace_prefix.Rsyslog',
|
||||
'Test2ndRsyslogType',
|
||||
|
||||
@@ -750,6 +750,8 @@ tosca-parser/master/toscaparser/tests/data/custom_types/wordpress.yaml
|
||||
properties:
|
||||
root_password: aaa
|
||||
port: 3376
|
||||
requirements:
|
||||
- host: server
|
||||
|
||||
groups:
|
||||
webserver_group:
|
||||
@@ -773,6 +775,8 @@ tosca-parser/master/toscaparser/tests/data/custom_types/wordpress.yaml
|
||||
properties:
|
||||
root_password: aaa
|
||||
port: 3376
|
||||
requirements:
|
||||
- host: server
|
||||
|
||||
groups:
|
||||
webserver_group:
|
||||
@@ -799,6 +803,8 @@ tosca-parser/master/toscaparser/tests/data/custom_types/wordpress.yaml
|
||||
properties:
|
||||
root_password: aaa
|
||||
port: 3376
|
||||
requirements:
|
||||
- host: server
|
||||
|
||||
groups:
|
||||
webserver_group:
|
||||
@@ -826,6 +832,8 @@ tosca-parser/master/toscaparser/tests/data/custom_types/wordpress.yaml
|
||||
properties:
|
||||
root_password: aaa
|
||||
port: 3376
|
||||
requirements:
|
||||
- host: server
|
||||
|
||||
groups:
|
||||
webserver_group:
|
||||
@@ -854,6 +862,8 @@ tosca-parser/master/toscaparser/tests/data/custom_types/wordpress.yaml
|
||||
properties:
|
||||
root_password: aaa
|
||||
port: 3376
|
||||
requirements:
|
||||
- host: server
|
||||
|
||||
groups:
|
||||
webserver_group:
|
||||
@@ -2139,3 +2149,12 @@ tosca-parser/master/toscaparser/tests/data/custom_types/wordpress.yaml
|
||||
"data/test_scalar_unit_without_unit.yaml")
|
||||
self.assertRaises(exception.ValidationError,
|
||||
lambda: ToscaTemplate(tpl_path))
|
||||
|
||||
def test_template_without_requirement(self):
|
||||
tpl_path = utils.get_sample_test_path(
|
||||
"data/test_template_without_requirement.yaml")
|
||||
err = self.assertRaises(exception.ValidationError,
|
||||
lambda: ToscaTemplate(tpl_path))
|
||||
expectedmessage = _('Relationship "host" in template "webserver" has '
|
||||
'a wrong number of occurrences')
|
||||
self.assertIn(expectedmessage, err.message)
|
||||
|
||||
@@ -114,10 +114,16 @@ class ToscaTemplate(object):
|
||||
self.policies = self._policies()
|
||||
self._handle_nested_tosca_templates_with_topology()
|
||||
self.graph = ToscaGraph(self.nodetemplates)
|
||||
self._validate_relationship_occurences()
|
||||
|
||||
ExceptionCollector.stop()
|
||||
self.verify_template()
|
||||
|
||||
def _validate_relationship_occurences(self):
|
||||
for tpl in self.nodetemplates:
|
||||
# Check if the requirements has a correct number of occurrences
|
||||
tpl._validate_relationship_occurrences()
|
||||
|
||||
def _topology_template(self):
|
||||
return TopologyTemplate(self._tpl_topology_template(),
|
||||
self._get_all_custom_defs(),
|
||||
|
||||
Reference in New Issue
Block a user