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