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