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