7ca4f78b375f7c5e3b033dcb5143d729088e6c53
[sdc.git] / openecomp-be / lib / openecomp-sdc-translator-lib / openecomp-sdc-translator-core / src / main / java / org / openecomp / sdc / translator / services / heattotosca / TranslationService.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;
18
19 import org.apache.commons.collections4.CollectionUtils;
20 import org.apache.commons.collections4.MapUtils;
21 import org.openecomp.core.translator.datatypes.TranslatorOutput;
22 import org.openecomp.core.utilities.file.FileUtils;
23 import org.openecomp.sdc.common.errors.CoreException;
24 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
25 import org.openecomp.sdc.heat.datatypes.model.Environment;
26 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
27 import org.openecomp.sdc.heat.datatypes.model.Output;
28 import org.openecomp.sdc.heat.datatypes.model.Resource;
29 import org.openecomp.sdc.logging.api.Logger;
30 import org.openecomp.sdc.logging.api.LoggerFactory;
31 import org.openecomp.sdc.tosca.datatypes.ToscaGroupType;
32 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
33 import org.openecomp.sdc.tosca.datatypes.model.GroupDefinition;
34 import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition;
35 import org.openecomp.sdc.tosca.datatypes.model.PropertyType;
36 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
37 import org.openecomp.sdc.tosca.datatypes.model.TopologyTemplate;
38 import org.openecomp.sdc.tosca.datatypes.model.heatextend.ParameterDefinitionExt;
39 import org.openecomp.sdc.tosca.services.DataModelUtil;
40 import org.openecomp.sdc.tosca.services.ToscaConstants;
41 import org.openecomp.sdc.tosca.services.ToscaFileOutputService;
42 import org.openecomp.sdc.tosca.services.ToscaUtil;
43 import org.openecomp.sdc.tosca.services.YamlUtil;
44 import org.openecomp.sdc.tosca.services.impl.ToscaFileOutputServiceCsarImpl;
45 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedResourceId;
46 import org.openecomp.sdc.translator.datatypes.heattotosca.TranslationContext;
47 import org.openecomp.sdc.translator.datatypes.heattotosca.to.FileDataCollection;
48 import org.openecomp.sdc.translator.services.heattotosca.errors.ResourceNotFoundInHeatFileErrorBuilder;
49 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
50 import org.openecomp.sdc.translator.services.heattotosca.mapping.TranslatorHeatToToscaParameterConverter;
51
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.Objects;
58 import java.util.Optional;
59 import java.util.Set;
60 import java.util.stream.Collectors;
61
62 public class TranslationService {
63
64     protected static Logger logger = LoggerFactory.getLogger(TranslationService.class);
65
66     /**
67      * Gets types to process by translator.
68      *
69      * @return the types to process by translator
70      */
71     public static Set<FileData.Type> getTypesToProcessByTranslator() {
72         Set<FileData.Type> types = new HashSet<>();
73         types.add(FileData.Type.HEAT);
74         types.add(FileData.Type.HEAT_VOL);
75         return types;
76     }
77
78     /**
79      * Translate heat files translator output.
80      *
81      * @param translationContext the translation context
82      * @return the translator output
83      */
84     public TranslatorOutput translateHeatFiles(TranslationContext translationContext) {
85         ServiceTemplate mainServiceTemplate = createMainServiceTemplate(translationContext);
86         List<FileData> fileDataList = translationContext.getManifest().getContent().getData();
87         FileDataCollection fileDataCollection = HeatToToscaUtil.getFileCollectionsByFilter(fileDataList,
88                 TranslationService.getTypesToProcessByTranslator(), translationContext);
89
90         if (fileDataCollection.getBaseFile() != null) {
91             for (FileData fileData : fileDataCollection.getBaseFile()) {
92                 translateHeatFile(mainServiceTemplate, fileData,  translationContext);
93             }
94         }
95         if (fileDataCollection.getAddOnFiles() != null) {
96             for (FileData fileData : fileDataCollection.getAddOnFiles()) {
97                 translateHeatFile(mainServiceTemplate, fileData, translationContext);
98             }
99         }
100
101         ToscaServiceModel toscaServiceModel =
102                 HeatToToscaUtil.createToscaServiceModel(mainServiceTemplate, translationContext);
103
104         TranslatorOutput translatorOutput = new TranslatorOutput();
105         //Keeping a copy of tosca service model after first stage of translation for extraction of
106         // composition data
107         translatorOutput.setNonUnifiedToscaServiceModel(
108                 ToscaServiceModel.getClonedServiceModel(toscaServiceModel));
109         translatorOutput.setToscaServiceModel(toscaServiceModel);
110         return translatorOutput;
111     }
112
113     private ServiceTemplate createMainServiceTemplate(TranslationContext translationContext) {
114         ServiceTemplate mainServiceTemplate = new ServiceTemplate();
115         translationContext.getTranslatedServiceTemplates()
116                 .put(Constants.MAIN_TEMPLATE_NAME, mainServiceTemplate);
117         Map<String, String> templateMetadata = new HashMap<>();
118         templateMetadata.put(ToscaConstants.ST_METADATA_TEMPLATE_NAME, Constants.MAIN_TEMPLATE_NAME);
119         mainServiceTemplate.setTosca_definitions_version(ToscaConstants.TOSCA_DEFINITIONS_VERSION);
120         mainServiceTemplate.setMetadata(templateMetadata);
121         mainServiceTemplate.setTopology_template(new TopologyTemplate());
122         mainServiceTemplate.setImports(GlobalTypesGenerator.getGlobalTypesImportList());
123         return mainServiceTemplate;
124     }
125
126     /**
127      * Translate heat file.
128      *
129      * @param serviceTemplate the service template
130      * @param heatFileData    the heat file data
131      * @param context         the context
132      */
133     public void translateHeatFile(ServiceTemplate serviceTemplate, FileData heatFileData,
134                                   TranslationContext context) {
135         translateHeatFile(serviceTemplate, heatFileData,  null, context);
136     }
137
138     /**
139      * Translate heat file.
140      *
141      * @param serviceTemplate the service template
142      * @param heatFileData    the current heat file data
143      * @param parentHeatFileName the main heat to which associated current heat file (e.g. volume heat)
144      * @param context         the context
145      */
146     public void translateHeatFile(ServiceTemplate serviceTemplate, FileData heatFileData, String parentHeatFileName,
147                                   TranslationContext context) {
148         String heatFileName = heatFileData.getFile();
149         HeatOrchestrationTemplate heatOrchestrationTemplate = new YamlUtil()
150                 .yamlToObject(context.getFileContent(heatFileName), HeatOrchestrationTemplate.class);
151
152         translateInputParameters(serviceTemplate, heatOrchestrationTemplate, heatFileData, context,
153                 heatFileName, parentHeatFileName);
154         translateResources(heatFileName, serviceTemplate, heatOrchestrationTemplate, context);
155         translateOutputParameters(serviceTemplate, heatOrchestrationTemplate, heatFileData,
156                 heatFileName, context);
157         createHeatStackGroup(serviceTemplate, heatFileData, heatOrchestrationTemplate, context);
158         handleHeatPseudoParam(heatFileName, serviceTemplate, context);
159
160         if (Objects.nonNull(heatFileData.getData())) {
161             heatFileData.getData().stream().filter(data -> data.getType() == FileData.Type.HEAT_VOL)
162                     .forEach(data -> translateHeatFile(serviceTemplate, data, heatFileData.getFile(), context));
163         }
164     }
165
166     private void handleHeatPseudoParam(String heatFileName, ServiceTemplate serviceTemplate,
167                                        TranslationContext context) {
168         Map<String, String> translatedHeatPseudoParam =
169                 context.getUsedHeatPseudoParams().get(heatFileName);
170         if (Objects.nonNull(translatedHeatPseudoParam)) {
171             for (String heatPseudoParam : translatedHeatPseudoParam.keySet()) {
172                 if (!serviceTemplate.getTopology_template().getInputs().containsKey(heatPseudoParam)) {
173                     ParameterDefinition parameterDefinition = new ParameterDefinition();
174                     parameterDefinition.setType(PropertyType.STRING.getDisplayName());
175                     parameterDefinition.setRequired(false);
176                     String parameterDefinitionId = translatedHeatPseudoParam.get(heatPseudoParam);
177                     DataModelUtil.addInputParameterToTopologyTemplate(serviceTemplate, parameterDefinitionId,
178                             parameterDefinition);
179                 }
180             }
181         }
182     }
183
184     private void createHeatStackGroup(ServiceTemplate serviceTemplate, FileData heatFileData,
185                                       HeatOrchestrationTemplate heatOrchestrationTemplate,
186                                       TranslationContext context) {
187         ToscaFileOutputService toscaFileOutputService = new ToscaFileOutputServiceCsarImpl();
188         final String fileName = heatFileData.getFile();
189         final String heatStackGroupId = FileUtils.getFileWithoutExtention(fileName) + "_group";
190
191         GroupDefinition groupDefinition = new GroupDefinition();
192         groupDefinition.setType(ToscaGroupType.HEAT_STACK);
193         groupDefinition.setProperties(new HashMap<>());
194         groupDefinition.getProperties()
195                 .put("heat_file", "../" + toscaFileOutputService.getArtifactsFolderName() + "/" + fileName);
196         String hotDescription = heatOrchestrationTemplate.getDescription();
197         if (hotDescription != null && !hotDescription.isEmpty()) {
198             groupDefinition.getProperties().put(Constants.DESCRIPTION_PROPERTY_NAME, hotDescription);
199         }
200         groupDefinition.setMembers(new ArrayList<>());
201         Set<String> heatStackGroupMembersIds = getHeatStackGroupMembers(fileName,
202                 serviceTemplate, context);
203         if (CollectionUtils.isEmpty(heatStackGroupMembersIds)) {
204             return; //not creating a group when no resources are present in the heat input
205         }
206         groupDefinition.getMembers().addAll(heatStackGroupMembersIds);
207         DataModelUtil
208                 .addGroupDefinitionToTopologyTemplate(serviceTemplate, heatStackGroupId, groupDefinition);
209     }
210
211     private Set<String> getHeatStackGroupMembers(String heatFileName,
212                                                  ServiceTemplate serviceTemplate,
213                                                  TranslationContext context) {
214
215         Map<String, Set<String>> heatStackGroupMembers = context.getHeatStackGroupMembers();
216         Set<String> groupMembers = MapUtils.isEmpty(heatStackGroupMembers) ? new HashSet<>()
217                 : heatStackGroupMembers.get(heatFileName);
218
219         if (CollectionUtils.isEmpty(groupMembers)) {
220             return new HashSet<>();
221         }
222
223         Set<String> updatedMembersIds = new HashSet<>();
224
225         groupMembers.forEach(member -> {
226             if (Objects.nonNull(DataModelUtil.getNodeTemplate(serviceTemplate, member))) {
227                 updatedMembersIds.add(member);
228             } else {
229                 updateSubstitutableGroupMemberId(heatFileName, serviceTemplate, updatedMembersIds);
230             }
231         });
232
233         return updatedMembersIds;
234     }
235
236     private void updateSubstitutableGroupMemberId(String heatFileName,
237                                                   ServiceTemplate serviceTemplate,
238                                                   Set<String> updatedMembersIds) {
239         Optional<String> substitutableGroupMemberId =
240                 ToscaUtil.getSubstitutableGroupMemberId(heatFileName, serviceTemplate);
241
242         substitutableGroupMemberId.ifPresent(updatedMembersIds::add);
243     }
244
245     private void translateInputParameters(ServiceTemplate serviceTemplate,
246                                           HeatOrchestrationTemplate heatOrchestrationTemplate,
247                                           FileData heatFileData, TranslationContext context,
248                                           String heatFileName, String parentHeatFileName) {
249         if (heatOrchestrationTemplate.getParameters() == null) {
250             return;
251         }
252
253         Map<String, ParameterDefinition> parameterDefinitionMap =
254                 TranslatorHeatToToscaParameterConverter
255                         .parameterConverter(serviceTemplate, heatOrchestrationTemplate.getParameters(),
256                                 heatOrchestrationTemplate, heatFileName, parentHeatFileName, context);
257         Environment heatEnvFile = getHeatEnvFile(heatFileData, context);
258         Map<String, Object> parameters = heatEnvFile.getParameters();
259         Object parameterValue;
260         if (parameters != null) {
261             for (Map.Entry<String, ParameterDefinition> entry : parameterDefinitionMap.entrySet()) {
262                 String paramName = entry.getKey();
263                 parameterValue = parameters.get(paramName);
264                 if (parameterValue != null) {
265                     entry.getValue().set_default(TranslatorHeatToToscaParameterConverter
266                             .getToscaParameterDefaultValue(null, null, parameterValue, entry.getValue().getType(),
267                                     heatFileName, heatOrchestrationTemplate, context));
268                 }
269             }
270         }
271
272
273         Map<String, ParameterDefinition> inputs = serviceTemplate.getTopology_template().getInputs();
274         if (Objects.isNull(inputs)) {
275             serviceTemplate.getTopology_template().setInputs(parameterDefinitionMap);
276         } else {
277             setInputs(inputs, parameterDefinitionMap);
278
279         }
280
281     }
282
283     private void setInputs(Map<String, ParameterDefinition> inputs, Map<String, ParameterDefinition> newParameters) {
284
285         updateAnnotations(inputs, newParameters);
286         inputs.putAll(newParameters);
287
288     }
289
290     private void updateAnnotations(Map<String, ParameterDefinition> inputParameters, Map<String, ParameterDefinition> newParameters) {
291
292             newParameters.entrySet().stream().filter(stringParameterDefinitionEntry ->
293                     inputParameters.containsKey(stringParameterDefinitionEntry.getKey()) &&
294                          isHasAnnotation(inputParameters, stringParameterDefinitionEntry)).
295                             forEach(stringParameterDefinitionEntry -> {
296                                 List inputParamVFModuleList = getVFModulesList(inputParameters.get(stringParameterDefinitionEntry.getKey()));
297                                 List newParamVFModuleList = getVFModulesList(stringParameterDefinitionEntry.getValue());
298                                 if(inputParamVFModuleList.contains(newParamVFModuleList.get(0))){
299                                     newParamVFModuleList.remove(0);
300                                 }
301                                 newParamVFModuleList.addAll(inputParamVFModuleList);
302
303                             });
304
305     }
306
307     private boolean isHasAnnotation(Map<String, ParameterDefinition> inputParameters, Map.Entry<String, ParameterDefinition> newParameterSet) {
308         ParameterDefinitionExt inputParameter = (ParameterDefinitionExt) inputParameters.get(newParameterSet.getKey());
309         ParameterDefinitionExt newParameter = (ParameterDefinitionExt) newParameterSet.getValue();
310         return inputParameter.getAnnotations() != null && newParameter.getAnnotations() != null;
311     }
312
313     private List getVFModulesList(ParameterDefinition param) {
314         ParameterDefinitionExt parameterDefinitionExt = (ParameterDefinitionExt) param;
315         return (List) parameterDefinitionExt.getAnnotations().get(ToscaConstants.SOURCE_ANNOTATION_ID).getProperties().
316                 get(ToscaConstants.VF_MODULE_LABEL_PROPERTY_NAME);
317     }
318
319     private void translateOutputParameters(ServiceTemplate serviceTemplate,
320                                            HeatOrchestrationTemplate heatOrchestrationTemplate,
321                                            FileData heatFileData, String heatFileName,
322                                            TranslationContext context) {
323         if (heatOrchestrationTemplate.getOutputs() == null) {
324             return;
325         }
326         Map<String, ParameterDefinition> parameterDefinitionMap =
327                 TranslatorHeatToToscaParameterConverter
328                         .parameterOutputConverter(serviceTemplate, heatOrchestrationTemplate.getOutputs(),
329                                 heatOrchestrationTemplate, heatFileName, context);
330         if (serviceTemplate.getTopology_template().getOutputs() != null) {
331             serviceTemplate.getTopology_template().getOutputs().putAll(parameterDefinitionMap);
332         } else {
333             serviceTemplate.getTopology_template().setOutputs(parameterDefinitionMap);
334         }
335
336         if (heatFileData.getBase() != null && heatFileData.getBase().equals(true)) {
337             updateSharedResources(serviceTemplate, heatFileName, heatOrchestrationTemplate,
338                     heatOrchestrationTemplate.getOutputs(), context);
339         }
340     }
341
342     private void updateSharedResources(ServiceTemplate serviceTemplate, String heatFileName,
343                                        HeatOrchestrationTemplate heatOrchestrationTemplate,
344                                        Map<String, Output> outputs, TranslationContext context) {
345         for (Map.Entry<String, Output> parameter : outputs.entrySet()) {
346             Optional<AttachedResourceId> attachedSharedResourceId = HeatToToscaUtil
347                     .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
348                             parameter.getValue().getValue());
349             if (attachedSharedResourceId.isPresent() && attachedSharedResourceId.get().isGetResource()
350                     && attachedSharedResourceId.get().getTranslatedId() != null) {
351                 String sharedTranslatedResourceId =
352                         attachedSharedResourceId.get().getTranslatedId().toString();
353                 updateSharedResource(serviceTemplate, context, parameter, sharedTranslatedResourceId,
354                         heatOrchestrationTemplate.getResources()
355                                 .get(attachedSharedResourceId.get().getEntityId()));
356             } else {
357                 Optional<String> contrailSharedResourceId = HeatToToscaUtil
358                         .extractContrailGetResourceAttachedHeatResourceId(parameter.getValue().getValue());
359                 if (contrailSharedResourceId.isPresent()
360                         && context.getTranslatedIds().get(heatFileName).get(contrailSharedResourceId.get())
361                         != null) {
362                     String sharedTranslatedResourceId = context.getTranslatedIds().get(heatFileName).get
363                             (contrailSharedResourceId.get());
364                     ConsolidationDataUtil.removeSharedResource(serviceTemplate, heatOrchestrationTemplate,
365                             context, parameter.getKey(), contrailSharedResourceId.get(), sharedTranslatedResourceId);
366                     updateSharedResource(serviceTemplate, context, parameter, sharedTranslatedResourceId,
367                             heatOrchestrationTemplate.getResources().get(contrailSharedResourceId.get()));
368                 }
369             }
370         }
371         if (serviceTemplate.getTopology_template().getOutputs() != null
372                 && serviceTemplate.getTopology_template().getOutputs().size() == 0) {
373             serviceTemplate.getTopology_template().setOutputs(null);
374         }
375     }
376
377     private void updateSharedResource(ServiceTemplate serviceTemplate, TranslationContext context,
378                                       Map.Entry<String, Output> paramName,
379                                       String sharedTranslatedResourceId, Resource resource) {
380         context.addHeatSharedResourcesByParam(paramName.getKey(), sharedTranslatedResourceId, resource);
381         serviceTemplate.getTopology_template().getOutputs().remove(paramName.getKey());
382     }
383
384     private void translateResources(String heatFileName, ServiceTemplate serviceTemplate,
385                                     HeatOrchestrationTemplate heatOrchestrationTemplate,
386                                     TranslationContext context) {
387         if (MapUtils.isEmpty(heatOrchestrationTemplate.getResources())) {
388             return;
389         }
390
391         for (String resourceId : heatOrchestrationTemplate.getResources().keySet()) {
392             Resource resource = heatOrchestrationTemplate.getResources().get(resourceId);
393             if (resource == null) {
394                 throw new CoreException(
395                         new ResourceNotFoundInHeatFileErrorBuilder(resourceId, heatFileName).build());
396             }
397             ResourceTranslationFactory.getInstance(resource)
398                     .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, resource,
399                             resourceId, context);
400         }
401     }
402
403     private Environment getHeatEnvFile(FileData heatFileData, TranslationContext context) {
404         List<FileData> fileRelatedDataList = heatFileData.getData();
405         if (fileRelatedDataList == null) {
406             return new Environment();
407         }
408         for (FileData fileRelatedData : fileRelatedDataList) {
409             if (fileRelatedData.getType().equals(FileData.Type.HEAT_ENV)) {
410                 return new YamlUtil().yamlToObject(context.getFileContent(fileRelatedData.getFile()),
411                         Environment.class);
412             }
413         }
414         return new Environment();
415     }
416
417
418 }