c084a6b8761f7284deef290570d024b8ac583ea5
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.translator.services.heattotosca;
22
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.core.translator.datatypes.TranslatorOutput;
26 import org.openecomp.core.utilities.file.FileUtils;
27 import org.openecomp.sdc.common.errors.CoreException;
28 import org.openecomp.sdc.datatypes.error.ErrorLevel;
29 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
30 import org.openecomp.sdc.heat.datatypes.model.Environment;
31 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
32 import org.openecomp.sdc.heat.datatypes.model.Output;
33 import org.openecomp.sdc.heat.datatypes.model.Resource;
34 import org.openecomp.sdc.logging.api.Logger;
35 import org.openecomp.sdc.logging.api.LoggerFactory;
36 import org.openecomp.sdc.logging.types.LoggerConstants;
37 import org.openecomp.sdc.logging.types.LoggerErrorCode;
38 import org.openecomp.sdc.logging.types.LoggerErrorDescription;
39 import org.openecomp.sdc.logging.types.LoggerTragetServiceName;
40 import org.openecomp.sdc.tosca.datatypes.ToscaGroupType;
41 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
42 import org.openecomp.sdc.tosca.datatypes.model.GroupDefinition;
43 import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition;
44 import org.openecomp.sdc.tosca.datatypes.model.PropertyType;
45 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
46 import org.openecomp.sdc.tosca.datatypes.model.TopologyTemplate;
47 import org.openecomp.sdc.tosca.services.DataModelUtil;
48 import org.openecomp.sdc.tosca.services.ToscaConstants;
49 import org.openecomp.sdc.tosca.services.ToscaFileOutputService;
50 import org.openecomp.sdc.tosca.services.ToscaUtil;
51 import org.openecomp.sdc.tosca.services.YamlUtil;
52 import org.openecomp.sdc.tosca.services.impl.ToscaFileOutputServiceCsarImpl;
53 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedResourceId;
54 import org.openecomp.sdc.translator.datatypes.heattotosca.TranslationContext;
55 import org.openecomp.sdc.translator.datatypes.heattotosca.to.FileDataCollection;
56 import org.openecomp.sdc.translator.services.heattotosca.errors.ResourceNotFoundInHeatFileErrorBuilder;
57 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
58 import org.openecomp.sdc.translator.services.heattotosca.mapping.TranslatorHeatToToscaParameterConverter;
59
60 import java.util.ArrayList;
61 import java.util.HashMap;
62 import java.util.HashSet;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Objects;
66 import java.util.Optional;
67 import java.util.Set;
68
69 public class TranslationService {
70
71   protected static Logger logger = (Logger) LoggerFactory.getLogger(TranslationService.class);
72   /**
73    * Gets types to process by translator.
74    *
75    * @return the types to process by translator
76    */
77   public static Set<FileData.Type> getTypesToProcessByTranslator() {
78     Set<FileData.Type> types = new HashSet<>();
79     types.add(FileData.Type.HEAT);
80     types.add(FileData.Type.HEAT_VOL);
81     return types;
82   }
83
84   /**
85    * Translate heat files translator output.
86    *
87    * @param translationContext the translation context
88    * @return the translator output
89    */
90   public TranslatorOutput translateHeatFiles(TranslationContext translationContext) {
91     ServiceTemplate mainServiceTemplate = createMainServiceTemplate(translationContext);
92     List<FileData> fileDataList = translationContext.getManifest().getContent().getData();
93     FileDataCollection fileDataCollection = HeatToToscaUtil.getFileCollectionsByFilter(fileDataList,
94         TranslationService.getTypesToProcessByTranslator(), translationContext);
95
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
107     ToscaServiceModel toscaServiceModel =
108         HeatToToscaUtil.createToscaServiceModel(mainServiceTemplate, translationContext);
109
110     TranslatorOutput translatorOutput = new TranslatorOutput();
111     //Keeping a copy of tosca service model after first stage of translation for extraction of
112     // composition data
113     translatorOutput.setNonUnifiedToscaServiceModel(
114         ToscaServiceModel.getClonedServiceModel(toscaServiceModel));
115     translatorOutput.setToscaServiceModel(toscaServiceModel);
116     return translatorOutput;
117   }
118
119   private ServiceTemplate createMainServiceTemplate(TranslationContext translationContext) {
120     ServiceTemplate mainServiceTemplate = new ServiceTemplate();
121     translationContext.getTranslatedServiceTemplates()
122         .put(Constants.MAIN_TEMPLATE_NAME, mainServiceTemplate);
123     Map<String, String> templateMetadata = new HashMap<>();
124     templateMetadata.put(ToscaConstants.ST_METADATA_TEMPLATE_NAME, Constants.MAIN_TEMPLATE_NAME);
125     mainServiceTemplate.setTosca_definitions_version(ToscaConstants.TOSCA_DEFINITIONS_VERSION);
126     mainServiceTemplate.setMetadata(templateMetadata);
127     mainServiceTemplate.setTopology_template(new TopologyTemplate());
128     mainServiceTemplate.setImports(GlobalTypesGenerator.getGlobalTypesImportList());
129     return mainServiceTemplate;
130   }
131
132   /**
133    * Translate heat file.
134    *
135    * @param serviceTemplate the service template
136    * @param heatFileData    the heat file data
137    * @param context         the context
138    */
139   public void translateHeatFile(ServiceTemplate serviceTemplate, FileData heatFileData,
140                                 TranslationContext context) {
141     String heatFileName = heatFileData.getFile();
142     HeatOrchestrationTemplate heatOrchestrationTemplate = new YamlUtil()
143         .yamlToObject(context.getFileContent(heatFileName), HeatOrchestrationTemplate.class);
144
145     translateInputParameters(serviceTemplate, heatOrchestrationTemplate, heatFileData, context,
146         heatFileName);
147     translateResources(heatFileName, serviceTemplate, heatOrchestrationTemplate, context);
148     translateOutputParameters(serviceTemplate, heatOrchestrationTemplate, heatFileData,
149         heatFileName, context);
150     createHeatStackGroup(serviceTemplate, heatFileData, heatOrchestrationTemplate, context);
151     handleHeatPseudoParam(heatFileName, serviceTemplate, context);
152
153     if (Objects.nonNull(heatFileData.getData())) {
154       heatFileData.getData().stream().filter(data -> data.getType() == FileData.Type.HEAT_VOL)
155           .forEach(data -> translateHeatFile(serviceTemplate, data, context));
156     }
157   }
158
159   private void handleHeatPseudoParam(String heatFileName, ServiceTemplate serviceTemplate,
160                                      TranslationContext context) {
161     Map<String, String> translatedHeatPseudoParam =
162         context.getUsedHeatPseudoParams().get(heatFileName);
163     if (Objects.nonNull(translatedHeatPseudoParam)) {
164       for (String heatPseudoParam : translatedHeatPseudoParam.keySet()) {
165         if (!serviceTemplate.getTopology_template().getInputs().containsKey(heatPseudoParam)) {
166           ParameterDefinition parameterDefinition = new ParameterDefinition();
167           parameterDefinition.setType(PropertyType.STRING.getDisplayName());
168           parameterDefinition.setRequired(false);
169           String parameterDefinitionId = translatedHeatPseudoParam.get(heatPseudoParam);
170           DataModelUtil.addInputParameterToTopologyTemplate(serviceTemplate, parameterDefinitionId,
171               parameterDefinition);
172         }
173       }
174     }
175   }
176
177   private void createHeatStackGroup(ServiceTemplate serviceTemplate, FileData heatFileData,
178                                     HeatOrchestrationTemplate heatOrchestrationTemplate,
179                                     TranslationContext context) {
180     ToscaFileOutputService toscaFileOutputService = new ToscaFileOutputServiceCsarImpl();
181     final String fileName = heatFileData.getFile();
182     final String heatStackGroupId = FileUtils.getFileWithoutExtention(fileName) + "_group";
183
184     GroupDefinition groupDefinition = new GroupDefinition();
185     groupDefinition.setType(ToscaGroupType.HEAT_STACK);
186     groupDefinition.setProperties(new HashMap<>());
187     groupDefinition.getProperties()
188         .put("heat_file", "../" + toscaFileOutputService.getArtifactsFolderName() + "/" + fileName);
189     String hotDescription = heatOrchestrationTemplate.getDescription();
190     if (hotDescription != null && !hotDescription.isEmpty()) {
191       groupDefinition.getProperties().put(Constants.DESCRIPTION_PROPERTY_NAME, hotDescription);
192     }
193     groupDefinition.setMembers(new ArrayList<>());
194     Set<String> heatStackGroupMembersIds = getHeatStackGroupMembers(fileName,
195         serviceTemplate, context);
196     if (CollectionUtils.isEmpty(heatStackGroupMembersIds)) {
197       return; //not creating a group when no resources are present in the heat input
198     }
199     groupDefinition.getMembers().addAll(heatStackGroupMembersIds);
200     DataModelUtil
201         .addGroupDefinitionToTopologyTemplate(serviceTemplate, heatStackGroupId, groupDefinition);
202   }
203
204   private Set<String> getHeatStackGroupMembers(String heatFileName,
205                                                             ServiceTemplate serviceTemplate,
206                                                             TranslationContext context){
207
208     Map<String, Set<String>> heatStackGroupMembers = context.getHeatStackGroupMembers();
209     Set<String> groupMembers = MapUtils.isEmpty(heatStackGroupMembers) ? new HashSet<>()
210         : heatStackGroupMembers.get(heatFileName);
211
212     if(CollectionUtils.isEmpty(groupMembers)){
213       return new HashSet<>();
214     }
215
216     Set<String> updatedMembersIds = new HashSet<>();
217
218     groupMembers.forEach(member -> {
219       if (Objects.nonNull(DataModelUtil.getNodeTemplate(serviceTemplate, member))) {
220         updatedMembersIds.add(member);
221       } else {
222         updateSubstitutableGroupMemberId(heatFileName, serviceTemplate, updatedMembersIds);
223       }
224     });
225
226     return updatedMembersIds;
227   }
228
229   private void updateSubstitutableGroupMemberId(String heatFileName,
230                                                 ServiceTemplate serviceTemplate,
231                                                 Set<String> updatedMembersIds) {
232     Optional<String> substitutableGroupMemberId =
233         ToscaUtil.getSubstitutableGroupMemberId(heatFileName, serviceTemplate);
234
235     if (substitutableGroupMemberId.isPresent()) {
236       updatedMembersIds.add(substitutableGroupMemberId.get());
237     }
238   }
239
240   private void translateInputParameters(ServiceTemplate serviceTemplate,
241                                         HeatOrchestrationTemplate heatOrchestrationTemplate,
242                                         FileData heatFileData, TranslationContext context,
243                                         String heatFileName) {
244     if (heatOrchestrationTemplate.getParameters() == null) {
245       return;
246     }
247
248     Map<String, ParameterDefinition> parameterDefinitionMap =
249         TranslatorHeatToToscaParameterConverter
250             .parameterConverter(serviceTemplate,heatOrchestrationTemplate.getParameters(),
251                 heatOrchestrationTemplate, heatFileName, context);
252     Environment heatEnvFile = getHeatEnvFile(heatFileData, context);
253     Map<String, Object> parameters = heatEnvFile.getParameters();
254     Object parameterValue;
255     if (parameters != null) {
256       for (Map.Entry<String, ParameterDefinition> entry : parameterDefinitionMap.entrySet()) {
257         String paramName = entry.getKey();
258         parameterValue = parameters.get(paramName);
259         if (parameterValue != null) {
260           entry.getValue().set_default(TranslatorHeatToToscaParameterConverter
261               .getToscaParameterDefaultValue(null, null, parameterValue, entry.getValue().getType(),
262                   heatFileName, heatOrchestrationTemplate, context));
263         }
264       }
265     }
266
267     Map<String, ParameterDefinition> inputs = serviceTemplate.getTopology_template().getInputs();
268     if (Objects.isNull(inputs)) {
269       serviceTemplate.getTopology_template().setInputs(parameterDefinitionMap);
270     } else {
271       inputs.putAll(parameterDefinitionMap);
272     }
273   }
274
275   private void translateOutputParameters(ServiceTemplate serviceTemplate,
276                                          HeatOrchestrationTemplate heatOrchestrationTemplate,
277                                          FileData heatFileData, String heatFileName,
278                                          TranslationContext context) {
279     if (heatOrchestrationTemplate.getOutputs() == null) {
280       return;
281     }
282     Map<String, ParameterDefinition> parameterDefinitionMap =
283         TranslatorHeatToToscaParameterConverter
284             .parameterOutputConverter(serviceTemplate,heatOrchestrationTemplate.getOutputs(),
285                 heatOrchestrationTemplate, heatFileName, context);
286     if (serviceTemplate.getTopology_template().getOutputs() != null) {
287       serviceTemplate.getTopology_template().getOutputs().putAll(parameterDefinitionMap);
288     } else {
289       serviceTemplate.getTopology_template().setOutputs(parameterDefinitionMap);
290     }
291
292     if (heatFileData.getBase() != null && heatFileData.getBase().equals(true)) {
293       updateSharedResources(serviceTemplate, heatFileName, heatOrchestrationTemplate,
294           heatOrchestrationTemplate.getOutputs(), context);
295     }
296   }
297
298   private void updateSharedResources(ServiceTemplate serviceTemplate, String heatFileName,
299                                      HeatOrchestrationTemplate heatOrchestrationTemplate,
300                                      Map<String, Output> outputs, TranslationContext context) {
301     for (Map.Entry<String, Output> parameter : outputs.entrySet()) {
302       Optional<AttachedResourceId> attachedSharedResourceId = HeatToToscaUtil
303           .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
304               parameter.getValue().getValue());
305       if (attachedSharedResourceId.isPresent() && attachedSharedResourceId.get().isGetResource()
306           && attachedSharedResourceId.get().getTranslatedId() != null) {
307         String sharedTranslatedResourceId =
308             attachedSharedResourceId.get().getTranslatedId().toString();
309         updateSharedResource(serviceTemplate, context, parameter, sharedTranslatedResourceId,
310             heatOrchestrationTemplate.getResources()
311                 .get(attachedSharedResourceId.get().getEntityId()));
312       } else {
313         Optional<String> contrailSharedResourceId = HeatToToscaUtil
314             .extractContrailGetResourceAttachedHeatResourceId(parameter.getValue().getValue());
315         if (contrailSharedResourceId.isPresent()
316             && context.getTranslatedIds().get(heatFileName).get(contrailSharedResourceId.get())
317             != null) {
318           String sharedTranslatedResourceId = context.getTranslatedIds().get(heatFileName).get
319               (contrailSharedResourceId.get());
320           ConsolidationDataUtil.removeSharedResource(serviceTemplate, heatOrchestrationTemplate,
321               context, parameter.getKey(),contrailSharedResourceId.get(), sharedTranslatedResourceId);
322           updateSharedResource(serviceTemplate, context, parameter,sharedTranslatedResourceId,
323               heatOrchestrationTemplate.getResources().get(contrailSharedResourceId.get()));
324         }
325       }
326     }
327     if (serviceTemplate.getTopology_template().getOutputs() != null
328         && serviceTemplate.getTopology_template().getOutputs().size() == 0) {
329       serviceTemplate.getTopology_template().setOutputs(null);
330     }
331   }
332
333   private void updateSharedResource(ServiceTemplate serviceTemplate, TranslationContext context,
334                                     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,
341                                   HeatOrchestrationTemplate heatOrchestrationTemplate,
342                                   TranslationContext context) {
343     if(MapUtils.isEmpty(heatOrchestrationTemplate.getResources())){
344       return;
345     }
346
347     for (String resourceId : heatOrchestrationTemplate.getResources().keySet()) {
348       Resource resource = heatOrchestrationTemplate.getResources().get(resourceId);
349       if (resource == null) {
350         throw new CoreException(
351             new ResourceNotFoundInHeatFileErrorBuilder(resourceId, heatFileName).build());
352       }
353       ResourceTranslationFactory.getInstance(resource)
354           .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, resource,
355               resourceId, context);
356     }
357   }
358
359   private Environment getHeatEnvFile(FileData heatFileData, TranslationContext context) {
360     List<FileData> fileRelatedDataList = heatFileData.getData();
361     if (fileRelatedDataList == null) {
362       return new Environment();
363     }
364     for (FileData fileRelatedData : fileRelatedDataList) {
365       if (fileRelatedData.getType().equals(FileData.Type.HEAT_ENV)) {
366         return new YamlUtil().yamlToObject(context.getFileContent(fileRelatedData.getFile()),
367             Environment.class);
368       }
369     }
370     return new Environment();
371   }
372
373
374 }