bugs:The code in function of get_all_requirements is duplicated
[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(key, captype))
86                             relation = self._get_relation(key, value)
87                             keyword = key
88                             node_type = value
89                 rtype = RelationshipType(relation, keyword, self.custom_def)
90                 relatednode = NodeType(node_type, self.custom_def)
91                 relationship[rtype] = relatednode
92         return relationship
93
94     def _get_node_type_by_cap(self, key, cap):
95         '''Find the node type that has the provided capability
96
97         This method will lookup all node types if they have the
98         provided capability.
99         '''
100
101         # Filter the node types
102         node_types = [node_type for node_type in self.TOSCA_DEF.keys()
103                       if node_type.startswith(self.NODE_PREFIX) and
104                       node_type != 'tosca.nodes.Root']
105
106         for node_type in node_types:
107             node_def = self.TOSCA_DEF[node_type]
108             if isinstance(node_def, dict) and 'capabilities' in node_def:
109                 node_caps = node_def['capabilities']
110                 for value in node_caps.values():
111                     if isinstance(value, dict) and \
112                             'type' in value and value['type'] == cap:
113                         return node_type
114
115     def _get_relation(self, key, ndtype):
116         relation = None
117         ntype = NodeType(ndtype)
118         caps = ntype.get_capabilities()
119         if caps and key in caps.keys():
120             c = caps[key]
121             for r in self.RELATIONSHIP_TYPE:
122                 rtypedef = ntype.TOSCA_DEF[r]
123                 for properties in rtypedef.values():
124                     if c.type in properties:
125                         relation = r
126                         break
127                 if relation:
128                     break
129                 else:
130                     for properties in rtypedef.values():
131                         if c.parent_type in properties:
132                             relation = r
133                             break
134         return relation
135
136     def get_capabilities_objects(self):
137         '''Return a list of capability objects.'''
138         typecapabilities = []
139         caps = self.get_value(self.CAPABILITIES, None, True)
140         if caps is None:
141             caps = self.get_value(self.CAPABILITIES, None, True)
142         if caps:
143             # 'name' is symbolic name of the capability
144             # 'value' is a dict { 'type': <capability type name> }
145             for name, value in caps.items():
146                 ctype = value.get('type')
147                 cap = CapabilityTypeDef(name, ctype, self.type,
148                                         self.custom_def)
149                 typecapabilities.append(cap)
150         return typecapabilities
151
152     def get_capabilities(self):
153         '''Return a dictionary of capability name-objects pairs.'''
154         return {cap.name: cap
155                 for cap in self.get_capabilities_objects()}
156
157     @property
158     def requirements(self):
159         return self.get_value(self.REQUIREMENTS, None, True)
160
161     def get_all_requirements(self):
162         return self.requirements
163
164     @property
165     def interfaces(self):
166         return self.get_value(self.INTERFACES)
167
168     @property
169     def lifecycle_inputs(self):
170         '''Return inputs to life cycle operations if found.'''
171         inputs = []
172         interfaces = self.interfaces
173         if interfaces:
174             for name, value in interfaces.items():
175                 if name == ifaces.LIFECYCLE:
176                     for x, y in value.items():
177                         if x == 'inputs':
178                             for i in y.iterkeys():
179                                 inputs.append(i)
180         return inputs
181
182     @property
183     def lifecycle_operations(self):
184         '''Return available life cycle operations if found.'''
185         ops = None
186         interfaces = self.interfaces
187         if interfaces:
188             i = InterfacesDef(self.type, ifaces.LIFECYCLE)
189             ops = i.lifecycle_ops
190         return ops
191
192     def get_capability(self, name):
193         caps = self.get_capabilities()
194         if caps and name in caps.keys():
195             return caps[name].value
196
197     def get_capability_type(self, name):
198         captype = self.get_capability(name)
199         if captype and name in captype.keys():
200             return captype[name].value
201
202     def _validate_keys(self):
203         if self.defs:
204             for key in self.defs.keys():
205                 if key not in self.SECTIONS:
206                     ExceptionCollector.appendException(
207                         UnknownFieldError(what='Nodetype"%s"' % self.ntype,
208                                           field=key))