Validation of imported templates

Validated First level sections of imported templates,First level
sub-sections of node_types and policy_types
and added testcases for the same

Change-Id: I51f4e2496fea567fb0e5672f77899334c7556909
Partially Implements: #1516177
This commit is contained in:
madhavi
2016-01-05 15:31:48 +05:30
parent 4cbb3e331d
commit 8e2c7bde62
10 changed files with 225 additions and 11 deletions

View File

@@ -12,6 +12,8 @@
import logging
import os
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import ValidationError
from toscaparser.extensions.exttools import ExtTools
import toscaparser.utils.yamlparser
@@ -82,7 +84,7 @@ class EntityType(object):
value = None
if defs is None:
if not hasattr(self, 'defs'):
return
return None
defs = self.defs
if ndtype in defs:
value = defs[ndtype]
@@ -111,8 +113,13 @@ class EntityType(object):
def get_definition(self, ndtype):
value = None
if not hasattr(self, 'defs'):
defs = None
ExceptionCollector.appendException(
ValidationError(message="defs is " + str(defs)))
else:
defs = self.defs
if ndtype in defs:
if defs is not None and ndtype in defs:
value = defs[ndtype]
p = self.parent_type
if p:

View File

@@ -10,6 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import UnknownFieldError
from toscaparser.common.exception import ValidationError
from toscaparser.elements.capabilitytype import CapabilityTypeDef
import toscaparser.elements.interfaces as ifaces
from toscaparser.elements.interfaces import InterfacesDef
@@ -19,16 +22,22 @@ from toscaparser.elements.statefulentitytype import StatefulEntityType
class NodeType(StatefulEntityType):
'''TOSCA built-in node type.'''
SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, ATTRIBUTES, REQUIREMENTS, CAPABILITIES, INTERFACES, ARTIFACTS) = \
('derived_from', 'metadata', 'properties', 'version',
'description', 'attributes', 'requirements', 'capabilities',
'interfaces', 'artifacts')
def __init__(self, ntype, custom_def=None):
super(NodeType, self).__init__(ntype, self.NODE_PREFIX, custom_def)
self.ntype = ntype
self.custom_def = custom_def
self._validate_keys()
@property
def parent_type(self):
'''Return a node this node is derived from.'''
if not hasattr(self, 'defs'):
return
return None
pnode = self.derived_from(self.defs)
if pnode:
return NodeType(pnode, self.custom_def)
@@ -153,6 +162,11 @@ class NodeType(StatefulEntityType):
parent_node = self.parent_type
if requires is None:
requires = self.get_value(self.REQUIREMENTS, None, True)
if parent_node is None:
ExceptionCollector.appendException(
ValidationError(message="parent_node is "
+ str(parent_node)))
else:
parent_node = parent_node.parent_type
if parent_node:
while parent_node.type != 'tosca.nodes.Root':
@@ -200,3 +214,11 @@ class NodeType(StatefulEntityType):
captype = self.get_capability(name)
if captype and name in captype.keys():
return captype[name].value
def _validate_keys(self):
if self.defs:
for key in self.defs.keys():
if key not in self.SECTIONS:
ExceptionCollector.appendException(
UnknownFieldError(what='Nodetype"%s"' % self.ntype,
field=key))

View File

@@ -89,7 +89,7 @@ class PolicyType(StatefulEntityType):
for key in self.defs.keys():
if key not in self.SECTIONS:
ExceptionCollector.appendException(
UnknownFieldError(what='Policy "%s"' % self.name,
UnknownFieldError(what='Policy "%s"' % self.type,
field=key))
def _validate_targets(self, targets_list, custom_def):

View File

@@ -39,6 +39,7 @@ class StatefulEntityType(EntityType):
elif custom_def and entitytype in list(custom_def.keys()):
self.defs = custom_def[entitytype]
else:
self.defs = None
ExceptionCollector.appendException(
InvalidTypeError(what=entitytype))
self.type = entitytype

View File

@@ -0,0 +1,59 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import InvalidTemplateVersion
from toscaparser.common.exception import UnknownFieldError
from toscaparser.extensions.exttools import ExtTools
class TypeValidation(object):
ALLOWED_TYPE_SECTIONS = (DEFINITION_VERSION, DESCRIPTION, IMPORTS,
DSL_DEFINITIONS, NODE_TYPES, REPOSITORIES,
DATA_TYPES, ARTIFACT_TYPES, GROUP_TYPES,
RELATIONSHIP_TYPES, CAPABILITY_TYPES,
INTERFCAE_TYPES, POLICY_TYPES, DATATYPE_DEFINITIONS) = \
('tosca_definitions_version', 'description',
'imports', 'dsl_definitions', 'node_types',
'repositories', 'data_types', 'group_types',
'artifact_types', 'relationship_types',
'capability_types', 'interface_types',
'policy_types', 'datatype_definitions')
VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0']
exttools = ExtTools()
VALID_TEMPLATE_VERSIONS.extend(exttools.get_versions())
def __init__(self, custom_types, import_def):
self.import_def = import_def
self._validate_type_keys(custom_types)
def _validate_type_keys(self, custom_type):
version = custom_type[self.DEFINITION_VERSION] \
if self.DEFINITION_VERSION in custom_type \
else None
if version:
self._validate_type_version(version)
self.version = version
for name in custom_type:
if name not in self.ALLOWED_TYPE_SECTIONS:
ExceptionCollector.appendException(
UnknownFieldError(what='Template ' + (self.import_def),
field=name))
def _validate_type_version(self, version):
if version not in self.VALID_TEMPLATE_VERSIONS:
ExceptionCollector.appendException(
InvalidTemplateVersion(
what=version + ' in ' + self.import_def,
valid_versions=', '. join(self.VALID_TEMPLATE_VERSIONS)))

View File

@@ -17,6 +17,7 @@ from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import MissingRequiredFieldError
from toscaparser.common.exception import UnknownFieldError
from toscaparser.common.exception import ValidationError
from toscaparser.elements.tosca_type_validation import TypeValidation
from toscaparser.utils.gettextutils import _
import toscaparser.utils.urlutils
import toscaparser.utils.yamlparser
@@ -79,11 +80,14 @@ class ImportsLoader(object):
namespace_prefix = import_uri.get(
self.NAMESPACE_PREFIX)
if custom_type:
TypeValidation(custom_type, import_def)
self._update_custom_def(custom_type, namespace_prefix)
else: # old style of imports
custom_type = self._load_import_template(None,
import_def)
if custom_type:
TypeValidation(
custom_type, import_def)
self._update_custom_def(custom_type, None)
def _update_custom_def(self, custom_type, namespace_prefix):

View File

@@ -18,6 +18,7 @@ from toscaparser.common.exception import InvalidPropertyValueError
from toscaparser.common.exception import MissingRequiredFieldError
from toscaparser.common.exception import TypeMismatchError
from toscaparser.common.exception import UnknownFieldError
from toscaparser.common.exception import ValidationError
from toscaparser.dataentity import DataEntity
from toscaparser.elements.interfaces import CONFIGURE
from toscaparser.elements.interfaces import CONFIGURE_SHORTNAME
@@ -93,6 +94,11 @@ class NodeTemplate(EntityTemplate):
# check if it's type has relationship defined
if not relationship:
parent_reqs = self.type_definition.get_all_requirements()
if parent_reqs is None:
ExceptionCollector.appendException(
ValidationError(message='parent_req is ' +
str(parent_reqs)))
else:
for key in req.keys():
for req_dict in parent_reqs:
if key in req_dict.keys():

View File

@@ -0,0 +1,34 @@
tosca1_definitions_version: tosca_simple_yaml_1_0
tosca_definitions_version: tosca_simple_yaml_1_10
descriptions: >
Pizza store app that allows you to explore the features provided by PayPal's REST APIs.
More detail can be found at https://github.com/paypal/rest-api-sample-app-nodejs/
node_typess:
node_types:
tosca.nodes.SoftwareComponent.Logstash:
derived_from: tosca.nodes.SoftwareComponent
requirements:
- search_endpoint:
capability: tosca.capabilities.Endpoint
node: tosca.nodes.SoftwareComponent.Elasticsearch
relationship:
type: tosca.relationships.ConnectsTo
interfaces:
Configure:
pre_configure_source:
inputs:
elasticsearch_ip:
type: string
capabilities1:
log_endpoint:
type: tosca.capabilities.Endpoint
policy_types1:
policy_types:
mycompany.mytypes.myScalingPolicy:
derived1_from: tosca.policies.Scaling
metadata:
type: map
entry_schema:
type: string

View File

@@ -0,0 +1,39 @@
tosca_definitions_version: tosca_simple_yaml_1_0
description: Template to test invalid imports.
imports:
- custom_types/imported_sample.yaml
topology_template:
node_templates:
logstash:
type: tosca.nodes.SoftwareComponent.Logstash
requirements:
- search_endpoint:
capability: search_endpoint
relationship:
type: tosca.relationships.ConnectsTo
interfaces:
Configure:
pre_configure_source:
implementation: logstash/configure_elasticsearch.py
inputs:
elasticsearch_ip: { get_attribute: [elasticsearch_server, private_address] }
interfaces:
Standard:
create: logstash/create.sh
start: logstash/start.sh
policies:
- my_compute_placement_policy:
type: tosca.policies.Placement
description: Apply placement policy to servers
metadata: { user1: 1001, user2: 1002 }
targets: [ my_server_1, my_server_2 ]
- my_groups_placement:
type: mycompany.mytypes.myScalingPolicy
targets: [ webserver_group ]
description: my company scaling policy
metadata:
user1: 1001
user2: 1003

View File

@@ -54,6 +54,48 @@ class ToscaTemplateValidationTest(TestCase):
_('Template contains unknown field "node_template". Refer to the '
'definition to verify valid values.'))
def test_template_with_imports_validation(self):
tpl_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"data/tosca_imports_validation.yaml")
self.assertRaises(exception.ValidationError, ToscaTemplate, tpl_path)
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError,
_('Template custom_types/imported_sample.yaml contains unknown '
'field "descriptions". Refer to the definition'
' to verify valid values.'))
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError,
_('Template custom_types/imported_sample.yaml contains unknown '
'field "node_typess". Refer to the definition to '
'verify valid values.'))
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError,
_('Template custom_types/imported_sample.yaml contains unknown '
'field "tosca1_definitions_version". Refer to the definition'
' to verify valid values.'))
exception.ExceptionCollector.assertExceptionMessage(
exception.InvalidTemplateVersion,
_('The template version "tosca_simple_yaml_1_10 in '
'custom_types/imported_sample.yaml" is invalid. '
'Valid versions are "tosca_simple_yaml_1_0, '
'tosca_simple_profile_for_nfv_1_0_0".'))
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError,
_('Template custom_types/imported_sample.yaml contains unknown '
'field "policy_types1". Refer to the definition to '
'verify valid values.'))
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError,
_('Nodetype"tosca.nodes.SoftwareComponent.Logstash" contains '
'unknown field "capabilities1". Refer to the definition '
'to verify valid values.'))
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError,
_('Policy "mycompany.mytypes.myScalingPolicy" contains unknown '
'field "derived1_from". Refer to the definition to '
'verify valid values.'))
def test_inputs(self):
tpl_snippet = '''
inputs: