TOSCA parser
Parse the TOSCA template as per the specification defined in TOSCA Simple Profile in YAML v1.0 working draft 1. Partially Implements: blueprint heat-translator-tosca Change-Id: I9d71a28b7b48b7591a55c2b0947ce63beb335bbf
This commit is contained in:
		| @@ -166,6 +166,34 @@ tosca.nodes.WebApplication: | ||||
|   requirements: | ||||
|     - host: tosca.nodes.WebServer | ||||
|  | ||||
| tosca.nodes.WebApplication.WordPress: | ||||
|   derived_from: tosca.nodes.WebApplication | ||||
|   properties: | ||||
|     admin_user: | ||||
|       required: no | ||||
|       type: string | ||||
|     admin_password: | ||||
|       required: no | ||||
|       type: string | ||||
|     db_host: | ||||
|       required: no | ||||
|       type: string | ||||
|   requirements: | ||||
|     - database_endpoint: tosca.nodes.Database | ||||
|   interfaces: | ||||
|     tosca.interfaces.node.Lifecycle: | ||||
|       inputs: | ||||
|         db_host: | ||||
|           type: string | ||||
|         db_port: | ||||
|           type: integer | ||||
|         db_name: | ||||
|           type: string | ||||
|         db_user: | ||||
|           type: string | ||||
|         db_password: | ||||
|           type: string | ||||
|  | ||||
| ########################################################################## | ||||
| # Relationship Type. | ||||
| # A Relationship Type is a reusable entity that defines the type of one | ||||
|   | ||||
| @@ -28,7 +28,9 @@ class EntityType(object): | ||||
|         os.path.dirname(os.path.abspath(__file__)), | ||||
|         "TOSCA_definition.yaml") | ||||
|  | ||||
|     TOSCA_DEF = translator.toscalib.utils.yamlparser.load_yaml(TOSCA_DEF_FILE) | ||||
|     loader = translator.toscalib.utils.yamlparser.load_yaml | ||||
|  | ||||
|     TOSCA_DEF = loader(TOSCA_DEF_FILE) | ||||
|  | ||||
|     RELATIONSHIP_TYPE = (DEPENDSON, HOSTEDON, CONNECTSTO) = \ | ||||
|                         ('tosca.relationships.DependsOn', | ||||
|   | ||||
| @@ -67,13 +67,20 @@ class NodeType(StatefulEntityType): | ||||
|         ''' | ||||
|         relationship = {} | ||||
|         requires = self.requirements | ||||
|         parent_node = self.parent_type | ||||
|         if requires is None: | ||||
|             requires = self._get_value(REQUIREMENTS, None, True) | ||||
|             parent_node = parent_node.parent_type | ||||
|         if parent_node: | ||||
|             while parent_node.type != 'tosca.nodes.Root': | ||||
|                 req = parent_node._get_value(REQUIREMENTS, None, True) | ||||
|                 requires.extend(req) | ||||
|                 parent_node = parent_node.parent_type | ||||
|         if requires: | ||||
|             for req in requires: | ||||
|                 for key, value in req.items(): | ||||
|                     relation = self._get_relation(key, value) | ||||
|                     rtype = RelationshipType(relation) | ||||
|                     rtype = RelationshipType(relation, key) | ||||
|                     relatednode = NodeType(value) | ||||
|                     relationship[rtype] = relatednode | ||||
|         return relationship | ||||
| @@ -156,11 +163,12 @@ class NodeType(StatefulEntityType): | ||||
|             if key == type: | ||||
|                 return value | ||||
|  | ||||
|     def _get_value(self, key, defs=None, parent=None): | ||||
|     def _get_value(self, ndtype, defs=None, parent=None): | ||||
|         value = None | ||||
|         if defs is None: | ||||
|             defs = self.defs | ||||
|         value = self.entity_value(defs, key) | ||||
|         if ndtype in defs: | ||||
|             value = defs[ndtype] | ||||
|         if parent and not value: | ||||
|             p = self.parent_type | ||||
|             while value is None: | ||||
| @@ -169,6 +177,6 @@ class NodeType(StatefulEntityType): | ||||
|                     break | ||||
|                 if p and p.type == 'tosca.nodes.Root': | ||||
|                     break | ||||
|                 value = self.entity_value(defs, key) | ||||
|                 value = p._get_value(ndtype) | ||||
|                 p = p.parent_type | ||||
|         return value | ||||
|   | ||||
| @@ -51,9 +51,15 @@ class PropertyDef(object): | ||||
|  | ||||
|     @property | ||||
|     def constraints(self): | ||||
|         if self.schema: | ||||
|         try: | ||||
|             if self.CONSTRAINTS in self.schema: | ||||
|                 return self.schema[self.CONSTRAINTS] | ||||
|         except Exception: | ||||
|             #Simply passing the exception to ignore Node Type in-line value. | ||||
|             #Exception will not be needed when Node Type and Node Template | ||||
|             #properties are separated. | ||||
|             #TODO(spzala) | ||||
|             pass | ||||
|  | ||||
|     @property | ||||
|     def description(self): | ||||
| @@ -69,16 +75,19 @@ class PropertyDef(object): | ||||
|             self._validate_datatype() | ||||
|  | ||||
|     def _validate_datatype(self): | ||||
|         if self.schema: | ||||
|             dtype = self.schema[self.TYPE] | ||||
|             if dtype == self.STRING: | ||||
|                 return Constraint.validate_string(self.value) | ||||
|             elif dtype == self.INTEGER: | ||||
|                 return Constraint.validate_integer(self.value) | ||||
|             elif dtype == self.NUMBER: | ||||
|                 return Constraint.validate_number(self.value) | ||||
|             elif dtype == self.LIST: | ||||
|                 return Constraint.validate_list(self.value) | ||||
|         try: | ||||
|             if self.TYPE in self.schema: | ||||
|                 dtype = self.schema[self.TYPE] | ||||
|                 if dtype == self.STRING: | ||||
|                     return Constraint.validate_string(self.value) | ||||
|                 elif dtype == self.INTEGER: | ||||
|                     return Constraint.validate_integer(self.value) | ||||
|                 elif dtype == self.NUMBER: | ||||
|                     return Constraint.validate_number(self.value) | ||||
|                 elif dtype == self.LIST: | ||||
|                     return Constraint.validate_list(self.value) | ||||
|         except Exception: | ||||
|             pass | ||||
|  | ||||
|     def _validate_constraints(self): | ||||
|         constraints = self.constraints | ||||
|   | ||||
| @@ -19,10 +19,11 @@ from translator.toscalib.elements.statefulentitytype import StatefulEntityType | ||||
| class RelationshipType(StatefulEntityType): | ||||
|     '''TOSCA built-in relationship type.''' | ||||
|  | ||||
|     def __init__(self, type): | ||||
|     def __init__(self, type, capability_name): | ||||
|         super(RelationshipType, self).__init__() | ||||
|         self.defs = self.TOSCA_DEF[type] | ||||
|         self.type = type | ||||
|         self.capability_name = capability_name | ||||
|  | ||||
|     @property | ||||
|     def valid_targets(self): | ||||
|   | ||||
							
								
								
									
										154
									
								
								translator/toscalib/nodetemplate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								translator/toscalib/nodetemplate.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| # vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||||
|  | ||||
| # | ||||
| #    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. | ||||
|  | ||||
|  | ||||
| import logging | ||||
|  | ||||
| from translator.toscalib.elements.capabilitytype import CapabilityTypeDef | ||||
| from translator.toscalib.elements.interfaces import InterfacesDef | ||||
| from translator.toscalib.elements.nodetype import NodeType | ||||
| from translator.toscalib.elements.properties import PropertyDef | ||||
| from translator.toscalib.utils.gettextutils import _ | ||||
|  | ||||
| SECTIONS = (DERIVED_FROM, PROPERTIES, REQUIREMENTS, | ||||
|             INTERFACES, CAPABILITIES) = \ | ||||
|            ('derived_from', 'properties', 'requirements', 'interfaces', | ||||
|             'capabilities') | ||||
|  | ||||
| log = logging.getLogger('tosca') | ||||
|  | ||||
|  | ||||
| class NodeTemplate(NodeType): | ||||
|     '''Node template from a Tosca profile.''' | ||||
|     def __init__(self, name, nodetemplates): | ||||
|         super(NodeTemplate, self).__init__(nodetemplates[name]['type']) | ||||
|         self.name = name | ||||
|         self.nodetemplates = nodetemplates | ||||
|         self.nodetemplate = nodetemplates[self.name] | ||||
|         self.type = self.nodetemplate['type'] | ||||
|         self.type_properties = self.properties_def | ||||
|         self.type_capabilities = self.capabilities | ||||
|         self.type_lifecycle_ops = self.lifecycle_operations | ||||
|         self.type_relationship = self.relationship | ||||
|         self.related = {} | ||||
|  | ||||
|     @property | ||||
|     def tpl_requirements(self): | ||||
|         return self._get_value(REQUIREMENTS, self.nodetemplate) | ||||
|  | ||||
|     @property | ||||
|     def tpl_relationship(self): | ||||
|         tpl_relation = {} | ||||
|         requires = self.tpl_requirements | ||||
|         if requires: | ||||
|             for r in requires: | ||||
|                 for cap, node in r.items(): | ||||
|                     for relationship_type in self.type_relationship.keys(): | ||||
|                         if cap == relationship_type.capability_name: | ||||
|                             rtpl = NodeTemplate(node, self.nodetemplates) | ||||
|                             tpl_relation[relationship_type] = rtpl | ||||
|         return tpl_relation | ||||
|  | ||||
|     @property | ||||
|     def tpl_capabilities(self): | ||||
|         tpl_cap = [] | ||||
|         properties = {} | ||||
|         cap_type = None | ||||
|         caps = self._get_value(CAPABILITIES, self.nodetemplate) | ||||
|         if caps: | ||||
|             for name, value in caps.items(): | ||||
|                 for prop, val in value.items(): | ||||
|                     properties = val | ||||
|                 for c in self.type_capabilities: | ||||
|                     if c.name == name: | ||||
|                         cap_type = c.type | ||||
|                 cap = CapabilityTypeDef(name, cap_type, | ||||
|                                         self.name, properties) | ||||
|                 tpl_cap.append(cap) | ||||
|         return tpl_cap | ||||
|  | ||||
|     @property | ||||
|     def tpl_interfaces(self): | ||||
|         tpl_ifaces = [] | ||||
|         ifaces = self._get_value(INTERFACES, self.nodetemplate) | ||||
|         if ifaces: | ||||
|             for i in ifaces: | ||||
|                 for name, value in ifaces.items(): | ||||
|                     for ops, val in value.items(): | ||||
|                         iface = InterfacesDef(None, name, self.name, | ||||
|                                               ops, val) | ||||
|                         tpl_ifaces.append(iface) | ||||
|         return tpl_ifaces | ||||
|  | ||||
|     @property | ||||
|     def properties(self): | ||||
|         tpl_props = [] | ||||
|         properties = self._get_value(PROPERTIES, self.nodetemplate) | ||||
|         requiredprop = [] | ||||
|         for p in self.type_properties: | ||||
|             if p.required: | ||||
|                 requiredprop.append(p.name) | ||||
|         if properties: | ||||
|             #make sure it's not missing any property required by a node type | ||||
|             missingprop = [] | ||||
|             for r in requiredprop: | ||||
|                 if r not in properties.keys(): | ||||
|                     missingprop.append(r) | ||||
|             if missingprop: | ||||
|                 raise ValueError(_("Node template %(tpl)s is missing " | ||||
|                                    "one or more required properties %(prop)s") | ||||
|                                  % {'tpl': self.name, 'prop': missingprop}) | ||||
|             for name, value in properties.items(): | ||||
|                 prop = PropertyDef(name, self.type, value, self.name) | ||||
|                 tpl_props.append(prop) | ||||
|         else: | ||||
|             if requiredprop: | ||||
|                 raise ValueError(_("Node template %(tpl)s is missing" | ||||
|                                    "one or more required properties %(prop)s") | ||||
|                                  % {'tpl': self.name, 'prop': requiredprop}) | ||||
|         return tpl_props | ||||
|  | ||||
|     def _add_next(self, nodetpl, relationship): | ||||
|         self.related[nodetpl] = relationship | ||||
|  | ||||
|     @property | ||||
|     def related_nodes(self): | ||||
|         if not self.related: | ||||
|             for relation, node in self.tpl_relationship.items(): | ||||
|                 for tpl in self.nodetemplates: | ||||
|                     if tpl == node.type: | ||||
|                         self.related[NodeTemplate(tpl)] = relation | ||||
|         return self.related.keys() | ||||
|  | ||||
|     def ref_property(self, cap, cap_name, property): | ||||
|         requires = self.tpl_requirements | ||||
|         tpl_name = None | ||||
|         if requires: | ||||
|             for r in requires: | ||||
|                 for cap, node in r.items(): | ||||
|                     if cap == cap: | ||||
|                         tpl_name = node | ||||
|                         break | ||||
|             if tpl_name: | ||||
|                 tpl = NodeTemplate(tpl_name, self.nodetemplates) | ||||
|                 caps = tpl.tpl_capabilities | ||||
|                 for c in caps: | ||||
|                     if c.name == cap_name: | ||||
|                         if c.property == property: | ||||
|                             return c.property_value | ||||
|  | ||||
|     def validate(self): | ||||
|         for prop in self.properties: | ||||
|             prop.validate() | ||||
							
								
								
									
										76
									
								
								translator/toscalib/parameters.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								translator/toscalib/parameters.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| # vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||||
|  | ||||
| # | ||||
| #    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. | ||||
|  | ||||
|  | ||||
| import logging | ||||
|  | ||||
| from translator.toscalib.elements.constraints import Constraint | ||||
| from translator.toscalib.elements.properties import PropertyDef | ||||
|  | ||||
| log = logging.getLogger('tosca') | ||||
|  | ||||
|  | ||||
| class Input(object): | ||||
|     def __init__(self, name, schema): | ||||
|         self.name = name | ||||
|         self.schema = schema | ||||
|  | ||||
|     @property | ||||
|     def type(self): | ||||
|         return self.schema['type'] | ||||
|  | ||||
|     @property | ||||
|     def description(self): | ||||
|         if PropertyDef.DESCRIPTION in self.schema: | ||||
|             return self.schema['description'] | ||||
|  | ||||
|     @property | ||||
|     def default(self): | ||||
|         if self.PropertyDef.DEFAULT in self.schema: | ||||
|             return self.schema['default'] | ||||
|  | ||||
|     @property | ||||
|     def constraints(self): | ||||
|         if PropertyDef.CONSTRAINTS in self.schema: | ||||
|             return self.schema['constraints'] | ||||
|  | ||||
|     def validate(self): | ||||
|         self.validate_type(self.type) | ||||
|         if self.constraints: | ||||
|             self.validate_constraints(self.constraints) | ||||
|  | ||||
|     def validate_type(self, input_type): | ||||
|         if input_type not in PropertyDef.PROPERTIY_TYPES: | ||||
|             raise ValueError(_('Invalid type %s') % type) | ||||
|  | ||||
|     def validate_constraints(self, constraints): | ||||
|         for constraint in constraints: | ||||
|             for key in constraint.keys(): | ||||
|                 if key not in Constraint.CONSTRAINTS: | ||||
|                     raise ValueError(_('Invalid constraint %s') % constraint) | ||||
|  | ||||
|  | ||||
| class Output(object): | ||||
|     def __init__(self, name, attrs): | ||||
|         self.name = name | ||||
|         self.attrs = attrs | ||||
|  | ||||
|     @property | ||||
|     def description(self): | ||||
|         return self.attrs['description'] | ||||
|  | ||||
|     @property | ||||
|     def value(self): | ||||
|         return self.attrs['value'] | ||||
| @@ -0,0 +1,102 @@ | ||||
| tosca_definitions_version: tosca_simple_1.0 | ||||
|  | ||||
| description: > | ||||
|   TOSCA simple profile with wordpress, web server and mysql on the same server. | ||||
|  | ||||
| inputs: | ||||
|   cpus: | ||||
|     type: integer | ||||
|     description: Number of CPUs for the server. | ||||
|     constraints: | ||||
|       - valid_values: [ 1, 2, 4, 8 ] | ||||
|   db_name: | ||||
|     type: string | ||||
|     description: The name of the database. | ||||
|   db_user: | ||||
|     type: string | ||||
|     description: The user name of the DB user. | ||||
|   db_pwd: | ||||
|     type: string | ||||
|     description: The WordPress database admin account password. | ||||
|   db_root_pwd: | ||||
|     type: string | ||||
|     description: Root password for MySQL. | ||||
|   db_port: | ||||
|     type: integer | ||||
|     description: Port for the MySQL database. | ||||
|  | ||||
| node_templates: | ||||
|   wordpress: | ||||
|     type: tosca.nodes.WebApplication.WordPress | ||||
|     requirements: | ||||
|       - host: webserver | ||||
|       - database_endpoint: mysql_database | ||||
|     interfaces: | ||||
|       tosca.interfaces.node.Lifecycle: | ||||
|          create: wordpress_install.sh | ||||
|          configure: | ||||
|            implementation: wordpress_configure.sh | ||||
|            input: | ||||
|              wp_db_name: { get_property: [ mysql_database, db_name ] } | ||||
|              wp_db_user: { get_property: [ mysql_database, db_user ] } | ||||
|              wp_db_password: { get_property: [ mysql_database, db_password ] } | ||||
|              wp_db_port: { get_ref_property: [ database_endpoint, database_endpoint, port ] } | ||||
|  | ||||
|   mysql_database: | ||||
|     type: tosca.nodes.Database | ||||
|     properties: | ||||
|       db_name: { get_input: db_name } | ||||
|       db_user: { get_input: db_user } | ||||
|       db_password: { get_input: db_pwd } | ||||
|     capabilities: | ||||
|       database_endpoint: | ||||
|         properties: | ||||
|           port: { get_input: db_port } | ||||
|     requirements: | ||||
|       - host: mysql_dbms | ||||
|     interfaces: | ||||
|       tosca.interfaces.node.Lifecycle: | ||||
|          configure: mysql_database_configure.sh | ||||
|  | ||||
|   mysql_dbms: | ||||
|     type: tosca.nodes.DBMS | ||||
|     properties: | ||||
|       dbms_root_password: { get_input: db_root_pwd } | ||||
|       dbms_port: { get_input: db_port } | ||||
|     requirements: | ||||
|       - host: server | ||||
|     interfaces: | ||||
|       tosca.interfaces.node.Lifecycle: | ||||
|         create: mysql_dbms_install.sh | ||||
|         start: mysql_dbms_start.sh | ||||
|         configure: | ||||
|           implementation: mysql_dbms_configure.sh | ||||
|           input: | ||||
|             db_root_password: { get_property: [ mysql_dbms, dbms_root_password ] } | ||||
|  | ||||
|   webserver: | ||||
|     type: tosca.nodes.WebServer | ||||
|     requirements: | ||||
|       - host: server | ||||
|     interfaces: | ||||
|       tosca.interfaces.node.Lifecycle: | ||||
|         create: webserver_install.sh | ||||
|         start: webserver_start.sh | ||||
|  | ||||
|   server: | ||||
|     type: tosca.nodes.Compute | ||||
|     properties: | ||||
|       # compute properties (flavor) | ||||
|       disk_size: 10 | ||||
|       num_cpus: { get_input: cpus } | ||||
|       mem_size: 4096 | ||||
|       # host image properties | ||||
|       os_arch: x86_64 | ||||
|       os_type: Linux | ||||
|       os_distribution: Fedora | ||||
|       os_version: 18 | ||||
|  | ||||
| outputs: | ||||
|   website_url: | ||||
|     description: URL for Wordpress wiki. | ||||
|     value: { get_property: [server, ip_address] } | ||||
| @@ -15,7 +15,6 @@ | ||||
|  | ||||
| from translator.toscalib.elements.nodetype import NodeType | ||||
| from translator.toscalib.tests.base import TestCase | ||||
|  | ||||
| compute_type = NodeType('tosca.nodes.Compute') | ||||
| component_type = NodeType('tosca.nodes.SoftwareComponent') | ||||
|  | ||||
|   | ||||
							
								
								
									
										100
									
								
								translator/toscalib/tests/test_toscatpl.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								translator/toscalib/tests/test_toscatpl.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| # vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||||
|  | ||||
| # | ||||
| #    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. | ||||
|  | ||||
| import os | ||||
| from translator.toscalib.tests.base import TestCase | ||||
| from translator.toscalib.tosca_template import ToscaTemplate | ||||
|  | ||||
|  | ||||
| class ToscaTemplateTest(TestCase): | ||||
|  | ||||
|     '''TOSCA template.''' | ||||
|     tosca_tpl = os.path.join( | ||||
|         os.path.dirname(os.path.abspath(__file__)), | ||||
|         "data/tosca_single_instance_wordpress.yaml") | ||||
|     tosca = ToscaTemplate(tosca_tpl) | ||||
|  | ||||
|     def test_version(self): | ||||
|         self.assertEqual(self.tosca.version, "tosca_simple_1.0") | ||||
|  | ||||
|     def test_description(self): | ||||
|         expected_description = "TOSCA simple profile with wordpress, " \ | ||||
|                                "web server and mysql on the same server." | ||||
|         self.assertEqual(self.tosca.description, expected_description) | ||||
|  | ||||
|     def test_inputs(self): | ||||
|         self.assertEqual( | ||||
|             ['cpus', 'db_name', 'db_port', | ||||
|              'db_pwd', 'db_root_pwd', 'db_user'], | ||||
|             sorted([input.name for input in self.tosca.inputs])) | ||||
|  | ||||
|         input_name = "db_port" | ||||
|         expected_description = "Port for the MySQL database." | ||||
|         for input in self.tosca.inputs: | ||||
|             if input.name == input_name: | ||||
|                 self.assertEqual(input.description, expected_description) | ||||
|  | ||||
|     def test_node_tpls(self): | ||||
|         '''Test nodetemplate names.''' | ||||
|         self.assertEqual( | ||||
|             ['mysql_database', 'mysql_dbms', 'server', | ||||
|              'webserver', 'wordpress'], | ||||
|             sorted([tpl.name for tpl in self.tosca.nodetemplates])) | ||||
|  | ||||
|         tpl_name = "mysql_database" | ||||
|         expected_type = "tosca.nodes.Database" | ||||
|         expected_properties = ['db_name', 'db_password', 'db_user'] | ||||
|         expected_capabilities = ['database_endpoint'] | ||||
|         expected_requirements = [{'host': 'mysql_dbms'}] | ||||
|         expected_relationshp = ['tosca.relationships.HostedOn'] | ||||
|         expected_host = ['mysql_dbms'] | ||||
|         expected_interface = ['tosca.interfaces.node.Lifecycle'] | ||||
|  | ||||
|         for tpl in self.tosca.nodetemplates: | ||||
|             if tpl_name == tpl.name: | ||||
|                 '''Test node type.''' | ||||
|                 self.assertEqual(tpl.type, expected_type) | ||||
|  | ||||
|                 '''Test properties.''' | ||||
|                 self.assertEqual( | ||||
|                     expected_properties, | ||||
|                     sorted([p.name for p in tpl.properties])) | ||||
|  | ||||
|                 '''Test capabilities.''' | ||||
|                 self.assertEqual( | ||||
|                     expected_capabilities, | ||||
|                     sorted([p.name for p in tpl.tpl_capabilities])) | ||||
|  | ||||
|                 '''Test requirements.''' | ||||
|                 self.assertEqual( | ||||
|                     expected_requirements, tpl.tpl_requirements) | ||||
|  | ||||
|                 '''Test relationship.''' | ||||
|                 self.assertEqual( | ||||
|                     expected_relationshp, | ||||
|                     [x.type for x in tpl.tpl_relationship.keys()]) | ||||
|                 self.assertEqual( | ||||
|                     expected_host, | ||||
|                     [y.name for y in tpl.tpl_relationship.values()]) | ||||
|  | ||||
|                 '''Test interfaces.''' | ||||
|                 self.assertEqual( | ||||
|                     expected_interface, | ||||
|                     [x.type for x in tpl.tpl_interfaces]) | ||||
|  | ||||
|     def test_outputs(self): | ||||
|         self.assertEqual( | ||||
|             ['website_url'], | ||||
|             sorted([output.name for output in self.tosca.outputs])) | ||||
							
								
								
									
										83
									
								
								translator/toscalib/tosca_template.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								translator/toscalib/tosca_template.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| # vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||||
|  | ||||
| # | ||||
| #    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. | ||||
|  | ||||
|  | ||||
| import logging | ||||
| from translator.toscalib.nodetemplate import NodeTemplate | ||||
| from translator.toscalib.parameters import Input, Output | ||||
| from translator.toscalib.tpl_relationship_graph import ToscaGraph | ||||
| from translator.toscalib.utils.gettextutils import _ | ||||
| import translator.toscalib.utils.yamlparser | ||||
|  | ||||
|  | ||||
| SECTIONS = (VERSION, DESCRIPTION, INPUTS, | ||||
|             NODE_TEMPLATES, OUTPUTS) = \ | ||||
|            ('tosca_definitions_version', 'description', 'inputs', | ||||
|             'node_templates', 'outputs') | ||||
|  | ||||
| log = logging.getLogger("tosca.model") | ||||
|  | ||||
|  | ||||
| class ToscaTemplate(object): | ||||
|     '''Load the template data.''' | ||||
|     def __init__(self, path): | ||||
|         self.tpl = translator.toscalib.utils.yamlparser.load_yaml(path) | ||||
|         self.version = self._tpl_version() | ||||
|         self.description = self._tpl_description() | ||||
|         self.inputs = self._inputs() | ||||
|         self.nodetemplates = self._nodetemplates() | ||||
|         self.outputs = self._outputs() | ||||
|         self.graph = ToscaGraph(self.nodetemplates) | ||||
|  | ||||
|     def _inputs(self): | ||||
|         inputs = [] | ||||
|         for name, attrs in self._tpl_inputs().items(): | ||||
|             input = Input(name, attrs) | ||||
|             if not isinstance(input.schema, dict): | ||||
|                 raise ValueError(_("The input %(input)s has no attributes.") | ||||
|                                  % {'input': input}) | ||||
|             input.validate() | ||||
|             inputs.append(input) | ||||
|         return inputs | ||||
|  | ||||
|     def _nodetemplates(self): | ||||
|         nodetemplates = [] | ||||
|         tpls = self._tpl_nodetemplates() | ||||
|         for name, value in tpls.items(): | ||||
|             tpl = NodeTemplate(name, tpls) | ||||
|             tpl.validate() | ||||
|             nodetemplates.append(tpl) | ||||
|         return nodetemplates | ||||
|  | ||||
|     def _outputs(self): | ||||
|         outputs = [] | ||||
|         for name, attrs in self._tpl_outputs().items(): | ||||
|             outputs.append(Output(name, attrs)) | ||||
|         return outputs | ||||
|  | ||||
|     def _tpl_version(self): | ||||
|         return self.tpl[VERSION] | ||||
|  | ||||
|     def _tpl_description(self): | ||||
|         return self.tpl[DESCRIPTION].rstrip() | ||||
|  | ||||
|     def _tpl_inputs(self): | ||||
|         return self.tpl[INPUTS] | ||||
|  | ||||
|     def _tpl_nodetemplates(self): | ||||
|         return self.tpl[NODE_TEMPLATES] | ||||
|  | ||||
|     def _tpl_outputs(self): | ||||
|         return self.tpl[OUTPUTS] | ||||
							
								
								
									
										48
									
								
								translator/toscalib/tpl_relationship_graph.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								translator/toscalib/tpl_relationship_graph.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| # vim: tabstop=4 shiftwidth=4 softtabstop=4 | ||||
|  | ||||
| # | ||||
| #    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. | ||||
|  | ||||
|  | ||||
| class ToscaGraph(object): | ||||
|     '''Graph of Tosca Node Templates.''' | ||||
|     def __init__(self, nodetemplates): | ||||
|         self.nodetemplates = nodetemplates | ||||
|         self.vertices = {} | ||||
|         self._create() | ||||
|  | ||||
|     def _create_vertex(self, node): | ||||
|         self.vertices[node.name] = node | ||||
|  | ||||
|     def _create_edge(self, node1, node2, relationship): | ||||
|         if node1 not in self.vertices: | ||||
|             self._create_vertex(node1) | ||||
|         self.vertices[node1.name]._add_next(node2, | ||||
|                                             relationship) | ||||
|  | ||||
|     def vertex(self, node): | ||||
|         if node in self.vertices: | ||||
|             return self.vertices[node] | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return iter(self.vertices.values()) | ||||
|  | ||||
|     def _create(self): | ||||
|         for node in self.nodetemplates: | ||||
|             if node.tpl_relationship: | ||||
|                 relation = node.tpl_relationship | ||||
|                 for relation, nodetpls in relation.items(): | ||||
|                     for tpl in self.nodetemplates: | ||||
|                         if tpl.name == nodetpls.name: | ||||
|                             self._create_edge(node, tpl, relation) | ||||
|             self._create_vertex(node) | ||||
		Reference in New Issue
	
	Block a user
	 Sahdev Zala
					Sahdev Zala