Add output validation for substitution mappings
1. Validate that the attributes of the substitution mappings node type can be accessed in the service template by substituted node. 2.Validate that an attempt to access any attributes not belong to a specific node type or substitution mappings results into an expected error. This patch is related to bp: https://review.openstack.org/#/c/345492/ Co-Authored-By: Sahdev Zala <spzala@us.ibm.com> Change-Id: I5f6cdcf7eb66f20ba9e524b73edd249d2c7b1e31
This commit is contained in:
parent
9baadf93b5
commit
d061ef025d
toscaparser
@ -114,6 +114,10 @@ class UnknownInputError(TOSCAException):
|
||||
msg_fmt = _('Unknown input "%(input_name)s".')
|
||||
|
||||
|
||||
class UnknownOutputError(TOSCAException):
|
||||
msg_fmt = _('Unknown output "%(output_name)s" in %(where)s.')
|
||||
|
||||
|
||||
class MissingRequiredInputError(TOSCAException):
|
||||
msg_fmt = _('%(what)s is missing required input definition '
|
||||
'of input "%(input_name)s".')
|
||||
@ -129,6 +133,11 @@ class MissingDefaultValueError(TOSCAException):
|
||||
'of input "%(input_name)s".')
|
||||
|
||||
|
||||
class MissingRequiredOutputError(TOSCAException):
|
||||
msg_fmt = _('%(what)s is missing required output definition '
|
||||
'of output "%(output_name)s".')
|
||||
|
||||
|
||||
class InvalidPropertyValueError(TOSCAException):
|
||||
msg_fmt = _('Value of property "%(what)s" is invalid.')
|
||||
|
||||
|
@ -18,6 +18,7 @@ from toscaparser.common.exception import MissingDefaultValueError
|
||||
from toscaparser.common.exception import MissingRequiredFieldError
|
||||
from toscaparser.common.exception import MissingRequiredInputError
|
||||
from toscaparser.common.exception import UnknownFieldError
|
||||
from toscaparser.common.exception import UnknownOutputError
|
||||
from toscaparser.elements.nodetype import NodeType
|
||||
from toscaparser.utils.gettextutils import _
|
||||
|
||||
@ -34,6 +35,8 @@ class SubstitutionMappings(object):
|
||||
SECTIONS = (NODE_TYPE, REQUIREMENTS, CAPABILITIES) = \
|
||||
('node_type', 'requirements', 'capabilities')
|
||||
|
||||
OPTIONAL_OUTPUTS = ['tosca_id', 'tosca_name', 'state']
|
||||
|
||||
def __init__(self, sub_mapping_def, nodetemplates, inputs, outputs,
|
||||
sub_mapped_node_template, custom_defs):
|
||||
self.nodetemplates = nodetemplates
|
||||
@ -189,14 +192,23 @@ class SubstitutionMappings(object):
|
||||
# field=req))
|
||||
|
||||
def _validate_outputs(self):
|
||||
"""validate the outputs of substitution mappings."""
|
||||
pass
|
||||
# The outputs in service template which defines substutition mappings
|
||||
# must be in atrributes of node template wchich be mapped.
|
||||
# outputs_names = self.sub_mapped_node_template.get_properties().
|
||||
# keys() if self.sub_mapped_node_template else None
|
||||
# for name in outputs_names:
|
||||
# if name not in [output.name for input in self.outputs]:
|
||||
# ExceptionCollector.appendException(
|
||||
# UnknownFieldError(what='SubstitutionMappings',
|
||||
# field=name))
|
||||
"""validate the outputs of substitution mappings.
|
||||
|
||||
The outputs defined by the topology template have to match the
|
||||
attributes of the node type or the substituted node template,
|
||||
and the observable attributes of the substituted node template
|
||||
have to be defined as attributes of the node type or outputs in
|
||||
the topology template.
|
||||
"""
|
||||
|
||||
# The outputs defined by the topology template have to match the
|
||||
# attributes of the node type according to the specification, but
|
||||
# it's reasonable that there are more inputs than the node type
|
||||
# has properties, the specification will be amended?
|
||||
for output in self.outputs:
|
||||
if output.name not in self.node_definition.get_attributes_def():
|
||||
ExceptionCollector.appendException(
|
||||
UnknownOutputError(
|
||||
where=_('SubstitutionMappings with node_type ')
|
||||
+ self.node_type,
|
||||
output_name=output.name))
|
||||
|
@ -75,15 +75,6 @@ topology_template:
|
||||
distribution: Ubuntu
|
||||
version: 14.04
|
||||
|
||||
outputs:
|
||||
receiver_ip:
|
||||
description: private IP address of the database application
|
||||
value: { get_attribute: [ server, private_address ] }
|
||||
# It seems current _process_intrisic_function can not handle more than 2 arguments, save it for later
|
||||
# receiver_port:
|
||||
# description: Port of the message receiver endpoint
|
||||
# value: { get_attribute: [ app, data_endpoint, port_name ] }
|
||||
|
||||
groups:
|
||||
dbserver_group:
|
||||
members: [ dbms, server ]
|
||||
|
@ -61,13 +61,13 @@ topology_template:
|
||||
version: 14.04
|
||||
|
||||
outputs:
|
||||
receiver_ip:
|
||||
description: private IP address of the message receiver application
|
||||
value: { get_attribute: [ server, private_address ] }
|
||||
# It seems current _process_intrisic_function can not handle more than 2 arguments, save it for later
|
||||
# receiver_port:
|
||||
# description: Port of the message receiver endpoint
|
||||
# value: { get_attribute: [ app, data_endpoint, port_name ] }
|
||||
server_ip:
|
||||
description: server_ip of the message receiver application
|
||||
value: { get_input: server_ip }
|
||||
|
||||
server_port:
|
||||
description: server_port of the message receiver application
|
||||
value: { get_input: server_port }
|
||||
|
||||
groups:
|
||||
tran_server_group:
|
||||
|
@ -21,8 +21,6 @@ topology_template:
|
||||
node_templates:
|
||||
mq:
|
||||
type: example.QueuingSubsystem
|
||||
# properties:
|
||||
# to be updated when substitution_mapping is validated later
|
||||
properties:
|
||||
server_ip: { get_input: mq_server_ip }
|
||||
server_port: { get_input: mq_server_port }
|
||||
@ -36,9 +34,7 @@ topology_template:
|
||||
trans1:
|
||||
type: example.TransactionSubsystem
|
||||
properties:
|
||||
# mq_server_ip: 127.0.0.1
|
||||
mq_server_ip: { get_attribute: [ mq, server_ip ] }
|
||||
# receiver_port: 8080
|
||||
receiver_port: { get_attribute: [ mq, server_port ] }
|
||||
# capabilities:
|
||||
# message_receiver:
|
||||
@ -49,9 +45,7 @@ topology_template:
|
||||
trans2:
|
||||
type: example.TransactionSubsystem
|
||||
properties:
|
||||
# mq_server_ip: 127.0.0.1
|
||||
mq_server_ip: { get_attribute: [ mq, server_ip ] }
|
||||
# receiver_port: 8080
|
||||
receiver_port: { get_attribute: [ mq, server_port ] }
|
||||
# capabilities:
|
||||
# message_receiver:
|
||||
|
@ -77,10 +77,10 @@ topology_template:
|
||||
receiver_ip:
|
||||
description: private IP address of the message receiver application
|
||||
value: { get_attribute: [ server, private_address ] }
|
||||
# It seems current _process_intrisic_function can not handle more than 2 arguments, save it for later
|
||||
# receiver_port:
|
||||
# description: Port of the message receiver endpoint
|
||||
# value: { get_attribute: [ app, data_endpoint, port_name ] }
|
||||
|
||||
receiver_port:
|
||||
description: receiver_port of the message receiver application
|
||||
value: { get_input: receiver_port }
|
||||
|
||||
groups:
|
||||
webserver_group:
|
||||
|
70
toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml
Normal file
70
toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
tosca_definitions_version: tosca_simple_yaml_1_0
|
||||
|
||||
description: >
|
||||
Template showing an example TOSCA type to demonstrate usage
|
||||
of output in the substitution mappings.
|
||||
|
||||
node_types:
|
||||
example.app:
|
||||
derived_from: tosca.nodes.WebApplication
|
||||
properties:
|
||||
mq_server_ip:
|
||||
type: string
|
||||
required: False
|
||||
receiver_port:
|
||||
type: integer
|
||||
required: False
|
||||
attributes:
|
||||
receiver_ip:
|
||||
type: string
|
||||
receiver_port:
|
||||
type: integer
|
||||
|
||||
topology_template:
|
||||
inputs:
|
||||
mq_server_ip:
|
||||
type: string
|
||||
description: IP address of the message queuing server to receive messages from.
|
||||
default: 127.0.0.1
|
||||
receiver_port:
|
||||
type: integer
|
||||
description: Port to be used for receiving messages.
|
||||
default: 8080
|
||||
my_cpus:
|
||||
type: integer
|
||||
description: Number of CPUs for the server.
|
||||
default: 2
|
||||
constraints:
|
||||
- valid_values: [ 1, 2, 4, 8 ]
|
||||
|
||||
substitution_mappings:
|
||||
node_type: example.app
|
||||
|
||||
node_templates:
|
||||
app:
|
||||
type: example.app
|
||||
properties:
|
||||
mq_server_ip: { get_input: mq_server_ip }
|
||||
receiver_port: { get_input: receiver_port }
|
||||
requirements:
|
||||
- host:
|
||||
node: websrv
|
||||
websrv:
|
||||
type: tosca.nodes.WebServer
|
||||
requirements:
|
||||
- host:
|
||||
node: server
|
||||
server:
|
||||
type: tosca.nodes.Compute
|
||||
capabilities:
|
||||
host:
|
||||
properties:
|
||||
disk_size: 10 GB
|
||||
num_cpus: { get_input: my_cpus }
|
||||
mem_size: 4096 MB
|
||||
os:
|
||||
properties:
|
||||
architecture: x86_64
|
||||
type: Linux
|
||||
distribution: Ubuntu
|
||||
version: 14.04
|
31
toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml
Normal file
31
toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml
Normal file
@ -0,0 +1,31 @@
|
||||
tosca_definitions_version: tosca_simple_yaml_1_0
|
||||
|
||||
imports:
|
||||
- test_example_app_substitution_mappings.yaml
|
||||
|
||||
topology_template:
|
||||
description: >
|
||||
Test template showing valid output section containing attribute defined
|
||||
in the substitution mappings in the imported yaml file.
|
||||
|
||||
inputs:
|
||||
mq_server_ip:
|
||||
type: string
|
||||
default: 127.0.0.1
|
||||
description: IP address of the message queuing server to receive messages from.
|
||||
mq_server_port:
|
||||
type: integer
|
||||
default: 8080
|
||||
description: Port to be used for receiving messages.
|
||||
|
||||
node_templates:
|
||||
substitute_app:
|
||||
type: example.app
|
||||
properties:
|
||||
mq_server_ip: { get_input: mq_server_ip }
|
||||
receiver_port: { get_input: mq_server_port }
|
||||
|
||||
outputs:
|
||||
receiver_ip:
|
||||
description: private IP address of the message receiver application
|
||||
value: { get_attribute: [ substitute_app, my_cpu_output ] }
|
31
toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml
Normal file
31
toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml
Normal file
@ -0,0 +1,31 @@
|
||||
tosca_definitions_version: tosca_simple_yaml_1_0
|
||||
|
||||
imports:
|
||||
- test_example_app_substitution_mappings.yaml
|
||||
|
||||
topology_template:
|
||||
description: >
|
||||
Test template showing valid output section containing attribute defined
|
||||
in the substitution mappings in the imported yaml file.
|
||||
|
||||
inputs:
|
||||
mq_server_ip:
|
||||
type: string
|
||||
default: 127.0.0.1
|
||||
description: IP address of the message queuing server to receive messages from.
|
||||
mq_server_port:
|
||||
type: integer
|
||||
default: 8080
|
||||
description: Port to be used for receiving messages.
|
||||
|
||||
node_templates:
|
||||
sustitute_app:
|
||||
type: example.app
|
||||
properties:
|
||||
mq_server_ip: { get_input: mq_server_ip }
|
||||
receiver_port: { get_input: mq_server_port }
|
||||
|
||||
outputs:
|
||||
receiver_ip:
|
||||
description: private IP address of the message receiver application
|
||||
value: { get_attribute: [ sustitute_app, receiver_ip ] }
|
@ -154,7 +154,7 @@ class TopologyTemplateTest(TestCase):
|
||||
|
||||
def test_outputs(self):
|
||||
self.assertEqual(
|
||||
['receiver_ip'],
|
||||
sorted(['receiver_ip', 'receiver_port']),
|
||||
sorted([output.name for output in self.topo.outputs]))
|
||||
|
||||
def test_groups(self):
|
||||
@ -262,3 +262,22 @@ class TopologyTemplateTest(TestCase):
|
||||
lambda: ToscaTemplate(tpl_path1))
|
||||
exception.ExceptionCollector.assertExceptionMessage(
|
||||
exception.MissingRequiredInputError, errormsg)
|
||||
|
||||
def test_substitution_mappings_valid_output(self):
|
||||
tpl_path = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"data/topology_template/validate/"
|
||||
"test_substitution_mappings_valid_output.yaml")
|
||||
self.assertIsNotNone(ToscaTemplate(tpl_path))
|
||||
|
||||
def test_system_with_unknown_output_validation(self):
|
||||
tpl_path = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"data/topology_template/validate/"
|
||||
"test_substitution_mappings_invalid_output.yaml")
|
||||
errormsg = _('\'Attribute "my_cpu_output" was not found in node '
|
||||
'template "substitute_app".\'')
|
||||
self.assertRaises(exception.ValidationError,
|
||||
lambda: ToscaTemplate(tpl_path))
|
||||
exception.ExceptionCollector.assertExceptionMessage(
|
||||
KeyError, errormsg)
|
||||
|
Loading…
x
Reference in New Issue
Block a user