Support functions in TOSCA Simple Profile in YAML
[sdc.git] / openecomp-be / lib / openecomp-sdc-translator-lib / openecomp-sdc-translator-core / src / main / java / org / openecomp / sdc / translator / services / heattotosca / impl / resourcetranslation / BaseResourceConnection.java
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.translator.services.heattotosca.impl.resourcetranslation;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Objects;
24 import java.util.Optional;
25 import java.util.function.Predicate;
26
27 import org.apache.commons.collections4.CollectionUtils;
28 import org.apache.commons.collections4.MapUtils;
29 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
30 import org.onap.sdc.tosca.datatypes.model.NodeType;
31 import org.onap.sdc.tosca.datatypes.model.RequirementAssignment;
32 import org.onap.sdc.tosca.datatypes.model.RequirementDefinition;
33 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
34 import org.onap.sdc.tosca.services.YamlUtil;
35 import org.openecomp.sdc.common.errors.CoreException;
36 import org.openecomp.sdc.common.errors.ErrorCategory;
37 import org.openecomp.sdc.common.errors.ErrorCode;
38 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
39 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
40 import org.openecomp.sdc.heat.datatypes.model.Resource;
41 import org.openecomp.sdc.logging.api.Logger;
42 import org.openecomp.sdc.logging.api.LoggerFactory;
43 import org.openecomp.sdc.tosca.datatypes.ToscaFunctions;
44 import org.openecomp.sdc.tosca.services.DataModelUtil;
45 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
46 import org.openecomp.sdc.tosca.services.impl.ToscaAnalyzerServiceImpl;
47 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedResourceId;
48 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslateTo;
49 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslatedHeatResource;
50 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
51 import org.openecomp.sdc.translator.services.heattotosca.errors.TranslatorErrorCodes;
52
53 abstract class BaseResourceConnection<T> {
54     protected static Logger logger = LoggerFactory.getLogger(BaseResourceConnection.class);
55     protected TranslateTo translateTo;
56     FileData nestedFileData;
57     NodeTemplate substitutionNodeTemplate;
58     NodeType nodeType;
59     ResourceTranslationBase resourceTranslationBase;
60
61     BaseResourceConnection(ResourceTranslationBase resourceTranslationBase, TranslateTo translateTo,
62                            FileData nestedFileData, NodeTemplate substitutionNodeTemplate,
63                            NodeType nodeType) {
64         this.translateTo = translateTo;
65         this.nestedFileData = nestedFileData;
66         this.substitutionNodeTemplate = substitutionNodeTemplate;
67         this.nodeType = nodeType;
68         this.resourceTranslationBase = resourceTranslationBase;
69     }
70
71     abstract boolean isDesiredNodeTemplateType(NodeTemplate nodeTemplate);
72
73     abstract List<Predicate<T>> getPredicatesListForConnectionPoints();
74
75     abstract Optional<List<String>> getConnectorPropertyParamName(String heatResourceId,
76                                                                   Resource heatResource,
77                                                                   HeatOrchestrationTemplate
78                                                                           nestedHeatOrchestrationTemplate,
79                                                                   String nestedHeatFileName);
80
81     abstract String getDesiredResourceType();
82
83     abstract String getMappedNodeTranslatedResourceId(ServiceTemplate nestedServiceTemplate,
84                                                       Map.Entry<String, T> connectionPointEntry);
85
86     abstract Map.Entry<String, T> getMappedConnectionPointEntry(ServiceTemplate nestedServiceTemplate,
87                                                                 Map.Entry<String, T>
88                                                                         connectionPointEntry);
89
90     abstract void addRequirementToConnectResources(Map.Entry<String, T> connectionPointEntry,
91                                                    List<String> paramNames);
92
93     abstract List<Map<String, T>> getAllConnectionPoints();
94
95     abstract boolean validateResourceTypeSupportedForReqCreation(String nestedResourceId,
96                                                                  final String nestedPropertyName,
97                                                                  String connectionPointId,
98                                                                  Resource connectedResource,
99                                                                  List<String> supportedTypes);
100
101     void connect() {
102         ServiceTemplate nestedServiceTemplate = translateTo.getContext().getTranslatedServiceTemplates()
103                 .get(translateTo.getResource().getType());
104         List<String> paramNames;
105         HeatOrchestrationTemplate nestedHeatOrchestrationTemplate = new YamlUtil()
106                 .yamlToObject(translateTo.getContext().getFileContentAsStream(nestedFileData.getFile()),
107                         HeatOrchestrationTemplate.class);
108         List<Map<String, T>> exposedConnectionPoints = getAllConnectionPoints();
109         for (Map<String, T> connectionPointsMap : exposedConnectionPoints) {
110             for (Map.Entry<String, T> connectionPointEntry : connectionPointsMap.entrySet()) {
111                 paramNames =
112                         getConnectionParameterName(nestedServiceTemplate, nestedHeatOrchestrationTemplate,
113                                 nestedFileData.getFile(), connectionPointEntry);
114                 if (CollectionUtils.isNotEmpty(paramNames)) {
115                     addRequirementToConnectResources(connectionPointEntry, paramNames);
116                 }
117             }
118         }
119     }
120
121     private List<String> getConnectionParameterName(ServiceTemplate nestedServiceTemplate,
122                                                     HeatOrchestrationTemplate
123                                                             nestedHeatOrchestrationTemplate,
124                                                     String nestedHeatFileName,
125                                                     Map.Entry<String, T> connectionPointEntry) {
126         List<String> connectionParameterNameList = new ArrayList<>();
127         String mappedTranslatedResourceId = getMappedNodeTranslatedResourceId(nestedServiceTemplate,
128                 connectionPointEntry);
129         NodeTemplate mappedNodeTemplate = nestedServiceTemplate.getTopology_template().getNode_templates()
130                         .get(mappedTranslatedResourceId);
131         if (isDesiredNodeTemplateType(mappedNodeTemplate)) {
132             return getResourcesConnectionParameterName(mappedTranslatedResourceId,
133                     nestedHeatOrchestrationTemplate, nestedHeatFileName);
134         }
135
136         ToscaAnalyzerService toscaAnalyzerService = new ToscaAnalyzerServiceImpl();
137         if (!toscaAnalyzerService.isSubstitutableNodeTemplate(mappedNodeTemplate)) {
138             return Collections.emptyList();
139         }
140         Optional<String> mappedSubstituteServiceTemplateName = toscaAnalyzerService
141                 .getSubstituteServiceTemplateName(mappedTranslatedResourceId, mappedNodeTemplate);
142         if (!mappedSubstituteServiceTemplateName.isPresent()) {
143             return Collections.emptyList();
144         }
145         String mappedNestedHeatFileName = translateTo.getContext().getNestedHeatFileName()
146                 .get(mappedSubstituteServiceTemplateName.get());
147         if (Objects.isNull(mappedNestedHeatFileName)) {
148             return Collections.emptyList();
149         }
150         HeatOrchestrationTemplate mappedNestedHeatOrchestrationTemplate = new YamlUtil()
151                 .yamlToObject(translateTo.getContext().getFileContentAsStream(mappedNestedHeatFileName),
152                         HeatOrchestrationTemplate.class);
153         ServiceTemplate mappedNestedServiceTemplate =
154                 translateTo.getContext().getTranslatedServiceTemplates().get(mappedNestedHeatFileName);
155         List<String> nestedPropertyNames = getConnectionParameterName(mappedNestedServiceTemplate,
156                 mappedNestedHeatOrchestrationTemplate, mappedNestedHeatFileName,
157                 getMappedConnectionPointEntry(nestedServiceTemplate, connectionPointEntry));
158
159         if (CollectionUtils.isEmpty(nestedPropertyNames)) {
160             return connectionParameterNameList;
161         }
162         for (String propertyName : nestedPropertyNames) {
163             Object propertyValue = mappedNodeTemplate.getProperties().get(propertyName);
164             if (propertyValue instanceof Map
165                     && ((Map) propertyValue).containsKey(ToscaFunctions.GET_INPUT.getFunctionName())) {
166                 Object paramName = ((Map) propertyValue).get(ToscaFunctions.GET_INPUT.getFunctionName());
167                 if (paramName instanceof String) {
168                     connectionParameterNameList.add((String) paramName);
169                 }
170             }
171         }
172         return connectionParameterNameList;
173     }
174
175     private List<String> getResourcesConnectionParameterName(String translatedResourceId,
176                                                              HeatOrchestrationTemplate
177                                                                      nestedHeatOrchestrationTemplate,
178                                                              String nestedHeatFileName) {
179         List<String> params = new ArrayList<>();
180         Optional<List<Map.Entry<String, Resource>>> heatResources =
181                 getResourceByTranslatedResourceId(translatedResourceId, nestedHeatOrchestrationTemplate);
182         if (!heatResources.isPresent()) {
183             return params;
184         }
185         for (Map.Entry<String, Resource> resourceEntry : heatResources.get()) {
186             Resource heatResource = resourceEntry.getValue();
187             if (!MapUtils.isEmpty(heatResource.getProperties())) {
188                 Optional<List<String>> connectorParamName =
189                         getConnectorPropertyParamName(resourceEntry.getKey(), heatResource,
190                                 nestedHeatOrchestrationTemplate, nestedHeatFileName);
191                 connectorParamName.ifPresent(params::addAll);
192             }
193         }
194         return params;
195     }
196
197     protected Optional<List<Map.Entry<String, Resource>>> getResourceByTranslatedResourceId(
198             String translatedResourceId, HeatOrchestrationTemplate nestedHeatOrchestrationTemplate) {
199         Optional<List<Map.Entry<String, Resource>>> resourceByTranslatedResourceId =
200                 resourceTranslationBase.getResourceByTranslatedResourceId(nestedFileData.getFile(),
201                         nestedHeatOrchestrationTemplate, translatedResourceId, translateTo,
202                         getDesiredResourceType());
203         if (!resourceByTranslatedResourceId.isPresent()) {
204             throw new CoreException((new ErrorCode.ErrorCodeBuilder()).withMessage(
205                     "Failed to get original resource from heat for translate resource id '"
206                             + translatedResourceId + "'")
207                     .withId(TranslatorErrorCodes.HEAT_TO_TOSCA_MAPPING_COLLISION)
208                     .withCategory(ErrorCategory.APPLICATION).build());
209         }
210         return resourceByTranslatedResourceId;
211     }
212
213     RequirementAssignment createRequirementAssignment(Map.Entry<String, RequirementDefinition> requirementEntry,
214                                                       String node,
215                                                       NodeTemplate nodeTemplate) {
216         RequirementAssignment requirementAssignment = null;
217         if (Objects.nonNull(node)) {
218             requirementAssignment = new RequirementAssignment();
219             requirementAssignment.setRelationship(requirementEntry.getValue().getRelationship());
220             requirementAssignment.setCapability(requirementEntry.getValue().getCapability());
221             requirementAssignment.setNode(node);
222             DataModelUtil.addRequirementAssignment(nodeTemplate, requirementEntry.getKey(), requirementAssignment);
223         }
224         return requirementAssignment;
225     }
226
227
228     Optional<String> getConnectionTranslatedNodeUsingGetParamFunc(
229             Map.Entry<String, T> connectionPointEntry, String paramName,
230             List<String> supportedNodeTypes) {
231
232         Optional<AttachedResourceId> attachedResourceId =
233                 HeatToToscaUtil.extractAttachedResourceId(translateTo, paramName);
234         if (!attachedResourceId.isPresent()) {
235             return Optional.empty();
236         }
237         AttachedResourceId resourceId = attachedResourceId.get();
238         if (resourceId.isGetParam() && resourceId.getEntityId() instanceof String) {
239             TranslatedHeatResource shareResource =
240                     translateTo.getContext().getHeatSharedResourcesByParam().get(resourceId.getEntityId());
241             if (isSupportedSharedResource(paramName, connectionPointEntry.getKey(), supportedNodeTypes,
242                     shareResource)) {
243                 return Optional.of(shareResource.getTranslatedId());
244             }
245         }
246         return Optional.empty();
247     }
248
249     private boolean isSupportedSharedResource(String paramName, String connectionPointId,
250                                               List<String> supportedNodeTypes,
251                                               TranslatedHeatResource shareResource) {
252         return Objects.nonNull(shareResource)
253                 && !HeatToToscaUtil.isHeatFileNested(translateTo, translateTo.getHeatFileName())
254                 && validateResourceTypeSupportedForReqCreation(translateTo.getResourceId(), paramName,
255                 connectionPointId, shareResource.getHeatResource(), supportedNodeTypes);
256     }
257
258     Optional<TranslatedHeatResource> getConnectionTranslatedHeatResourceUsingGetParamFunc(
259             Map.Entry<String, T> connectionPointEntry, String paramName,
260             List<String> supportedNodeTypes) {
261
262         Optional<AttachedResourceId> attachedResourceId =
263                 HeatToToscaUtil.extractAttachedResourceId(translateTo, paramName);
264         if (!attachedResourceId.isPresent()) {
265             return Optional.empty();
266         }
267         AttachedResourceId resourceId = attachedResourceId.get();
268         if (resourceId.isGetParam() && resourceId.getEntityId() instanceof String) {
269             TranslatedHeatResource shareResource =
270                     translateTo.getContext().getHeatSharedResourcesByParam().get(resourceId.getEntityId());
271             if (isSupportedSharedResource(paramName, connectionPointEntry.getKey(), supportedNodeTypes,
272                     shareResource)) {
273                 return Optional.of(shareResource);
274             }
275         }
276         return Optional.empty();
277     }
278
279
280     Optional<String> getConnectionTranslatedNodeUsingGetResourceFunc(
281             Map.Entry<String, T> connectionPointEntry, String paramName, Object paramValue,
282             List<String> supportedNodeTypes) {
283         Optional<String> getResourceAttachedResourceId =
284                 HeatToToscaUtil.extractContrailGetResourceAttachedHeatResourceId(paramValue);
285         if (getResourceAttachedResourceId.isPresent()) { // get resource
286             Resource resource = translateTo.getHeatOrchestrationTemplate().getResources()
287                     .get(getResourceAttachedResourceId.get());
288             if (validateResourceTypeSupportedForReqCreation(translateTo.getResourceId(), paramName,
289                     connectionPointEntry.getKey(), resource, supportedNodeTypes)) {
290                 return ResourceTranslationBase.getResourceTranslatedId(translateTo.getHeatFileName(),
291                         translateTo.getHeatOrchestrationTemplate(), getResourceAttachedResourceId.get(),
292                         translateTo.getContext());
293             }
294         }
295
296         return Optional.empty();
297     }
298
299     Optional<String> getConnectionResourceUsingGetResourceFunc(
300             Map.Entry<String, T> connectionPointEntry, String paramName, Object paramValue,
301             List<String> supportedNodeTypes) {
302         Optional<String> getResourceAttachedResourceId =
303                 HeatToToscaUtil.extractContrailGetResourceAttachedHeatResourceId(paramValue);
304         if (getResourceAttachedResourceId.isPresent()) { // get resource
305             Resource resource = translateTo.getHeatOrchestrationTemplate().getResources()
306                     .get(getResourceAttachedResourceId.get());
307             if (validateResourceTypeSupportedForReqCreation(translateTo.getResourceId(), paramName,
308                     connectionPointEntry.getKey(), resource, supportedNodeTypes)) {
309                 return getResourceAttachedResourceId;
310             }
311         }
312         return Optional.empty();
313     }
314 }