2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.translator.services.heattotosca.impl.resourcetranslation;
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
26 import org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes;
27 import org.openecomp.sdc.heat.datatypes.model.Resource;
28 import org.openecomp.sdc.heat.services.HeatConstants;
29 import org.openecomp.sdc.logging.api.Logger;
30 import org.openecomp.sdc.logging.api.LoggerFactory;
31 import org.openecomp.sdc.tosca.datatypes.ToscaCapabilityType;
32 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
33 import org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType;
34 import org.openecomp.sdc.tosca.datatypes.model.GroupDefinition;
35 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
36 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
37 import org.openecomp.sdc.tosca.datatypes.model.RelationshipTemplate;
38 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
39 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
40 import org.openecomp.sdc.tosca.services.DataModelUtil;
41 import org.openecomp.sdc.tosca.services.ToscaConstants;
42 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedResourceId;
43 import org.openecomp.sdc.translator.datatypes.heattotosca.PropertyRegexMatcher;
44 import org.openecomp.sdc.translator.datatypes.heattotosca.TranslationContext;
45 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslateTo;
46 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslatedHeatResource;
47 import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.ComputeTemplateConsolidationData;
48 import org.openecomp.sdc.translator.services.heattotosca.ConsolidationDataUtil;
49 import org.openecomp.sdc.translator.services.heattotosca.Constants;
50 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
51 import org.openecomp.sdc.translator.services.heattotosca.NameExtractor;
52 import org.openecomp.sdc.translator.services.heattotosca.ResourceTranslationFactory;
53 import org.openecomp.sdc.translator.services.heattotosca.mapping.TranslatorHeatToToscaPropertyConverter;
55 import java.util.ArrayList;
56 import java.util.Arrays;
57 import java.util.Collections;
58 import java.util.HashMap;
59 import java.util.List;
61 import java.util.Objects;
62 import java.util.Optional;
65 public class ResourceTranslationNovaServerImpl extends ResourceTranslationBase {
66 protected static Logger logger =
67 (Logger) LoggerFactory.getLogger(ResourceTranslationNovaServerImpl.class);
70 protected void translate(TranslateTo translateTo) {
71 TranslationContext context = translateTo.getContext();
72 Map<String, Object> properties = translateTo.getResource().getProperties();
73 String heatFileName = translateTo.getHeatFileName();
75 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
76 String nodeTypeRef = createLocalNodeType(serviceTemplate, translateTo.getResource(),
77 translateTo.getResourceId(), translateTo.getTranslatedId(), context);
79 //create compute in consolidation data
80 ConsolidationDataUtil.getComputeTemplateConsolidationData(context, serviceTemplate,
81 nodeTypeRef, translateTo.getTranslatedId());
83 NodeTemplate novaNodeTemplate = new NodeTemplate();
84 novaNodeTemplate.setType(nodeTypeRef);
85 HeatOrchestrationTemplate heatOrchestrationTemplate =
86 translateTo.getHeatOrchestrationTemplate();
87 novaNodeTemplate.setProperties(TranslatorHeatToToscaPropertyConverter
88 .getToscaPropertiesSimpleConversion(serviceTemplate, translateTo.getResourceId(),
89 properties, novaNodeTemplate.getProperties(), heatFileName,
90 heatOrchestrationTemplate, translateTo.getResource().getType(),
91 novaNodeTemplate, context));
93 HeatToToscaUtil.mapBoolean(novaNodeTemplate, HeatToToscaUtil
94 .getToscaPropertyName(translateTo, HeatConstants.CONFIG_DRIVE_PROPERTY_NAME));
96 manageNovaServerNetwork(translateTo, novaNodeTemplate);
97 manageNovaServerBlockDeviceMapping(translateTo, novaNodeTemplate);
98 manageNovaServerGroupMapping(translateTo, context, properties, heatFileName, serviceTemplate,
99 novaNodeTemplate, heatOrchestrationTemplate);
100 DataModelUtil.addNodeTemplate(serviceTemplate, translateTo.getTranslatedId(), novaNodeTemplate);
103 private void manageNovaServerGroupMapping(TranslateTo translateTo, TranslationContext context,
104 Map<String, Object> properties, String heatFileName,
105 ServiceTemplate serviceTemplate,
106 NodeTemplate novaNodeTemplate,
107 HeatOrchestrationTemplate heatOrchestrationTemplate) {
108 if (isSchedulerHintsPropExist(properties)) {
109 Object schedulerHints = properties.get("scheduler_hints");
110 if (schedulerHints instanceof Map) {
111 addServerGroupHintsToPoliciesGroups(translateTo, context, heatFileName, serviceTemplate,
112 novaNodeTemplate, heatOrchestrationTemplate, (Map<String, Object>) schedulerHints);
114 logger.warn("'scheduler_hints' property of resource '" + translateTo.getResourceId()
115 + "' is not valid. This property should be a map");
120 private void addServerGroupHintsToPoliciesGroups(TranslateTo translateTo,
121 TranslationContext context, String heatFileName,
122 ServiceTemplate serviceTemplate,
123 NodeTemplate novaNodeTemplate,
124 HeatOrchestrationTemplate
125 heatOrchestrationTemplate,
126 Map<String, Object> schedulerHints) {
127 for (Object hint : schedulerHints.values()) {
128 Optional<AttachedResourceId> attachedResourceId = HeatToToscaUtil
129 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context, hint);
130 if (attachedResourceId.isPresent()) {
131 AttachedResourceId serverGroupResourceId = attachedResourceId.get();
132 Object serverGroupResourceToTranslate = serverGroupResourceId.getEntityId();
133 if (serverGroupResourceId.isGetResource()) {
134 boolean isHintOfTypeNovaServerGroup =
135 isHintOfTypeNovaServerGroup(heatOrchestrationTemplate,
136 serverGroupResourceToTranslate);
137 if (isHintOfTypeNovaServerGroup) {
138 addNovaServerToPolicyGroup(translateTo, context, heatFileName, serviceTemplate,
139 heatOrchestrationTemplate, (String) serverGroupResourceToTranslate,
142 } else if (serverGroupResourceId.isGetParam()
143 && serverGroupResourceToTranslate instanceof String) {
144 TranslatedHeatResource
145 translatedServerGroupResource =
146 context.getHeatSharedResourcesByParam().get(serverGroupResourceToTranslate);
147 if (Objects.nonNull(translatedServerGroupResource)
148 && !HeatToToscaUtil.isHeatFileNested(translateTo, translateTo.getHeatFileName())
149 && isResourceTypeServerGroup(translatedServerGroupResource)) {
150 Map<String, GroupDefinition> groups =
151 serviceTemplate.getTopology_template().getGroups();
152 if(MapUtils.isNotEmpty(groups) && Objects.nonNull(groups.get(translatedServerGroupResource
153 .getTranslatedId()))) {
155 .get(translatedServerGroupResource.getTranslatedId()).getMembers()
156 .add(translateTo.getTranslatedId());
157 //Add group Id to compute consolidation data
158 updateComputeConsolidationDataGroup(translateTo, novaNodeTemplate,
159 translatedServerGroupResource.getTranslatedId());
167 private boolean isResourceTypeServerGroup(TranslatedHeatResource translatedServerGroupResource) {
168 return translatedServerGroupResource.getHeatResource().getType().equals(HeatResourcesTypes.NOVA_SERVER_GROUP_RESOURCE_TYPE.getHeatResource());
171 private void updateComputeConsolidationDataGroup(TranslateTo translateTo,
172 NodeTemplate novaNodeTemplate,
174 TranslationContext translationContext = translateTo.getContext();
175 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
176 ComputeTemplateConsolidationData computeTemplateConsolidationData = ConsolidationDataUtil
177 .getComputeTemplateConsolidationData(translationContext, serviceTemplate,
178 novaNodeTemplate.getType(),
179 translateTo.getTranslatedId());
180 ConsolidationDataUtil.updateGroupIdInConsolidationData(computeTemplateConsolidationData,
184 private boolean isHintOfTypeNovaServerGroup(HeatOrchestrationTemplate heatOrchestrationTemplate,
185 Object resourceToTranslate) {
186 return heatOrchestrationTemplate.getResources().get(resourceToTranslate).getType()
187 .equals(HeatResourcesTypes.NOVA_SERVER_GROUP_RESOURCE_TYPE.getHeatResource());
190 private void addNovaServerToPolicyGroup(TranslateTo translateTo, TranslationContext context,
191 String heatFileName, ServiceTemplate serviceTemplate,
192 HeatOrchestrationTemplate heatOrchestrationTemplate,
193 String resourceToTranslate,
194 NodeTemplate novaNodeTemplate) {
195 Resource serverGroup =
196 HeatToToscaUtil.getResource(heatOrchestrationTemplate, resourceToTranslate, heatFileName);
197 Optional<String> serverGroupTranslatedId = ResourceTranslationFactory.getInstance(serverGroup)
198 .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, serverGroup,
199 resourceToTranslate, context);
200 if (serverGroupTranslatedId.isPresent()) {
201 serviceTemplate.getTopology_template().getGroups().get(serverGroupTranslatedId.get())
202 .getMembers().add(translateTo.getTranslatedId());
203 updateComputeConsolidationDataGroup(translateTo, novaNodeTemplate,
204 serverGroupTranslatedId.get());
209 private boolean isSchedulerHintsPropExist(Map<String, Object> properties) {
210 return !MapUtils.isEmpty(properties) && Objects.nonNull(properties.get("scheduler_hints"));
213 private void manageNovaServerBlockDeviceMapping(TranslateTo translateTo,
214 NodeTemplate novaNodeTemplate) {
215 String heatFileName = translateTo.getHeatFileName();
216 TranslationContext context = translateTo.getContext();
217 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
218 Resource resource = translateTo.getResource();
219 String resourceId = translateTo.getResourceId();
220 String novaServerTranslatedId = translateTo.getTranslatedId();
221 HeatOrchestrationTemplate heatOrchestrationTemplate = translateTo
222 .getHeatOrchestrationTemplate();
223 List<Map<String, Object>> blockDeviceMappingList = getBlockDeviceMappingList(resource);
224 if (CollectionUtils.isEmpty(blockDeviceMappingList)) {
228 Object volumeIdObject;
229 Object snapshotIdObject;
230 String volumeResourceId;
232 for (Map<String, Object> blockDeviceMapping : blockDeviceMappingList) {
233 volumeIdObject = blockDeviceMapping.get("volume_id");
234 snapshotIdObject = blockDeviceMapping.get("snapshot_id");
236 if (volumeIdObject == null && snapshotIdObject == null) {
237 logger.warn("Resource '" + resourceId
238 + "' has block_device_mapping property with empty/missing volume_id and snapshot_id "
239 + "properties. Entry number "
240 + (index + 1) + ", this entry will be ignored in TOSCA translation.");
244 if (volumeIdObject == null) {
245 Optional<AttachedResourceId> attachedSnapshotId = HeatToToscaUtil
246 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
248 if (attachedSnapshotId.isPresent()) {
249 volumeResourceId = novaServerTranslatedId + "_" + attachedSnapshotId.get().getEntityId();
250 String deviceName = (String) blockDeviceMapping.get("device_name");
251 String relationshipId = novaServerTranslatedId + "_" + index;
253 createVolumeAttachesToRelationship(serviceTemplate, deviceName, novaServerTranslatedId,
254 volumeResourceId, relationshipId);
255 createCinderVolumeNodeTemplate(serviceTemplate, translateTo.getResourceId(),
256 volumeResourceId, heatFileName, blockDeviceMapping, heatOrchestrationTemplate,
258 connectNovaServerToVolume(novaNodeTemplate, volumeResourceId, relationshipId,
262 Optional<AttachedResourceId> attachedVolumeId = HeatToToscaUtil
263 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
265 if (attachedVolumeId.isPresent() && attachedVolumeId.get().isGetResource()) {
266 connectNovaServerToVolume(novaNodeTemplate,
267 (String) attachedVolumeId.get().getTranslatedId(), null, translateTo);
274 private void connectNovaServerToVolume(NodeTemplate novaNodeTemplate, String volumeResourceId,
275 String relationshipId, TranslateTo translateTo) {
276 RequirementAssignment requirementAssignment = new RequirementAssignment();
277 requirementAssignment.setCapability(ToscaCapabilityType.NATIVE_ATTACHMENT);
278 requirementAssignment.setNode(volumeResourceId);
279 if (relationshipId != null) {
280 requirementAssignment.setRelationship(relationshipId);
282 requirementAssignment
283 .setRelationship(ToscaRelationshipType.NATIVE_ATTACHES_TO);
286 .addRequirementAssignment(novaNodeTemplate, ToscaConstants.LOCAL_STORAGE_REQUIREMENT_ID,
287 requirementAssignment);
288 //Add volume consolidation data
289 ConsolidationDataUtil.updateComputeConsolidationDataVolumes(translateTo, novaNodeTemplate
290 .getType(), translateTo.getTranslatedId(), ToscaConstants.LOCAL_STORAGE_REQUIREMENT_ID,
291 requirementAssignment);
294 private void createCinderVolumeNodeTemplate(ServiceTemplate serviceTemplate, String resourceId,
295 String volumeResourceId, String heatFileName,
296 Map<String, Object> blockDeviceMapping,
297 HeatOrchestrationTemplate heatOrchestrationTemplate,
298 TranslationContext context) {
299 NodeTemplate cinderVolumeNodeTemplate = new NodeTemplate();
300 cinderVolumeNodeTemplate.setType(ToscaNodeType.CINDER_VOLUME);
301 cinderVolumeNodeTemplate.setProperties(TranslatorHeatToToscaPropertyConverter
302 .getToscaPropertiesSimpleConversion(serviceTemplate, resourceId, blockDeviceMapping, null,
303 heatFileName, heatOrchestrationTemplate,
304 HeatResourcesTypes.CINDER_VOLUME_RESOURCE_TYPE.getHeatResource(),
305 cinderVolumeNodeTemplate, context));
306 DataModelUtil.addNodeTemplate(serviceTemplate, volumeResourceId, cinderVolumeNodeTemplate);
309 private void createVolumeAttachesToRelationship(ServiceTemplate serviceTemplate,
310 String deviceName, String novaServerTranslatedId,
311 String volumeId, String relationshipId) {
312 RelationshipTemplate relationshipTemplate = new RelationshipTemplate();
313 relationshipTemplate.setType(ToscaRelationshipType.CINDER_VOLUME_ATTACHES_TO);
314 Map<String, Object> properties = new HashMap<>();
315 properties.put("instance_uuid", novaServerTranslatedId);
316 properties.put("volume_id", volumeId);
317 if (deviceName != null) {
318 properties.put("device", deviceName);
320 relationshipTemplate.setProperties(properties);
322 DataModelUtil.addRelationshipTemplate(serviceTemplate, relationshipId, relationshipTemplate);
325 private List<Map<String, Object>> getBlockDeviceMappingList(Resource resource) {
326 if (Objects.isNull(resource.getProperties())) {
327 return Collections.emptyList();
329 List<Map<String, Object>> blockDeviceMappingList =
330 (List<Map<String, Object>>) resource.getProperties().get("block_device_mapping");
331 List<Map<String, Object>> blockDeviceMappingV2List =
332 (List<Map<String, Object>>) resource.getProperties().get("block_device_mapping_v2");
334 if (blockDeviceMappingList != null && blockDeviceMappingV2List != null) {
335 blockDeviceMappingList.addAll(blockDeviceMappingV2List);
336 } else if (CollectionUtils.isEmpty(blockDeviceMappingList)
337 && CollectionUtils.isEmpty(blockDeviceMappingV2List)) {
341 blockDeviceMappingList =
342 blockDeviceMappingList != null ? blockDeviceMappingList : blockDeviceMappingV2List;
344 return blockDeviceMappingList;
347 private void manageNovaServerNetwork(TranslateTo translateTo,
348 NodeTemplate novaNodeTemplate) {
349 Resource resource = translateTo.getResource();
350 String translatedId = translateTo.getTranslatedId();
352 if (resource.getProperties() == null) {
355 Object networks = resource.getProperties().get("networks");
356 if(Objects.isNull(networks)
357 || !(networks instanceof List)){
361 List<Map<String, Object>> heatNetworkList =
362 (List<Map<String, Object>>) networks;
364 for (Map<String, Object> heatNetwork : heatNetworkList) {
365 getOrTranslatePortTemplate(translateTo, heatNetwork.get(
366 Constants.PORT_PROPERTY_NAME), translatedId, novaNodeTemplate);
370 private void getOrTranslatePortTemplate(TranslateTo translateTo,
372 String novaServerResourceId,
373 NodeTemplate novaNodeTemplate) {
374 String heatFileName = translateTo.getHeatFileName();
375 HeatOrchestrationTemplate heatOrchestrationTemplate = translateTo
376 .getHeatOrchestrationTemplate();
377 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
378 TranslationContext context = translateTo.getContext();
380 Optional<AttachedResourceId> attachedPortId = HeatToToscaUtil
381 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context, port);
383 if (!attachedPortId.isPresent()) {
387 if (attachedPortId.get().isGetResource()) {
388 String resourceId = (String) attachedPortId.get().getEntityId();
389 Resource portResource =
390 HeatToToscaUtil.getResource(heatOrchestrationTemplate, resourceId, heatFileName);
391 if (!Arrays.asList(HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource(),
392 HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE.getHeatResource())
393 .contains(portResource.getType())) {
394 logger.warn("NovaServer connect to port resource with id : " + resourceId + " and type : "
395 + portResource.getType()
396 + ". This resource type is not supported, therefore the connection to the port is "
397 + "ignored. Supported types are: "
398 + HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource() + ", "
399 + HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE
402 } else if (HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE
403 .getHeatResource().equals(portResource.getType())) {
404 Map<String, Object> properties = portResource.getProperties();
405 if (!MapUtils.isEmpty(properties) && Objects.nonNull(properties.get("port_tuple_refs"))) {
406 novaNodeTemplate.getProperties().put("contrail_service_instance_ind", true);
409 Optional<String> translatedPortId = ResourceTranslationFactory.getInstance(portResource)
410 .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, portResource,
411 resourceId, context);
412 if (translatedPortId.isPresent()) {
413 NodeTemplate portNodeTemplate =
414 DataModelUtil.getNodeTemplate(serviceTemplate, translatedPortId.get());
415 DataModelUtil.addBindingReqFromPortToCompute(novaServerResourceId, portNodeTemplate);
418 ConsolidationDataUtil.updatePortInConsolidationData(translateTo, novaNodeTemplate.getType(),
419 translatedPortId.get());
421 logger.warn("NovaServer connect to port resource with id : " + resourceId + " and type : "
422 + portResource.getType()
423 + ". This resource type is not supported, therefore the connection to the port is "
430 private String createLocalNodeType(ServiceTemplate serviceTemplate, Resource resource, String
432 String translatedId, TranslationContext context) {
433 NameExtractor nodeTypeNameExtractor = context.getNameExtractorImpl(resource.getType());
434 String nodeTypeName =
435 nodeTypeNameExtractor.extractNodeTypeName(resource, resourceId, translatedId);
437 if (!isNodeTypeCreated(serviceTemplate, nodeTypeName)) {
438 DataModelUtil.addNodeType(serviceTemplate, nodeTypeName, createNodeType());
444 * Get property Regx matcher list.
446 * @return Regex exprission per nova resource property, while nova node type name is consider when
447 * setting the name value.
449 public List<PropertyRegexMatcher> getPropertyRegexMatchersForNovaNodeType() {
450 List<PropertyRegexMatcher> propertyRegexMatchers = new ArrayList<>();
451 propertyRegexMatchers
452 .add(new PropertyRegexMatcher(Constants.NAME_PROPERTY_NAME,
453 Arrays.asList(".+_name$", ".+_names$", ".+_name_[0-9]+"), "_name"));
454 propertyRegexMatchers
455 .add(new PropertyRegexMatcher("image", Collections.singletonList(".+_image_name$"),
457 propertyRegexMatchers
458 .add(new PropertyRegexMatcher("flavor", Collections.singletonList(".+_flavor_name$"),
460 return propertyRegexMatchers;
463 private boolean isNodeTypeCreated(ServiceTemplate serviceTemplate, String nodeTypeName) {
464 return !MapUtils.isEmpty(serviceTemplate.getNode_types())
465 && Objects.nonNull(serviceTemplate.getNode_types().get(nodeTypeName));
468 private NodeType createNodeType() {
469 NodeType nodeType = new NodeType();
470 nodeType.setDerived_from(ToscaNodeType.NOVA_SERVER);