a6bb9323ee8eef8551b1722972922f7554f411e8
[sdc.git] /
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.sdc.enrichment.impl.tosca;
18
19 import org.apache.commons.collections4.CollectionUtils;
20 import org.apache.commons.lang3.StringUtils;
21 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
22 import org.onap.sdc.tosca.datatypes.model.NodeType;
23 import org.onap.sdc.tosca.datatypes.model.RequirementAssignment;
24 import org.onap.sdc.tosca.datatypes.model.RequirementDefinition;
25 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
26 import org.onap.sdc.tosca.datatypes.model.TopologyTemplate;
27 import org.openecomp.sdc.datatypes.error.ErrorMessage;
28 import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes;
29 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
30 import org.openecomp.sdc.tosca.services.DataModelUtil;
31 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
32 import org.openecomp.sdc.tosca.services.ToscaConstants;
33 import org.openecomp.sdc.tosca.services.impl.ToscaAnalyzerServiceImpl;
34 import org.openecomp.sdc.versioning.dao.types.Version;
35
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.Optional;
42
43 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.HIGH_AVAIL_MODE;
44 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.MANDATORY;
45 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.MAX_INSTANCES;
46 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.MIN_INSTANCES;
47 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.NFC_FUNCTION;
48 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.NFC_NAMING_CODE;
49 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.VFC_CODE;
50 import static org.openecomp.sdc.enrichment.impl.util.EnrichmentConstants.VM_TYPE_TAG;
51 import static org.openecomp.sdc.tosca.datatypes.ToscaCapabilityType.NATIVE_NODE;
52 import static org.openecomp.sdc.tosca.datatypes.ToscaNodeType.MULTIDEPLOYMENTFLAVOR_NODE_TYPE;
53 import static org.openecomp.sdc.tosca.datatypes.ToscaNodeType.VFC_ABSTRACT_SUBSTITUTE;
54 import static org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType.NATIVE_DEPENDS_ON;
55 import static org.openecomp.sdc.tosca.services.ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME;
56 import static org.openecomp.sdc.translator.services.heattotosca.Constants.VNF_NODE_TEMPLATE_ID_SUFFIX;
57
58 public class AbstractSubstituteToscaEnricher {
59
60     private ToscaAnalyzerService toscaAnalyzerService;
61     private ComponentQuestionnaireData componentQuestionnaireData;
62
63
64     public Map<String, List<ErrorMessage>> enrich(ToscaServiceModel toscaModel, String vspId, Version version) {
65         componentQuestionnaireData = getComponentQuestionnaireData();
66         toscaAnalyzerService = new ToscaAnalyzerServiceImpl();
67
68         Map<String, Map<String, Object>> componentProperties =
69                 componentQuestionnaireData.getPropertiesfromCompQuestionnaire(vspId, version);
70
71         final Map<String, List<String>> sourceToTargetDependencies = componentQuestionnaireData
72                                                                              .populateDependencies(vspId, version,
73                                                                                      componentQuestionnaireData
74                                                                                       .getSourceToTargetComponent());
75         Map<String, List<ErrorMessage>> errors = new HashMap<>();
76
77         final ServiceTemplate serviceTemplate =
78                 toscaModel.getServiceTemplates().get(toscaModel.getEntryDefinitionServiceTemplate());
79
80         if (serviceTemplate == null) {
81             return errors;
82         }
83
84         final TopologyTemplate topologyTemplate = serviceTemplate.getTopology_template();
85         if (topologyTemplate == null) {
86             return errors;
87         }
88
89         final Map<String, NodeTemplate> nodeTemplates = serviceTemplate.getTopology_template().getNode_templates();
90         if (nodeTemplates == null) {
91             return errors;
92         }
93
94         final Map<String, List<String>> componentDisplayNameToNodeTemplateIds =
95                 populateAllNodeTemplateIdForComponent(nodeTemplates, serviceTemplate, toscaModel);
96
97         nodeTemplates.keySet().forEach(nodeTemplateId -> {
98             final NodeTemplate nodeTemplate =
99                     toscaAnalyzerService.getNodeTemplateById(serviceTemplate, nodeTemplateId).orElse(null);
100
101             if (nodeTemplate != null && toscaAnalyzerService.isTypeOf(nodeTemplate, VFC_ABSTRACT_SUBSTITUTE,
102                     serviceTemplate, toscaModel)) {
103
104                 String componentDisplayName = getComponentDisplayName(nodeTemplateId, nodeTemplate);
105
106                 enrichProperties(nodeTemplate, componentDisplayName, componentProperties);
107
108                 enrichRequirements(sourceToTargetDependencies, componentDisplayName, nodeTemplate,
109                         componentDisplayNameToNodeTemplateIds, serviceTemplate, toscaModel);
110             }
111         });
112         return errors;
113     }
114
115     private void enrichProperties(NodeTemplate nodeTemplate, String componentDisplayName,
116             Map<String, Map<String, Object>> componentProperties) {
117         setProperty(nodeTemplate, VM_TYPE_TAG, componentDisplayName);
118
119         if (componentProperties != null && componentProperties.containsKey(componentDisplayName)) {
120             final String mandatory =
121                     getValueFromQuestionnaireDetails(componentProperties, componentDisplayName, MANDATORY);
122
123             boolean isServiceTemplateFilterNotExists = false;
124             if (!StringUtils.isEmpty(mandatory)) {
125                 Map<String, Object> innerProps = (Map<String, Object>) nodeTemplate.getProperties()
126                                                                    .get(SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
127
128                 if (innerProps == null) {
129                     innerProps = new HashMap<>();
130                     isServiceTemplateFilterNotExists = true;
131                 }
132                 Optional<Boolean> mandatoryValue = getValue(mandatory);
133                 if (mandatoryValue.isPresent()) {
134                     innerProps.put(MANDATORY, mandatoryValue.get());
135                 }
136
137                 if (isServiceTemplateFilterNotExists) {
138                     nodeTemplate.getProperties().put(SERVICE_TEMPLATE_FILTER_PROPERTY_NAME, innerProps);
139                 }
140             }
141
142             setProperty(nodeTemplate, HIGH_AVAIL_MODE,
143                     getValueFromQuestionnaireDetails(componentProperties, componentDisplayName,
144                             HIGH_AVAIL_MODE));
145
146             setProperty(nodeTemplate, NFC_NAMING_CODE,
147                     getValueFromQuestionnaireDetails(componentProperties, componentDisplayName,
148                             NFC_NAMING_CODE));
149
150             setProperty(nodeTemplate, VFC_CODE,
151                     getValueFromQuestionnaireDetails(componentProperties, componentDisplayName, VFC_CODE));
152
153             setProperty(nodeTemplate, NFC_FUNCTION,
154                     getValueFromQuestionnaireDetails(componentProperties, componentDisplayName, NFC_FUNCTION));
155
156             if (componentProperties.get(componentDisplayName).get(MIN_INSTANCES) != null) {
157                 nodeTemplate.getProperties().put(MIN_INSTANCES,
158                         componentProperties.get(componentDisplayName).get(MIN_INSTANCES));
159             }
160
161             if (componentProperties.get(componentDisplayName).get(MAX_INSTANCES) != null) {
162                 nodeTemplate.getProperties().put(MAX_INSTANCES,
163                         componentProperties.get(componentDisplayName).get(MAX_INSTANCES));
164             }
165         }
166     }
167
168     private Map<String, List<String>> populateAllNodeTemplateIdForComponent(Map<String, NodeTemplate> nodeTemplates,
169                                                                                    ServiceTemplate serviceTemplate,
170                                                                                    ToscaServiceModel toscaModel) {
171
172
173         Map<String, List<String>> componentDisplayNameToNodeTempalteIds = new HashMap<>();
174
175         //set dependency target
176         nodeTemplates.keySet().forEach(nodeTemplateId -> {
177             final NodeTemplate nodeTemplate =
178                     toscaAnalyzerService.getNodeTemplateById(serviceTemplate, nodeTemplateId).orElse(null);
179
180             if (nodeTemplate != null &&
181                     toscaAnalyzerService.isTypeOf(nodeTemplate, VFC_ABSTRACT_SUBSTITUTE, serviceTemplate, toscaModel)) {
182
183                 String componentDisplayName = getComponentDisplayName(nodeTemplateId, nodeTemplate);
184
185                 if (componentDisplayNameToNodeTempalteIds.containsKey(componentDisplayName)) {
186                     componentDisplayNameToNodeTempalteIds.get(componentDisplayName).add(nodeTemplateId);
187                 } else {
188                     List<String> nodeTemplateIds = new ArrayList<>();
189                     nodeTemplateIds.add(nodeTemplateId);
190                     componentDisplayNameToNodeTempalteIds.put(componentDisplayName, nodeTemplateIds);
191                 }
192
193             }
194         });
195
196         return componentDisplayNameToNodeTempalteIds;
197     }
198
199     private void enrichRequirements(Map<String, List<String>> sourceToTargetDependencies, String componentDisplayName,
200                                            NodeTemplate nodeTemplate,
201                                            Map<String, List<String>> componentDisplayNameToNodeTempalteIds,
202                                            ServiceTemplate serviceTemplate, ToscaServiceModel toscaServiceModel) {
203         final List<String> targets = sourceToTargetDependencies.get(componentDisplayName);
204         if (CollectionUtils.isEmpty(targets)) {
205             return;
206         }
207
208         for (String target : targets) {
209             List<String> targetNodeTemplateIds = componentDisplayNameToNodeTempalteIds.get(target);
210             if (CollectionUtils.isEmpty(targetNodeTemplateIds)) {
211                 continue;
212             }
213             for (String targetNodeTemplateId : targetNodeTemplateIds) {
214                 Optional<String> dependencyRequirementKey =
215                         getDependencyRequirementKey(serviceTemplate, componentDisplayName, nodeTemplate,
216                                 toscaServiceModel);
217                 if (dependencyRequirementKey.isPresent()) {
218                     RequirementAssignment requirementAssignment = new RequirementAssignment();
219                     requirementAssignment.setCapability(NATIVE_NODE);
220                     requirementAssignment.setRelationship(NATIVE_DEPENDS_ON);
221                     requirementAssignment.setNode(targetNodeTemplateId);
222                     DataModelUtil.addRequirementAssignment(nodeTemplate, dependencyRequirementKey.get(),
223                             requirementAssignment);
224                 }
225             }
226         }
227     }
228
229     private Optional<String> getDependencyRequirementKey(ServiceTemplate serviceTemplate, String componentDisplayName,
230                                                                 NodeTemplate nodeTemplate,
231                                                                 ToscaServiceModel toscaServiceModel) {
232         String nodeType = nodeTemplate.getType();
233         NodeType flatNodeType = (NodeType) toscaAnalyzerService.getFlatEntity(ToscaElementTypes.NODE_TYPE, nodeType,
234                 serviceTemplate, toscaServiceModel).getFlatEntity();
235         List<Map<String, RequirementDefinition>> flatNodeTypeRequirements = flatNodeType.getRequirements();
236         if (Objects.isNull(flatNodeTypeRequirements)) {
237             return Optional.empty();
238         }
239         for (Map<String, RequirementDefinition> requirementDefinitionMap : flatNodeTypeRequirements) {
240             String requirementKey = requirementDefinitionMap.keySet().iterator().next();
241             String expectedKey = ToscaConstants.DEPENDS_ON_REQUIREMENT_ID + "_" + componentDisplayName;
242             if (requirementKey.equals(expectedKey)) {
243                 return Optional.of(requirementKey);
244             }
245         }
246         return Optional.empty();
247     }
248
249     private String getComponentDisplayName(String nodeTemplateId, NodeTemplate nodeTemplate) {
250         String componentDisplayName;
251         final String type = nodeTemplate.getType();
252         if (MULTIDEPLOYMENTFLAVOR_NODE_TYPE.equals(type)) {
253             componentDisplayName = nodeTemplateId.substring(0, nodeTemplateId.lastIndexOf(VNF_NODE_TEMPLATE_ID_SUFFIX));
254         } else {
255             String vmType = DataModelUtil.getNamespaceSuffix(type);
256             final String[] removedSuffix = vmType.split("_\\d+");
257             componentDisplayName = removedSuffix[0];
258         }
259         return componentDisplayName;
260     }
261
262     private String getValueFromQuestionnaireDetails(Map<String, Map<String, Object>> componentTypetoParams,
263                                                            String componentDisplayName, String propertyName) {
264         return (String) componentTypetoParams.get(componentDisplayName).get(propertyName);
265     }
266
267     private void setProperty(NodeTemplate nodeTemplate, String key, String value) {
268         if (!StringUtils.isEmpty(value)) {
269             //YamlUtil throws IllegalStateException("duplicate key: " + key) if key is already present.
270             // So first removing and then populating same key with new updated value
271             nodeTemplate.getProperties().remove(key);
272             nodeTemplate.getProperties().put(key, value);
273         }
274     }
275
276     private Optional<Boolean> getValue(String value) {
277         switch (value) {
278             case "YES":
279                 return Optional.of(Boolean.TRUE);
280             case "NO":
281                 return Optional.of(Boolean.FALSE);
282             default:
283                 return Optional.empty();
284         }
285     }
286
287     private ComponentQuestionnaireData getComponentQuestionnaireData() {
288         if (componentQuestionnaireData == null) {
289             componentQuestionnaireData = new ComponentQuestionnaireData();
290         }
291         return componentQuestionnaireData;
292     }
293 }