Fix StatefulEntityType when entitytype is not define
[parser.git] / tosca2heat / tosca-parser / toscaparser / elements / nodetype.py
1 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
2 #    not use this file except in compliance with the License. You may obtain
3 #    a copy of the License at
4 #
5 #         http://www.apache.org/licenses/LICENSE-2.0
6 #
7 #    Unless required by applicable law or agreed to in writing, software
8 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 #    License for the specific language governing permissions and limitations
11 #    under the License.
12
13 from toscaparser.common.exception import ExceptionCollector
14 from toscaparser.common.exception import UnknownFieldError
15 from toscaparser.elements.capabilitytype import CapabilityTypeDef
16 import toscaparser.elements.interfaces as ifaces
17 from toscaparser.elements.interfaces import InterfacesDef
18 from toscaparser.elements.relationshiptype import RelationshipType
19 from toscaparser.elements.statefulentitytype import StatefulEntityType
20
21
22 class NodeType(StatefulEntityType):
23     '''TOSCA built-in node type.'''
24     SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, ATTRIBUTES, REQUIREMENTS, CAPABILITIES, INTERFACES, ARTIFACTS) = \
25                ('derived_from', 'metadata', 'properties', 'version',
26                 'description', 'attributes', 'requirements', 'capabilities',
27                 'interfaces', 'artifacts')
28
29     def __init__(self, ntype, custom_def=None):
30         super(NodeType, self).__init__(ntype, self.NODE_PREFIX, custom_def)
31         self.ntype = ntype
32         self.custom_def = custom_def
33         self._validate_keys()
34
35     @property
36     def parent_type(self):
37         '''Return a node this node is derived from.'''
38         if not hasattr(self, 'defs'):
39             return None
40         pnode = self.derived_from(self.defs)
41         if pnode:
42             return NodeType(pnode, self.custom_def)
43
44     @property
45     def relationship(self):
46         '''Return a dictionary of relationships to other node types.
47
48         This method returns a dictionary of named relationships that nodes
49         of the current node type (self) can have to other nodes (of specific
50         types) in a TOSCA template.
51
52         '''
53         relationship = {}
54         requires = self.get_all_requirements()
55         if requires:
56             # NOTE(sdmonov): Check if requires is a dict.
57             # If it is a dict convert it to a list of dicts.
58             # This is needed because currently the code below supports only
59             # lists as requirements definition. The following check will
60             # make sure if a map (dict) was provided it will be converted to
61             # a list before proceeding to the parsing.
62             if isinstance(requires, dict):
63                 requires = [{key: value} for key, value in requires.items()]
64
65             keyword = None
66             node_type = None
67             for require in requires:
68                 for key, req in require.items():
69                     if 'relationship' in req:
70                         relation = req.get('relationship')
71                         if 'type' in relation:
72                             relation = relation.get('type')
73                         node_type = req.get('node')
74                         value = req
75                         if node_type:
76                             keyword = 'node'
77                         else:
78                             # If value is a dict and has a type key
79                             # we need to lookup the node type using
80                             # the capability type
81                             value = req
82                             if isinstance(value, dict):
83                                 captype = value['capability']
84                                 value = (self.
85                                          _get_node_type_by_cap(captype))
86                             keyword = key
87                             node_type = value
88                 rtype = RelationshipType(relation, keyword, self.custom_def)
89                 relatednode = NodeType(node_type, self.custom_def)
90                 relationship[rtype] = relatednode
91         return relationship
92
93     def _get_node_type_by_cap(self, cap):
94         '''Find the node type that has the provided capability
95
96         This method will lookup all node types if they have the
97         provided capability.
98         '''
99
100         # Filter the node types
101         node_types = [node_type for node_type in self.TOSCA_DEF.keys()
102                       if node_type.startswith(self.NODE_PREFIX) and
103                       node_type != 'tosca.nodes.Root']
104         custom_node_types = [node_type for node_type in self.custom_def.keys()
105                              if node_type.startswith(self.NODE_PREFIX) and
106                              node_type != 'tosca.nodes.Root']
107
108         for node_type in node_types + custom_node_types:
109             if node_type in self.TOSCA_DEF:
110                 node_def = self.TOSCA_DEF[node_type]
111             else:
112                 node_def = self.custom_def[node_type]
113             if isinstance(node_def, dict) and 'capabilities' in node_def:
114                 node_caps = node_def['capabilities']
115                 for value in node_caps.values():
116                     if isinstance(value, dict) and \
117                             'type' in value and value['type'] == cap:
118                         return node_type
119
120     def _get_relation(self, key, ndtype):
121         relation = None
122         ntype = NodeType(ndtype, self.custom_def)
123         caps = ntype.get_capabilities()
124         if caps and key in caps.keys():
125             c = caps[key]
126             for r in self.RELATIONSHIP_TYPE:
127                 rtypedef = ntype.TOSCA_DEF[r]
128                 for properties in rtypedef.values():
129                     if c.type in properties:
130                         relation = r
131                         break
132                 if relation:
133                     break
134                 else:
135                     for properties in rtypedef.values():
136                         if c.parent_type in properties:
137                             relation = r
138                             break
139         return relation
140
141     def get_capabilities_objects(self):
142         '''Return a list of capability objects.'''
143         typecapabilities = []
144         caps = self.get_value(self.CAPABILITIES, None, True)
145         if caps:
146             # 'name' is symbolic name of the capability
147             # 'value' is a dict { 'type': <capability type name> }
148             for name, value in caps.items():
149                 ctype = value.get('type')
150                 cap = CapabilityTypeDef(name, ctype, self.type,
151                                         self.custom_def)
152                 typecapabilities.append(cap)
153         return typecapabilities
154
155     def get_capabilities(self):
156         '''Return a dictionary of capability name-objects pairs.'''
157         return {cap.name: cap
158                 for cap in self.get_capabilities_objects()}
159
160     @property
161     def requirements(self):
162         return self.get_value(self.REQUIREMENTS, None, True)
163
164     def get_all_requirements(self):
165         return self.requirements
166
167     @property
168     def interfaces(self):
169         return self.get_value(self.INTERFACES)
170
171     @property
172     def lifecycle_inputs(self):
173         '''Return inputs to life cycle operations if found.'''
174         inputs = []
175         interfaces = self.interfaces
176         if interfaces:
177             for name, value in interfaces.items():
178                 if name == ifaces.LIFECYCLE:
179                     for x, y in value.items():
180                         if x == 'inputs':
181                             for i in y.iterkeys():
182                                 inputs.append(i)
183         return inputs
184
185     @property
186     def lifecycle_operations(self):
187         '''Return available life cycle operations if found.'''
188         ops = None
189         interfaces = self.interfaces
190         if interfaces:
191             i = InterfacesDef(self.type, ifaces.LIFECYCLE)
192             ops = i.lifecycle_ops
193         return ops
194
195     def get_capability(self, name):
196         caps = self.get_capabilities()
197         if caps and name in caps.keys():
198             return caps[name].value
199
200     def get_capability_type(self, name):
201         captype = self.get_capability(name)
202         if captype and name in captype.keys():
203             return captype[name].value
204
205     def _validate_keys(self):
206         if self.defs:
207             for key in self.defs.keys():
208                 if key not in self.SECTIONS:
209                     ExceptionCollector.appendException(
210                         UnknownFieldError(what='Nodetype"%s"' % self.ntype,
211                                           field=key))