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