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