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;
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.tosca.datatypes.ToscaCapabilityType;
29 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
30 import org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType;
31 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
32 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
33 import org.openecomp.sdc.tosca.datatypes.model.RelationshipTemplate;
34 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
35 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
36 import org.openecomp.sdc.tosca.services.DataModelUtil;
37 import org.openecomp.sdc.tosca.services.ToscaConstants;
38 import org.openecomp.sdc.translator.datatypes.heattotosca.AttachedResourceId;
39 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslateTo;
40 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslatedHeatResource;
41 import org.openecomp.sdc.translator.services.heattotosca.Constants;
42 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
43 import org.openecomp.sdc.translator.services.heattotosca.ResourceTranslationFactory;
44 import org.openecomp.sdc.translator.services.heattotosca.TranslationContext;
45 import org.openecomp.sdc.translator.services.heattotosca.helper.NameExtractorService;
46 import org.openecomp.sdc.translator.services.heattotosca.helper.PropertyRegexMatcher;
47 import org.openecomp.sdc.translator.services.heattotosca.helper.impl.NameExtractorServiceImpl;
48 import org.openecomp.sdc.translator.services.heattotosca.mapping.TranslatorHeatToToscaPropertyConverter;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.Collections;
55 import java.util.HashMap;
56 import java.util.List;
58 import java.util.Objects;
59 import java.util.Optional;
61 public class ResourceTranslationNovaServerImpl extends ResourceTranslationBase {
62 protected static Logger logger = LoggerFactory.getLogger(ResourceTranslationNovaServerImpl.class);
65 protected void translate(TranslateTo translateTo) {
66 TranslationContext context = translateTo.getContext();
67 Map<String, Object> properties = translateTo.getResource().getProperties();
68 String heatFileName = translateTo.getHeatFileName();
70 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
73 createLocalNodeType(serviceTemplate, translateTo.getResource().getProperties(),
74 translateTo.getTranslatedId());
76 NodeTemplate novaNodeTemplate = new NodeTemplate();
77 novaNodeTemplate.setType(nodeTypeRef);
78 HeatOrchestrationTemplate heatOrchestrationTemplate =
79 translateTo.getHeatOrchestrationTemplate();
80 novaNodeTemplate.setProperties(TranslatorHeatToToscaPropertyConverter
81 .getToscaPropertiesSimpleConversion(properties, novaNodeTemplate.getProperties(),
82 heatFileName, heatOrchestrationTemplate, translateTo.getResource().getType(),
83 novaNodeTemplate, context));
85 manageNovaServerNetwork(heatFileName, serviceTemplate, heatOrchestrationTemplate,
86 translateTo.getResource(), translateTo.getTranslatedId(), context, novaNodeTemplate);
87 manageNovaServerBlockDeviceMapping(heatFileName, serviceTemplate, novaNodeTemplate,
88 heatOrchestrationTemplate, translateTo.getResource(), translateTo.getResourceId(),
89 translateTo.getTranslatedId(), context);
91 manageNovaServerGroupMapping(translateTo, context, properties, heatFileName, serviceTemplate,
92 heatOrchestrationTemplate);
93 DataModelUtil.addNodeTemplate(serviceTemplate, translateTo.getTranslatedId(), novaNodeTemplate);
96 private void manageNovaServerGroupMapping(TranslateTo translateTo, TranslationContext context,
97 Map<String, Object> properties, String heatFileName,
98 ServiceTemplate serviceTemplate,
99 HeatOrchestrationTemplate heatOrchestrationTemplate) {
100 if (isSchedulerHintsPropExist(properties)) {
101 Object schedulerHints = properties.get("scheduler_hints");
102 if (schedulerHints instanceof Map) {
103 addServerGroupHintsToPoliciesProups(translateTo, context, heatFileName, serviceTemplate,
104 heatOrchestrationTemplate, (Map<String, Object>) schedulerHints);
106 logger.warn("'scheduler_hints' property of resource '" + translateTo.getResourceId()
107 + "' is not valid. This property should be a map");
112 private void addServerGroupHintsToPoliciesProups(TranslateTo translateTo,
113 TranslationContext context, String heatFileName,
114 ServiceTemplate serviceTemplate,
115 HeatOrchestrationTemplate heatOrchestrationTemplate,
116 Map<String, Object> schedulerHints) {
117 for (Object hint : schedulerHints.values()) {
118 Optional<AttachedResourceId> attachedResourceId = HeatToToscaUtil
119 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context, hint);
120 if (attachedResourceId.isPresent()) {
121 AttachedResourceId serverGroupResourceId = attachedResourceId.get();
122 Object serverGroupResourceToTranslate = serverGroupResourceId.getEntityId();
123 if (serverGroupResourceId.isGetResource()) {
124 boolean isHintOfTypeNovaServerGroup =
125 isHintOfTypeNovaServerGroup(heatOrchestrationTemplate,
126 serverGroupResourceToTranslate);
127 if (isHintOfTypeNovaServerGroup) {
128 addNovaServerToPolicyGroup(translateTo, context, heatFileName, serviceTemplate,
129 heatOrchestrationTemplate, (String) serverGroupResourceToTranslate);
131 } else if (serverGroupResourceId.isGetParam()) {
132 TranslatedHeatResource translatedServerGroupResource =
133 context.getHeatSharedResourcesByParam().get(serverGroupResourceToTranslate);
134 if (Objects.nonNull(translatedServerGroupResource)
135 && !HeatToToscaUtil.isHeatFileNested(translateTo, translateTo.getHeatFileName())) {
136 serviceTemplate.getTopology_template().getGroups()
137 .get(translatedServerGroupResource.getTranslatedId()).getMembers()
138 .add(translateTo.getTranslatedId());
145 private boolean isHintOfTypeNovaServerGroup(HeatOrchestrationTemplate heatOrchestrationTemplate,
146 Object resourceToTranslate) {
147 return heatOrchestrationTemplate.getResources().get(resourceToTranslate).getType()
148 .equals(HeatResourcesTypes.NOVA_SERVER_GROUP_RESOURCE_TYPE.getHeatResource());
151 private void addNovaServerToPolicyGroup(TranslateTo translateTo, TranslationContext context,
152 String heatFileName, ServiceTemplate serviceTemplate,
153 HeatOrchestrationTemplate heatOrchestrationTemplate,
154 String resourceToTranslate) {
155 Resource serverGroup =
156 HeatToToscaUtil.getResource(heatOrchestrationTemplate, resourceToTranslate, heatFileName);
157 Optional<String> serverGroupTranslatedId = ResourceTranslationFactory.getInstance(serverGroup)
158 .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, serverGroup,
159 resourceToTranslate, context);
160 if (serverGroupTranslatedId.isPresent()) {
161 serviceTemplate.getTopology_template().getGroups().get(serverGroupTranslatedId.get())
162 .getMembers().add(translateTo.getTranslatedId());
166 private boolean isSchedulerHintsPropExist(Map<String, Object> properties) {
167 return !MapUtils.isEmpty(properties) && Objects.nonNull(properties.get("scheduler_hints"));
170 private void manageNovaServerBlockDeviceMapping(String heatFileName,
171 ServiceTemplate serviceTemplate,
172 NodeTemplate novaNodeTemplate,
173 HeatOrchestrationTemplate heatOrchestrationTemplate,
174 Resource resource, String resourceId,
175 String novaServerTranslatedId,
176 TranslationContext context) {
178 List<Map<String, Object>> blockDeviceMappingList = getBlockDeviceMappingList(resource);
179 if (CollectionUtils.isEmpty(blockDeviceMappingList)) {
183 Object volumeIdObject;
184 Object snapshotIdObject;
185 String volumeResourceId;
187 for (Map<String, Object> blockDeviceMapping : blockDeviceMappingList) {
188 volumeIdObject = blockDeviceMapping.get("volume_id");
189 snapshotIdObject = blockDeviceMapping.get("snapshot_id");
191 if (volumeIdObject == null && snapshotIdObject == null) {
192 logger.warn("Resource '" + resourceId
193 + "' has block_device_mapping property with empty/missing volume_id and snapshot_id "
194 + "properties. Entry number "
195 + (index + 1) + ", this entry will be ignored in TOSCA translation.");
199 if (volumeIdObject == null) {
200 String deviceName = (String) blockDeviceMapping.get("device_name");
201 String relationshipId = novaServerTranslatedId + "_" + index;
203 Optional<AttachedResourceId> attachedSnapshotId = HeatToToscaUtil
204 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
206 volumeResourceId = novaServerTranslatedId + "_" + attachedSnapshotId.get().getEntityId();
207 createVolumeAttachesToRelationship(serviceTemplate, deviceName, novaServerTranslatedId,
208 volumeResourceId, relationshipId);
209 createCinderVolumeNodeTemplate(serviceTemplate, volumeResourceId, heatFileName,
210 blockDeviceMapping, heatOrchestrationTemplate, context);
211 connectNovaServerToVolume(novaNodeTemplate, volumeResourceId, relationshipId);
213 Optional<AttachedResourceId> attachedVolumeId = HeatToToscaUtil
214 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
216 if (attachedVolumeId.get().isGetResource()) {
217 connectNovaServerToVolume(novaNodeTemplate,
218 (String) attachedVolumeId.get().getTranslatedId(), null);
225 private void connectNovaServerToVolume(NodeTemplate novaNodeTemplate, String volumeResourceId,
226 String relationshipId) {
227 RequirementAssignment requirementAssignment = new RequirementAssignment();
228 requirementAssignment.setCapability(ToscaCapabilityType.ATTACHMENT.getDisplayName());
229 requirementAssignment.setNode(volumeResourceId);
230 if (relationshipId != null) {
231 requirementAssignment.setRelationship(relationshipId);
233 requirementAssignment
234 .setRelationship(ToscaRelationshipType.NATIVE_ATTACHES_TO.getDisplayName());
237 .addRequirementAssignment(novaNodeTemplate, ToscaConstants.LOCAL_STORAGE_REQUIREMENT_ID,
238 requirementAssignment);
241 private void createCinderVolumeNodeTemplate(ServiceTemplate serviceTemplate,
242 String volumeResourceId, String heatFileName,
243 Map<String, Object> blockDeviceMapping,
244 HeatOrchestrationTemplate heatOrchestrationTemplate,
245 TranslationContext context) {
246 NodeTemplate cinderVolumeNodeTemplate = new NodeTemplate();
247 cinderVolumeNodeTemplate.setType(ToscaNodeType.CINDER_VOLUME.getDisplayName());
248 cinderVolumeNodeTemplate.setProperties(TranslatorHeatToToscaPropertyConverter
249 .getToscaPropertiesSimpleConversion(blockDeviceMapping, null, heatFileName,
250 heatOrchestrationTemplate,
251 HeatResourcesTypes.CINDER_VOLUME_RESOURCE_TYPE.getHeatResource(),
252 cinderVolumeNodeTemplate, context));
253 DataModelUtil.addNodeTemplate(serviceTemplate, volumeResourceId, cinderVolumeNodeTemplate);
256 private void createVolumeAttachesToRelationship(ServiceTemplate serviceTemplate,
257 String deviceName, String novaServerTranslatedId,
258 String volumeId, String relationshipId) {
259 RelationshipTemplate relationshipTemplate = new RelationshipTemplate();
260 relationshipTemplate.setType(ToscaRelationshipType.CINDER_VOLUME_ATTACHES_TO.getDisplayName());
261 Map<String, Object> properties = new HashMap<>();
262 properties.put("instance_uuid", novaServerTranslatedId);
263 properties.put("volume_id", volumeId);
264 if (deviceName != null) {
265 properties.put("device", deviceName);
267 relationshipTemplate.setProperties(properties);
269 DataModelUtil.addRelationshipTemplate(serviceTemplate, relationshipId, relationshipTemplate);
272 private List<Map<String, Object>> getBlockDeviceMappingList(Resource resource) {
274 if (Objects.isNull(resource.getProperties())) {
275 return Collections.emptyList();
277 List<Map<String, Object>> blockDeviceMappingList =
278 (List<Map<String, Object>>) resource.getProperties().get("block_device_mapping");
279 List<Map<String, Object>> blockDeviceMappingV2List =
280 (List<Map<String, Object>>) resource.getProperties().get("block_device_mapping_v2");
282 if (blockDeviceMappingList != null && blockDeviceMappingV2List != null) {
283 blockDeviceMappingList.addAll(blockDeviceMappingV2List);
284 } else if (CollectionUtils.isEmpty(blockDeviceMappingList)
285 && CollectionUtils.isEmpty(blockDeviceMappingV2List)) {
289 blockDeviceMappingList =
290 blockDeviceMappingList != null ? blockDeviceMappingList : blockDeviceMappingV2List;
292 return blockDeviceMappingList;
295 private void manageNovaServerNetwork(String heatFileName, ServiceTemplate serviceTemplate,
296 HeatOrchestrationTemplate heatOrchestrationTemplate,
297 Resource resource, String translatedId,
298 TranslationContext context, NodeTemplate novaNodeTemplate) {
300 if (resource.getProperties() == null) {
303 List<Map<String, Object>> heatNetworkList =
304 (List<Map<String, Object>>) resource.getProperties().get("networks");
306 if (CollectionUtils.isEmpty(heatNetworkList)) {
310 for (Map<String, Object> heatNetwork : heatNetworkList) {
311 getOrTranslatePortTemplate(heatFileName, heatOrchestrationTemplate,
312 heatNetwork.get(Constants.PORT_PROPERTY_NAME), serviceTemplate, translatedId, context,
318 private void getOrTranslatePortTemplate(String heatFileName,
319 HeatOrchestrationTemplate heatOrchestrationTemplate,
320 Object port, ServiceTemplate serviceTemplate,
321 String novaServerResourceId, TranslationContext context,
322 NodeTemplate novaNodeTemplate) {
323 Optional<AttachedResourceId> attachedPortId = HeatToToscaUtil
324 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context, port);
326 if (!attachedPortId.isPresent()) {
330 if (attachedPortId.get().isGetResource()) {
331 String resourceId = (String) attachedPortId.get().getEntityId();
332 Resource portResource =
333 HeatToToscaUtil.getResource(heatOrchestrationTemplate, resourceId, heatFileName);
334 if (!Arrays.asList(HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource(),
335 HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE.getHeatResource())
336 .contains(portResource.getType())) {
337 logger.warn("NovaServer connect to port resource with id : " + resourceId + " and type : "
338 + portResource.getType()
339 + ". This resource type is not supported, therefore the connection to the port is "
341 + "Supported types are: "
342 + HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource() + ", "
343 + HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE
346 } else if (HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE
347 .getHeatResource().equals(portResource.getType())) {
348 Map<String, Object> properties = portResource.getProperties();
349 if (!MapUtils.isEmpty(properties) && Objects.nonNull(properties.get("port_tuple_refs"))) {
350 novaNodeTemplate.getProperties().put("contrail_service_instance_ind", true);
353 Optional<String> translatedPortId = ResourceTranslationFactory.getInstance(portResource)
354 .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, portResource,
355 resourceId, context);
356 if (translatedPortId.isPresent()) {
357 NodeTemplate portNodeTemplate =
358 DataModelUtil.getNodeTemplate(serviceTemplate, translatedPortId.get());
359 addBindingReqFromPortToCompute(novaServerResourceId, portNodeTemplate);
361 logger.warn("NovaServer connect to port resource with id : " + resourceId + " and type : "
362 + portResource.getType()
363 + ". This resource type is not supported, therefore the connection to the port is "
370 * Create local node type string.
372 * @param serviceTemplate the service template
373 * @param properties the properties
374 * @param resourceTranslatedId the resource translated id
377 public String createLocalNodeType(ServiceTemplate serviceTemplate, Map<String, Object> properties,
378 String resourceTranslatedId) {
379 NameExtractorService nodeTypeNameExtractor = new NameExtractorServiceImpl();
380 List<PropertyRegexMatcher> propertyRegexMatchers =
381 getPropertiesAndRegexMatchers(nodeTypeNameExtractor);
382 Optional<String> extractedNodeTypeName = nodeTypeNameExtractor
383 .extractNodeTypeNameByPropertiesPriority(properties, propertyRegexMatchers);
385 String nodeTypeName = ToscaConstants.NODES_PREFIX
386 + (extractedNodeTypeName.isPresent() ? extractedNodeTypeName.get()
387 : resourceTranslatedId.replace(".", "_"));
388 if (!isNodeTypeCreated(serviceTemplate, nodeTypeName)) {
389 DataModelUtil.addNodeType(serviceTemplate, nodeTypeName, createNodeType());
394 private List<PropertyRegexMatcher> getPropertiesAndRegexMatchers(
395 NameExtractorService nodeTypeNameExtractor) {
396 List<PropertyRegexMatcher> propertyRegexMatchers = new ArrayList<>();
397 propertyRegexMatchers.add(nodeTypeNameExtractor
398 .getPropertyRegexMatcher(Constants.NAME_PROPERTY_NAME,
399 Arrays.asList(".+_name$", ".+_names$", ".+_name_[0-9]+"), "_name"));
400 propertyRegexMatchers.add(nodeTypeNameExtractor
401 .getPropertyRegexMatcher("image", Collections.singletonList(".+_image_name$"),
403 propertyRegexMatchers.add(nodeTypeNameExtractor
404 .getPropertyRegexMatcher("flavor", Collections.singletonList(".+_flavor_name$"),
406 return propertyRegexMatchers;
409 private boolean isNodeTypeCreated(ServiceTemplate serviceTemplate, String nodeTypeName) {
410 return !MapUtils.isEmpty(serviceTemplate.getNode_types())
411 && Objects.nonNull(serviceTemplate.getNode_types().get(nodeTypeName));
414 private NodeType createNodeType() {
415 NodeType nodeType = new NodeType();
416 nodeType.setDerived_from(ToscaNodeType.NOVA_SERVER.getDisplayName());