Fix checkstyle violations in sdc/jtosca
[sdc/sdc-tosca.git] / src / main / java / org / onap / sdc / toscaparser / api / NodeTemplate.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.sdc.toscaparser.api;
22
23 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
24 import org.onap.sdc.toscaparser.api.elements.EntityType;
25 import org.onap.sdc.toscaparser.api.elements.InterfacesDef;
26 import org.onap.sdc.toscaparser.api.elements.Metadata;
27 import org.onap.sdc.toscaparser.api.elements.NodeType;
28 import org.onap.sdc.toscaparser.api.elements.RelationshipType;
29 import org.onap.sdc.toscaparser.api.utils.CopyUtils;
30 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
31
32 import java.util.ArrayList;
33 import java.util.LinkedHashMap;
34 import java.util.List;
35 import java.util.Map;
36
37 import static org.onap.sdc.toscaparser.api.elements.EntityType.TOSCA_DEF;
38
39 public class NodeTemplate extends EntityTemplate {
40
41     private LinkedHashMap<String, Object> templates;
42     private LinkedHashMap<String, Object> customDef;
43     private ArrayList<RelationshipTemplate> availableRelTpls;
44     private LinkedHashMap<String, Object> availableRelTypes;
45     private LinkedHashMap<NodeTemplate, RelationshipType> related;
46     private ArrayList<RelationshipTemplate> relationshipTpl;
47     private LinkedHashMap<RelationshipType, NodeTemplate> _relationships;
48     private SubstitutionMappings subMappingToscaTemplate;
49     private TopologyTemplate originComponentTemplate;
50     private Metadata metadata;
51
52     private static final String METADATA = "metadata";
53
54     public NodeTemplate(String name,
55                         LinkedHashMap<String, Object> ntnodeTemplates,
56                         LinkedHashMap<String, Object> ntcustomDef,
57                         ArrayList<RelationshipTemplate> ntavailableRelTpls,
58                         LinkedHashMap<String, Object> ntavailableRelTypes) {
59         this(name, ntnodeTemplates, ntcustomDef, ntavailableRelTpls,
60                 ntavailableRelTypes, null);
61     }
62
63     @SuppressWarnings("unchecked")
64     public NodeTemplate(String name,
65                         LinkedHashMap<String, Object> ntnodeTemplates,
66                         LinkedHashMap<String, Object> ntcustomDef,
67                         ArrayList<RelationshipTemplate> ntavailableRelTpls,
68                         LinkedHashMap<String, Object> ntavailableRelTypes,
69                         NodeTemplate parentNodeTemplate) {
70
71         super(name, (LinkedHashMap<String, Object>) ntnodeTemplates.get(name),
72                 "node_type", ntcustomDef, parentNodeTemplate);
73
74         templates = ntnodeTemplates;
75         _validateFields((LinkedHashMap<String, Object>) templates.get(name));
76         customDef = ntcustomDef;
77         related = new LinkedHashMap<NodeTemplate, RelationshipType>();
78         relationshipTpl = new ArrayList<RelationshipTemplate>();
79         availableRelTpls = ntavailableRelTpls;
80         availableRelTypes = ntavailableRelTypes;
81         _relationships = new LinkedHashMap<RelationshipType, NodeTemplate>();
82         subMappingToscaTemplate = null;
83         metadata = _metaData();
84     }
85
86     @SuppressWarnings("unchecked")
87     public LinkedHashMap<RelationshipType, NodeTemplate> getRelationships() {
88         if (_relationships.isEmpty()) {
89             List<RequirementAssignment> requires = getRequirements().getAll();
90             if (requires != null && requires instanceof List) {
91                 for (RequirementAssignment r : requires) {
92                     LinkedHashMap<RelationshipType, NodeTemplate> explicit = _getExplicitRelationship(r);
93                     if (explicit != null) {
94                         // _relationships.putAll(explicit)...
95                         for (Map.Entry<RelationshipType, NodeTemplate> ee : explicit.entrySet()) {
96                             _relationships.put(ee.getKey(), ee.getValue());
97                         }
98                     }
99                 }
100             }
101         }
102         return _relationships;
103     }
104
105     @SuppressWarnings("unchecked")
106     private LinkedHashMap<RelationshipType, NodeTemplate> _getExplicitRelationship(RequirementAssignment req) {
107         // Handle explicit relationship
108
109         // For example,
110         // - req:
111         //     node: DBMS
112         //     relationship: tosca.relationships.HostedOn
113
114         LinkedHashMap<RelationshipType, NodeTemplate> explicitRelation = new LinkedHashMap<RelationshipType, NodeTemplate>();
115         String node = req.getNodeTemplateName();
116
117         if (node != null && !node.isEmpty()) {
118             //msg = _('Lookup by TOSCA types is not supported. '
119             //        'Requirement for "%s" can not be full-filled.') % self.name
120             boolean bFound = false;
121             for (String k : EntityType.TOSCA_DEF.keySet()) {
122                 if (k.equals(node)) {
123                     bFound = true;
124                     break;
125                 }
126             }
127             if (bFound || customDef.get(node) != null) {
128                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE205", String.format(
129                         "NotImplementedError: Lookup by TOSCA types is not supported. Requirement for \"%s\" can not be full-filled",
130                         getName())));
131                 return null;
132             }
133             if (templates.get(node) == null) {
134                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE206", String.format(
135                         "KeyError: Node template \"%s\" was not found", node)));
136                 return null;
137             }
138             NodeTemplate relatedTpl = new NodeTemplate(node, templates, customDef, null, null);
139             Object relationship = req.getRelationship();
140             String relationshipString = null;
141 //                      // here relationship can be a string or a LHM with 'type':<relationship>
142
143             // check if its type has relationship defined
144             if (relationship == null) {
145                 ArrayList<Object> parentReqs = ((NodeType) typeDefinition).getAllRequirements();
146                 if (parentReqs == null) {
147                     ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE207", "ValidationError: parent_req is null"));
148                 } else {
149 //                                      for(String key: req.keySet()) {
150 //                                              boolean bFoundRel = false;
151                     for (Object rdo : parentReqs) {
152                         LinkedHashMap<String, Object> reqDict = (LinkedHashMap<String, Object>) rdo;
153                         LinkedHashMap<String, Object> relDict = (LinkedHashMap<String, Object>) reqDict.get(req.getName());
154                         if (relDict != null) {
155                             relationship = relDict.get("relationship");
156                             //BUG-python??? need to break twice?
157 //                                                              bFoundRel = true;
158                             break;
159                         }
160                     }
161 //                                              if(bFoundRel) {
162 //                                                      break;
163 //                                              }
164 //                                      }
165                 }
166             }
167
168             if (relationship != null) {
169                 // here relationship can be a string or a LHM with 'type':<relationship>
170                 if (relationship instanceof String) {
171                     relationshipString = (String) relationship;
172                 } else if (relationship instanceof LinkedHashMap) {
173                     relationshipString = (String) ((LinkedHashMap<String, Object>) relationship).get("type");
174                 }
175
176                 boolean foundRelationshipTpl = false;
177                 // apply available relationship templates if found
178                 if (availableRelTpls != null) {
179                     for (RelationshipTemplate tpl : availableRelTpls) {
180                         if (tpl.getName().equals(relationshipString)) {
181                             RelationshipType rtype = new RelationshipType(tpl.getType(), null, customDef);
182                             explicitRelation.put(rtype, relatedTpl);
183                             tpl.setTarget(relatedTpl);
184                             tpl.setSource(this);
185                             relationshipTpl.add(tpl);
186                             foundRelationshipTpl = true;
187                         }
188                     }
189                 }
190                 // create relationship template object.
191                 String relPrfx = EntityType.RELATIONSHIP_PREFIX;
192                 if (!foundRelationshipTpl) {
193                     if (relationship instanceof LinkedHashMap) {
194                         relationshipString = (String) ((LinkedHashMap<String, Object>) relationship).get("type");
195                         if (relationshipString != null) {
196                             if (availableRelTypes != null && !availableRelTypes.isEmpty() &&
197                                     availableRelTypes.get(relationshipString) != null) {
198                                 ;
199                             } else if (!(relationshipString).startsWith(relPrfx)) {
200                                 relationshipString = relPrfx + relationshipString;
201                             }
202                         } else {
203                             ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE208", String.format(
204                                     "MissingRequiredFieldError: \"relationship\" used in template \"%s\" is missing required field \"type\"",
205                                     relatedTpl.getName())));
206                         }
207                     }
208                     for (RelationshipType rtype : ((NodeType) typeDefinition).getRelationship().keySet()) {
209                         if (rtype.getType().equals(relationshipString)) {
210                             explicitRelation.put(rtype, relatedTpl);
211                             relatedTpl._addRelationshipTemplate(req, rtype.getType(), this);
212                         } else if (availableRelTypes != null && !availableRelTypes.isEmpty()) {
213                             LinkedHashMap<String, Object> relTypeDef = (LinkedHashMap<String, Object>) availableRelTypes.get(relationshipString);
214                             if (relTypeDef != null) {
215                                 String superType = (String) relTypeDef.get("derived_from");
216                                 if (superType != null) {
217                                     if (!superType.startsWith(relPrfx)) {
218                                         superType = relPrfx + superType;
219                                     }
220                                     if (rtype.getType().equals(superType)) {
221                                         explicitRelation.put(rtype, relatedTpl);
222                                         relatedTpl._addRelationshipTemplate(req, rtype.getType(), this);
223                                     }
224                                 }
225                             }
226                         }
227                     }
228                 }
229             }
230         }
231         return explicitRelation;
232     }
233
234     @SuppressWarnings("unchecked")
235     private void _addRelationshipTemplate(RequirementAssignment requirement, String rtype, NodeTemplate source) {
236         LinkedHashMap<String, Object> req = new LinkedHashMap<>();
237         req.put("relationship", CopyUtils.copyLhmOrAl(requirement.getRelationship()));
238         req.put("type", rtype);
239         RelationshipTemplate tpl = new RelationshipTemplate(req, rtype, customDef, this, source, getParentNodeTemplate());
240         relationshipTpl.add(tpl);
241     }
242
243     public ArrayList<RelationshipTemplate> getRelationshipTemplate() {
244         return relationshipTpl;
245     }
246
247     void _addNext(NodeTemplate nodetpl, RelationshipType relationship) {
248         related.put(nodetpl, relationship);
249     }
250
251     public ArrayList<NodeTemplate> getRelatedNodes() {
252         if (related.isEmpty()) {
253             for (Map.Entry<RelationshipType, NodeType> me : ((NodeType) typeDefinition).getRelationship().entrySet()) {
254                 RelationshipType relation = me.getKey();
255                 NodeType node = me.getValue();
256                 for (String tpl : templates.keySet()) {
257                     if (tpl.equals(node.getType())) {
258                         //BUG.. python has
259                         //    self.related[NodeTemplate(tpl)] = relation
260                         // but NodeTemplate doesn't have a constructor with just name...
261                         //????
262                         related.put(new NodeTemplate(tpl, null, null, null, null), relation);
263                     }
264                 }
265             }
266         }
267         return new ArrayList<NodeTemplate>(related.keySet());
268     }
269
270     public void validate(/*tosca_tpl=none is not used...*/) {
271         _validateCapabilities();
272         _validateRequirements();
273         _validateProperties(entityTpl, (NodeType) typeDefinition);
274         _validateInterfaces();
275         for (Property prop : getPropertiesObjects()) {
276             prop.validate();
277         }
278     }
279
280     public Object getPropertyValueFromTemplatesByName(String propertyName) {
281         LinkedHashMap<String, Object> nodeObject = (LinkedHashMap<String, Object>) templates.get(name);
282         if (nodeObject != null) {
283             LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>) nodeObject.get(PROPERTIES);
284             if (properties != null) {
285                 return properties.get(propertyName);
286             }
287         }
288         return null;
289     }
290
291     private Metadata _metaData() {
292         if (entityTpl.get(METADATA) != null) {
293             return new Metadata((Map<String, Object>) entityTpl.get(METADATA));
294         } else {
295             return null;
296         }
297     }
298
299     @SuppressWarnings("unchecked")
300     private void _validateRequirements() {
301         ArrayList<Object> typeRequires = ((NodeType) typeDefinition).getAllRequirements();
302         ArrayList<String> allowedReqs = new ArrayList<>();
303         allowedReqs.add("template");
304         if (typeRequires != null) {
305             for (Object to : typeRequires) {
306                 LinkedHashMap<String, Object> treq = (LinkedHashMap<String, Object>) to;
307                 for (Map.Entry<String, Object> me : treq.entrySet()) {
308                     String key = me.getKey();
309                     Object value = me.getValue();
310                     allowedReqs.add(key);
311                     if (value instanceof LinkedHashMap) {
312                         allowedReqs.addAll(((LinkedHashMap<String, Object>) value).keySet());
313                     }
314                 }
315
316             }
317         }
318
319         ArrayList<Object> requires = (ArrayList<Object>) ((NodeType) typeDefinition).getValue(REQUIREMENTS, entityTpl, false);
320         if (requires != null) {
321             if (!(requires instanceof ArrayList)) {
322                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE209", String.format(
323                         "TypeMismatchError: \"requirements\" of template \"%s\" are not of type \"list\"", name)));
324             } else {
325                 for (Object ro : requires) {
326                     LinkedHashMap<String, Object> req = (LinkedHashMap<String, Object>) ro;
327                     for (Map.Entry<String, Object> me : req.entrySet()) {
328                         String rl = me.getKey();
329                         Object vo = me.getValue();
330                         if (vo instanceof LinkedHashMap) {
331                             LinkedHashMap<String, Object> value = (LinkedHashMap<String, Object>) vo;
332                             _validateRequirementsKeys(value);
333                             _validateRequirementsProperties(value);
334                             allowedReqs.add(rl);
335                         }
336                     }
337                     _commonValidateField(req, allowedReqs, "requirements");
338                 }
339             }
340         }
341     }
342
343     @SuppressWarnings("unchecked")
344     private void _validateRequirementsProperties(LinkedHashMap<String, Object> reqs) {
345         // TO-DO(anyone): Only occurrences property of the requirements is
346         // validated here. Validation of other requirement properties are being
347         // validated in different files. Better to keep all the requirements
348         // properties validation here.
349         for (Map.Entry<String, Object> me : reqs.entrySet()) {
350             if (me.getKey().equals("occurrences")) {
351                 ArrayList<Object> val = (ArrayList<Object>) me.getValue();
352                 _validateOccurrences(val);
353             }
354
355         }
356     }
357
358     private void _validateOccurrences(ArrayList<Object> occurrences) {
359         DataEntity.validateDatatype("list", occurrences, null, null, null);
360         for (Object val : occurrences) {
361             DataEntity.validateDatatype("Integer", val, null, null, null);
362         }
363         if (occurrences.size() != 2 ||
364                 !(0 <= (int) occurrences.get(0) && (int) occurrences.get(0) <= (int) occurrences.get(1)) ||
365                 (int) occurrences.get(1) == 0) {
366             ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE210", String.format(
367                     "InvalidPropertyValueError: property has invalid value %s", occurrences.toString())));
368         }
369     }
370
371     private void _validateRequirementsKeys(LinkedHashMap<String, Object> reqs) {
372         for (String key : reqs.keySet()) {
373             boolean bFound = false;
374             for (int i = 0; i < REQUIREMENTS_SECTION.length; i++) {
375                 if (key.equals(REQUIREMENTS_SECTION[i])) {
376                     bFound = true;
377                     break;
378                 }
379             }
380             if (!bFound) {
381                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE211", String.format(
382                         "UnknownFieldError: \"requirements\" of template \"%s\" contains unknown field \"%s\"", name, key)));
383             }
384         }
385     }
386
387     @SuppressWarnings("unchecked")
388     private void _validateInterfaces() {
389         LinkedHashMap<String, Object> ifaces = (LinkedHashMap<String, Object>)
390                 ((NodeType) typeDefinition).getValue(INTERFACES, entityTpl, false);
391         if (ifaces != null) {
392             for (Map.Entry<String, Object> me : ifaces.entrySet()) {
393                 String iname = me.getKey();
394                 LinkedHashMap<String, Object> value = (LinkedHashMap<String, Object>) me.getValue();
395                 if (iname.equals(InterfacesDef.LIFECYCLE) || iname.equals(InterfacesDef.LIFECYCLE_SHORTNAME)) {
396                     // maybe we should convert [] to arraylist???
397                     ArrayList<String> inlo = new ArrayList<>();
398                     for (int i = 0; i < InterfacesDef.INTERFACE_NODE_LIFECYCLE_OPERATIONS.length; i++) {
399                         inlo.add(InterfacesDef.INTERFACE_NODE_LIFECYCLE_OPERATIONS[i]);
400                     }
401                     _commonValidateField(value, inlo, "interfaces");
402                 } else if (iname.equals(InterfacesDef.CONFIGURE) || iname.equals(InterfacesDef.CONFIGURE_SHORTNAME)) {
403                     // maybe we should convert [] to arraylist???
404                     ArrayList<String> irco = new ArrayList<>();
405                     for (int i = 0; i < InterfacesDef.INTERFACE_RELATIONSHIP_CONFIGURE_OPERATIONS.length; i++) {
406                         irco.add(InterfacesDef.INTERFACE_RELATIONSHIP_CONFIGURE_OPERATIONS[i]);
407                     }
408                     _commonValidateField(value, irco, "interfaces");
409                 } else if (((NodeType) typeDefinition).getInterfaces().keySet().contains(iname)) {
410                     _commonValidateField(value, _collectCustomIfaceOperations(iname), "interfaces");
411                 } else {
412                     ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE212", String.format(
413                             "UnknownFieldError: \"interfaces\" of template \"%s\" contains unknown field %s", name, iname)));
414                 }
415             }
416         }
417     }
418
419     @SuppressWarnings("unchecked")
420     private ArrayList<String> _collectCustomIfaceOperations(String iname) {
421         ArrayList<String> allowedOperations = new ArrayList<>();
422         LinkedHashMap<String, Object> nodetypeIfaceDef = (LinkedHashMap<String, Object>) ((NodeType)
423                 typeDefinition).getInterfaces().get(iname);
424         allowedOperations.addAll(nodetypeIfaceDef.keySet());
425         String ifaceType = (String) nodetypeIfaceDef.get("type");
426         if (ifaceType != null) {
427             LinkedHashMap<String, Object> ifaceTypeDef = null;
428             if (((NodeType) typeDefinition).customDef != null) {
429                 ifaceTypeDef = (LinkedHashMap<String, Object>) ((NodeType) typeDefinition).customDef.get(ifaceType);
430             }
431             if (ifaceTypeDef == null) {
432                 ifaceTypeDef = (LinkedHashMap<String, Object>) EntityType.TOSCA_DEF.get(ifaceType);
433             }
434             allowedOperations.addAll(ifaceTypeDef.keySet());
435         }
436         // maybe we should convert [] to arraylist???
437         ArrayList<String> idrw = new ArrayList<>();
438         for (int i = 0; i < InterfacesDef.INTERFACE_DEF_RESERVED_WORDS.length; i++) {
439             idrw.add(InterfacesDef.INTERFACE_DEF_RESERVED_WORDS[i]);
440         }
441         allowedOperations.removeAll(idrw);
442         return allowedOperations;
443     }
444
445     /**
446      * Get all interface details for given node template.<br>
447      *
448      * @return Map that contains the list of all interfaces and their definitions.
449      * If none found, an empty map will be returned.
450      */
451     public Map<String, List<InterfacesDef>> getAllInterfaceDetailsForNodeType() {
452         Map<String, List<InterfacesDef>> interfaceMap = new LinkedHashMap<>();
453
454         // Get custom interface details
455         Map<String, Object> customInterfacesDetails = ((NodeType) typeDefinition).getInterfaces();
456         // Get native interface details from tosca definitions
457         Object nativeInterfaceDetails = TOSCA_DEF.get(InterfacesDef.LIFECYCLE);
458         Map<String, Object> allInterfaceDetails = new LinkedHashMap<>();
459         allInterfaceDetails.putAll(customInterfacesDetails);
460         if (nativeInterfaceDetails != null) {
461             allInterfaceDetails.put(InterfacesDef.LIFECYCLE, nativeInterfaceDetails);
462         }
463
464         // Process all interface details from combined collection and return an interface Map with
465         // interface names and their definitions
466         for (Map.Entry<String, Object> me : allInterfaceDetails.entrySet()) {
467             ArrayList<InterfacesDef> interfaces = new ArrayList<>();
468             String interfaceType = me.getKey();
469             Map<String, Object> interfaceValue = (Map<String, Object>) me.getValue();
470             if (interfaceValue.containsKey("type")) {
471                 interfaceType = (String) interfaceValue.get("type");
472             }
473
474             for (Map.Entry<String, Object> ve : interfaceValue.entrySet()) {
475                 // Filter type as this is a reserved key and not an operation
476                 if (!ve.getKey().equals("type")) {
477                     InterfacesDef iface = new InterfacesDef(typeDefinition, interfaceType, this, ve.getKey(), ve.getValue());
478                     interfaces.add(iface);
479                 }
480             }
481             interfaceMap.put(interfaceType, interfaces);
482         }
483         return interfaceMap;
484     }
485
486     private void _validateFields(LinkedHashMap<String, Object> nodetemplate) {
487         for (String ntname : nodetemplate.keySet()) {
488             boolean bFound = false;
489             for (int i = 0; i < SECTIONS.length; i++) {
490                 if (ntname.equals(SECTIONS[i])) {
491                     bFound = true;
492                     break;
493                 }
494             }
495             if (!bFound) {
496                 for (int i = 0; i < SPECIAL_SECTIONS.length; i++) {
497                     if (ntname.equals(SPECIAL_SECTIONS[i])) {
498                         bFound = true;
499                         break;
500                     }
501                 }
502
503             }
504             if (!bFound) {
505                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE213", String.format(
506                         "UnknownFieldError: Node template \"%s\" has unknown field \"%s\"", name, ntname)));
507             }
508         }
509     }
510
511     // getter/setter
512
513     // multilevel nesting
514     public SubstitutionMappings getSubMappingToscaTemplate() {
515         return subMappingToscaTemplate;
516     }
517
518     public void setSubMappingToscaTemplate(SubstitutionMappings sm) {
519         subMappingToscaTemplate = sm;
520     }
521
522     public Metadata getMetaData() {
523         return metadata;
524     }
525
526     public void setMetaData(Metadata metadata) {
527         this.metadata = metadata;
528     }
529
530     @Override
531     public String toString() {
532         return getName();
533     }
534
535     public TopologyTemplate getOriginComponentTemplate() {
536         return originComponentTemplate;
537     }
538
539     public void setOriginComponentTemplate(TopologyTemplate originComponentTemplate) {
540         this.originComponentTemplate = originComponentTemplate;
541     }
542
543 }
544
545 /*python
546
547 from toscaparser.common.exception import ValidationIssueCollector
548 from toscaparser.common.exception import InvalidPropertyValueError
549 from toscaparser.common.exception import MissingRequiredFieldError
550 from toscaparser.common.exception import TypeMismatchError
551 from toscaparser.common.exception import UnknownFieldError
552 from toscaparser.common.exception import ValidationError
553 from toscaparser.dataentity import DataEntity
554 from toscaparser.elements.interfaces import CONFIGURE
555 from toscaparser.elements.interfaces import CONFIGURE_SHORTNAME
556 from toscaparser.elements.interfaces import INTERFACE_DEF_RESERVED_WORDS
557 from toscaparser.elements.interfaces import InterfacesDef
558 from toscaparser.elements.interfaces import LIFECYCLE
559 from toscaparser.elements.interfaces import LIFECYCLE_SHORTNAME
560 from toscaparser.elements.relationshiptype import RelationshipType
561 from toscaparser.entity_template import EntityTemplate
562 from toscaparser.relationship_template import RelationshipTemplate
563 from toscaparser.utils.gettextutils import _
564
565 log = logging.getLogger('tosca')
566
567
568 class NodeTemplate(EntityTemplate):
569     '''Node template from a Tosca profile.'''
570     def __init__(self, name, node_templates, custom_def=None,
571                  available_rel_tpls=None, available_rel_types=None):
572         super(NodeTemplate, self).__init__(name, node_templates[name],
573                                            'node_type',
574                                            custom_def)
575         self.templates = node_templates
576         self._validate_fields(node_templates[name])
577         self.custom_def = custom_def
578         self.related = {}
579         self.relationship_tpl = []
580         self.available_rel_tpls = available_rel_tpls
581         self.available_rel_types = available_rel_types
582         self._relationships = {}
583         self.sub_mapping_tosca_template = None
584
585     @property
586     def relationships(self):
587         if not self._relationships:
588             requires = self.requirements
589             if requires and isinstance(requires, list):
590                 for r in requires:
591                     for r1, value in r.items():
592                         explicit = self._get_explicit_relationship(r, value)
593                         if explicit:
594                             for key, value in explicit.items():
595                                 self._relationships[key] = value
596         return self._relationships
597
598     def _get_explicit_relationship(self, req, value):
599         """Handle explicit relationship
600
601         For example,
602         - req:
603             node: DBMS
604             relationship: tosca.relationships.HostedOn
605         """
606         explicit_relation = {}
607         node = value.get('node') if isinstance(value, dict) else value
608
609         if node:
610             # TO-DO(spzala) implement look up once Glance meta data is available
611             # to find a matching TOSCA node using the TOSCA types
612             msg = _('Lookup by TOSCA types is not supported. '
613                     'Requirement for "%s" can not be full-filled.') % self.name
614             if (node in list(self.type_definition.TOSCA_DEF.keys())
615                or node in self.custom_def):
616                 ValidationIssueCollector.appendException(NotImplementedError(msg))
617                 return
618
619             if node not in self.templates:
620                 ValidationIssueCollector.appendException(
621                     KeyError(_('Node template "%s" was not found.') % node))
622                 return
623
624             related_tpl = NodeTemplate(node, self.templates, self.custom_def)
625             relationship = value.get('relationship') \
626                 if isinstance(value, dict) else None
627             # check if it's type has relationship defined
628             if not relationship:
629                 parent_reqs = self.type_definition.get_all_requirements()
630                 if parent_reqs is None:
631                     ValidationIssueCollector.appendException(
632                         ValidationError(message='parent_req is ' +
633                                         str(parent_reqs)))
634                 else:
635                     for key in req.keys():
636                         for req_dict in parent_reqs:
637                             if key in req_dict.keys():
638                                 relationship = (req_dict.get(key).
639                                                 get('relationship'))
640                                 break
641             if relationship:
642                 found_relationship_tpl = False
643                 # apply available relationship templates if found
644                 if self.available_rel_tpls:
645                     for tpl in self.available_rel_tpls:
646                         if tpl.name == relationship:
647                             rtype = RelationshipType(tpl.type, None,
648                                                      self.custom_def)
649                             explicit_relation[rtype] = related_tpl
650                             tpl.target = related_tpl
651                             tpl.source = self
652                             self.relationship_tpl.append(tpl)
653                             found_relationship_tpl = True
654                 # create relationship template object.
655                 rel_prfx = self.type_definition.RELATIONSHIP_PREFIX
656                 if not found_relationship_tpl:
657                     if isinstance(relationship, dict):
658                         relationship = relationship.get('type')
659                         if relationship:
660                             if self.available_rel_types and \
661                                relationship in self.available_rel_types.keys():
662                                 pass
663                             elif not relationship.startswith(rel_prfx):
664                                 relationship = rel_prfx + relationship
665                         else:
666                             ValidationIssueCollector.appendException(
667                                 MissingRequiredFieldError(
668                                     what=_('"relationship" used in template '
669                                            '"%s"') % related_tpl.name,
670                                     required=self.TYPE))
671                     for rtype in self.type_definition.relationship.keys():
672                         if rtype.type == relationship:
673                             explicit_relation[rtype] = related_tpl
674                             related_tpl._add_relationship_template(req,
675                                                                    rtype.type,
676                                                                    self)
677                         elif self.available_rel_types:
678                             if relationship in self.available_rel_types.keys():
679                                 rel_type_def = self.available_rel_types.\
680                                     get(relationship)
681                                 if 'derived_from' in rel_type_def:
682                                     super_type = \
683                                         rel_type_def.get('derived_from')
684                                     if not super_type.startswith(rel_prfx):
685                                         super_type = rel_prfx + super_type
686                                     if rtype.type == super_type:
687                                         explicit_relation[rtype] = related_tpl
688                                         related_tpl.\
689                                             _add_relationship_template(
690                                                 req, rtype.type, self)
691         return explicit_relation
692
693     def _add_relationship_template(self, requirement, rtype, source):
694         req = requirement.copy()
695         req['type'] = rtype
696         tpl = RelationshipTemplate(req, rtype, self.custom_def, self, source)
697         self.relationship_tpl.append(tpl)
698
699     def get_relationship_template(self):
700         return self.relationship_tpl
701
702     def _add_next(self, nodetpl, relationship):
703         self.related[nodetpl] = relationship
704
705     @property
706     def related_nodes(self):
707         if not self.related:
708             for relation, node in self.type_definition.relationship.items():
709                 for tpl in self.templates:
710                     if tpl == node.type:
711                         self.related[NodeTemplate(tpl)] = relation
712         return self.related.keys()
713
714     def validate(self, tosca_tpl=None):
715         self._validate_capabilities()
716         self._validate_requirements()
717         self._validate_properties(self.entity_tpl, self.type_definition)
718         self._validate_interfaces()
719         for prop in self.get_properties_objects():
720             prop.validate()
721
722     def _validate_requirements(self):
723         type_requires = self.type_definition.get_all_requirements()
724         allowed_reqs = ["template"]
725         if type_requires:
726             for treq in type_requires:
727                 for key, value in treq.items():
728                     allowed_reqs.append(key)
729                     if isinstance(value, dict):
730                         for key in value:
731                             allowed_reqs.append(key)
732
733         requires = self.type_definition.get_value(self.REQUIREMENTS,
734                                                   self.entity_tpl)
735         if requires:
736             if not isinstance(requires, list):
737                 ValidationIssueCollector.appendException(
738                     TypeMismatchError(
739                         what='"requirements" of template "%s"' % self.name,
740                         type='list'))
741             else:
742                 for req in requires:
743                     for r1, value in req.items():
744                         if isinstance(value, dict):
745                             self._validate_requirements_keys(value)
746                             self._validate_requirements_properties(value)
747                             allowed_reqs.append(r1)
748                     self._common_validate_field(req, allowed_reqs,
749                                                 'requirements')
750
751     def _validate_requirements_properties(self, requirements):
752         # TO-DO(anyone): Only occurrences property of the requirements is
753         # validated here. Validation of other requirement properties are being
754         # validated in different files. Better to keep all the requirements
755         # properties validation here.
756         for key, value in requirements.items():
757             if key == 'occurrences':
758                 self._validate_occurrences(value)
759                 break
760
761     def _validate_occurrences(self, occurrences):
762         DataEntity.validate_datatype('list', occurrences)
763         for value in occurrences:
764             DataEntity.validate_datatype('integer', value)
765         if len(occurrences) != 2 or not (0 <= occurrences[0] <= occurrences[1]) \
766                 or occurrences[1] == 0:
767             ValidationIssueCollector.appendException(
768                 InvalidPropertyValueError(what=(occurrences)))
769
770     def _validate_requirements_keys(self, requirement):
771         for key in requirement.keys():
772             if key not in self.REQUIREMENTS_SECTION:
773                 ValidationIssueCollector.appendException(
774                     UnknownFieldError(
775                         what='"requirements" of template "%s"' % self.name,
776                         field=key))
777
778     def _validate_interfaces(self):
779         ifaces = self.type_definition.get_value(self.INTERFACES,
780                                                 self.entity_tpl)
781         if ifaces:
782             for name, value in ifaces.items():
783                 if name in (LIFECYCLE, LIFECYCLE_SHORTNAME):
784                     self._common_validate_field(
785                         value, InterfacesDef.
786                         interfaces_node_lifecycle_operations,
787                         'interfaces')
788                 elif name in (CONFIGURE, CONFIGURE_SHORTNAME):
789                     self._common_validate_field(
790                         value, InterfacesDef.
791                         interfaces_relationship_configure_operations,
792                         'interfaces')
793                 elif name in self.type_definition.interfaces.keys():
794                     self._common_validate_field(
795                         value,
796                         self._collect_custom_iface_operations(name),
797                         'interfaces')
798                 else:
799                     ValidationIssueCollector.appendException(
800                         UnknownFieldError(
801                             what='"interfaces" of template "%s"' %
802                             self.name, field=name))
803
804     def _collect_custom_iface_operations(self, name):
805         allowed_operations = []
806         nodetype_iface_def = self.type_definition.interfaces[name]
807         allowed_operations.extend(nodetype_iface_def.keys())
808         if 'type' in nodetype_iface_def:
809             iface_type = nodetype_iface_def['type']
810             if iface_type in self.type_definition.custom_def:
811                 iface_type_def = self.type_definition.custom_def[iface_type]
812             else:
813                 iface_type_def = self.type_definition.TOSCA_DEF[iface_type]
814             allowed_operations.extend(iface_type_def.keys())
815         allowed_operations = [op for op in allowed_operations if
816                               op not in INTERFACE_DEF_RESERVED_WORDS]
817         return allowed_operations
818
819     def _validate_fields(self, nodetemplate):
820         for name in nodetemplate.keys():
821             if name not in self.SECTIONS and name not in self.SPECIAL_SECTIONS:
822                 ValidationIssueCollector.appendException(
823                     UnknownFieldError(what='Node template "%s"' % self.name,
824                                       field=name))*/