2 * Copyright © 2016-2018 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.openecomp.sdc.translator.services.heattotosca.impl.resourcetranslation;
19 import org.apache.commons.collections4.CollectionUtils;
20 import org.apache.commons.collections4.MapUtils;
21 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
22 import org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes;
23 import org.openecomp.sdc.heat.datatypes.model.Resource;
24 import org.openecomp.sdc.heat.services.HeatConstants;
25 import org.openecomp.sdc.logging.api.Logger;
26 import org.openecomp.sdc.logging.api.LoggerFactory;
27 import org.openecomp.sdc.tosca.datatypes.ToscaCapabilityType;
28 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
29 import org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType;
30 import org.onap.sdc.tosca.datatypes.model.GroupDefinition;
31 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
32 import org.onap.sdc.tosca.datatypes.model.NodeType;
33 import org.onap.sdc.tosca.datatypes.model.RelationshipTemplate;
34 import org.onap.sdc.tosca.datatypes.model.RequirementAssignment;
35 import org.onap.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.PropertyRegexMatcher;
40 import org.openecomp.sdc.translator.datatypes.heattotosca.TranslationContext;
41 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslateTo;
42 import org.openecomp.sdc.translator.datatypes.heattotosca.to.TranslatedHeatResource;
43 import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.ComputeTemplateConsolidationData;
44 import org.openecomp.sdc.translator.services.heattotosca.ConsolidationDataUtil;
45 import org.openecomp.sdc.translator.services.heattotosca.Constants;
46 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
47 import org.openecomp.sdc.translator.services.heattotosca.NameExtractor;
48 import org.openecomp.sdc.translator.services.heattotosca.ResourceTranslationFactory;
49 import org.openecomp.sdc.translator.services.heattotosca.mapping.TranslatorHeatToToscaPropertyConverter;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collections;
54 import java.util.HashMap;
55 import java.util.List;
57 import java.util.Objects;
58 import java.util.Optional;
61 public class ResourceTranslationNovaServerImpl extends ResourceTranslationBase {
62 protected static Logger logger =
63 (Logger) LoggerFactory.getLogger(ResourceTranslationNovaServerImpl.class);
66 protected void translate(TranslateTo translateTo) {
67 TranslationContext context = translateTo.getContext();
68 Map<String, Object> properties = translateTo.getResource().getProperties();
69 String heatFileName = translateTo.getHeatFileName();
71 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
72 String nodeTypeRef = createLocalNodeType(serviceTemplate, translateTo.getResource(),
73 translateTo.getResourceId(), translateTo.getTranslatedId(), context);
75 //create compute in consolidation data
76 ConsolidationDataUtil.getComputeTemplateConsolidationData(context, serviceTemplate,
77 nodeTypeRef, translateTo.getTranslatedId());
79 NodeTemplate novaNodeTemplate = new NodeTemplate();
80 novaNodeTemplate.setType(nodeTypeRef);
81 HeatOrchestrationTemplate heatOrchestrationTemplate =
82 translateTo.getHeatOrchestrationTemplate();
83 novaNodeTemplate.setProperties(TranslatorHeatToToscaPropertyConverter
84 .getToscaPropertiesSimpleConversion(serviceTemplate, translateTo.getResourceId(),
85 properties, novaNodeTemplate.getProperties(), heatFileName,
86 heatOrchestrationTemplate, translateTo.getResource().getType(),
87 novaNodeTemplate, context));
89 HeatToToscaUtil.mapBoolean(novaNodeTemplate, HeatToToscaUtil
90 .getToscaPropertyName(translateTo, HeatConstants.CONFIG_DRIVE_PROPERTY_NAME));
92 manageNovaServerNetwork(translateTo, novaNodeTemplate);
93 manageNovaServerBlockDeviceMapping(translateTo, novaNodeTemplate);
94 manageNovaServerGroupMapping(translateTo, context, properties, heatFileName, serviceTemplate,
95 novaNodeTemplate, heatOrchestrationTemplate);
96 DataModelUtil.addNodeTemplate(serviceTemplate, translateTo.getTranslatedId(), novaNodeTemplate);
99 private void manageNovaServerGroupMapping(TranslateTo translateTo, TranslationContext context,
100 Map<String, Object> properties, String heatFileName,
101 ServiceTemplate serviceTemplate,
102 NodeTemplate novaNodeTemplate,
103 HeatOrchestrationTemplate heatOrchestrationTemplate) {
104 if (isSchedulerHintsPropExist(properties)) {
105 Object schedulerHints = properties.get("scheduler_hints");
106 if (schedulerHints instanceof Map) {
107 addServerGroupHintsToPoliciesGroups(translateTo, context, heatFileName, serviceTemplate,
108 novaNodeTemplate, heatOrchestrationTemplate, (Map<String, Object>) schedulerHints);
110 logger.warn("'scheduler_hints' property of resource '" + translateTo.getResourceId()
111 + "' is not valid. This property should be a map");
116 private void addServerGroupHintsToPoliciesGroups(TranslateTo translateTo,
117 TranslationContext context, String heatFileName,
118 ServiceTemplate serviceTemplate,
119 NodeTemplate novaNodeTemplate,
120 HeatOrchestrationTemplate
121 heatOrchestrationTemplate,
122 Map<String, Object> schedulerHints) {
123 for (Object hint : schedulerHints.values()) {
124 Optional<AttachedResourceId> attachedResourceId = HeatToToscaUtil
125 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context, hint);
126 if (attachedResourceId.isPresent()) {
127 AttachedResourceId serverGroupResourceId = attachedResourceId.get();
128 Object serverGroupResourceToTranslate = serverGroupResourceId.getEntityId();
129 if (serverGroupResourceId.isGetResource()) {
130 boolean isHintOfTypeNovaServerGroup =
131 isHintOfTypeNovaServerGroup(heatOrchestrationTemplate,
132 serverGroupResourceToTranslate);
133 if (isHintOfTypeNovaServerGroup) {
134 addNovaServerToPolicyGroup(translateTo, context, heatFileName, serviceTemplate,
135 heatOrchestrationTemplate, (String) serverGroupResourceToTranslate,
138 } else if (serverGroupResourceId.isGetParam()
139 && serverGroupResourceToTranslate instanceof String) {
140 TranslatedHeatResource
141 translatedServerGroupResource =
142 context.getHeatSharedResourcesByParam().get(serverGroupResourceToTranslate);
143 if (Objects.nonNull(translatedServerGroupResource)
144 && !HeatToToscaUtil.isHeatFileNested(translateTo, translateTo.getHeatFileName())
145 && isResourceTypeServerGroup(translatedServerGroupResource)) {
146 Map<String, GroupDefinition> groups =
147 serviceTemplate.getTopology_template().getGroups();
148 if(MapUtils.isNotEmpty(groups) && Objects.nonNull(groups.get(translatedServerGroupResource
149 .getTranslatedId()))) {
151 .get(translatedServerGroupResource.getTranslatedId()).getMembers()
152 .add(translateTo.getTranslatedId());
153 //Add group Id to compute consolidation data
154 updateComputeConsolidationDataGroup(translateTo, novaNodeTemplate,
155 translatedServerGroupResource.getTranslatedId());
163 private boolean isResourceTypeServerGroup(TranslatedHeatResource translatedServerGroupResource) {
164 return translatedServerGroupResource.getHeatResource().getType().equals(HeatResourcesTypes.NOVA_SERVER_GROUP_RESOURCE_TYPE.getHeatResource());
167 private void updateComputeConsolidationDataGroup(TranslateTo translateTo,
168 NodeTemplate novaNodeTemplate,
170 TranslationContext translationContext = translateTo.getContext();
171 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
172 ComputeTemplateConsolidationData computeTemplateConsolidationData = ConsolidationDataUtil
173 .getComputeTemplateConsolidationData(translationContext, serviceTemplate,
174 novaNodeTemplate.getType(),
175 translateTo.getTranslatedId());
176 ConsolidationDataUtil.updateGroupIdInConsolidationData(computeTemplateConsolidationData,
180 private boolean isHintOfTypeNovaServerGroup(HeatOrchestrationTemplate heatOrchestrationTemplate,
181 Object resourceToTranslate) {
182 return heatOrchestrationTemplate.getResources().get(resourceToTranslate).getType()
183 .equals(HeatResourcesTypes.NOVA_SERVER_GROUP_RESOURCE_TYPE.getHeatResource());
186 private void addNovaServerToPolicyGroup(TranslateTo translateTo, TranslationContext context,
187 String heatFileName, ServiceTemplate serviceTemplate,
188 HeatOrchestrationTemplate heatOrchestrationTemplate,
189 String resourceToTranslate,
190 NodeTemplate novaNodeTemplate) {
191 Resource serverGroup =
192 HeatToToscaUtil.getResource(heatOrchestrationTemplate, resourceToTranslate, heatFileName);
193 Optional<String> serverGroupTranslatedId = ResourceTranslationFactory.getInstance(serverGroup)
194 .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, serverGroup,
195 resourceToTranslate, context);
196 if (serverGroupTranslatedId.isPresent()) {
197 serviceTemplate.getTopology_template().getGroups().get(serverGroupTranslatedId.get())
198 .getMembers().add(translateTo.getTranslatedId());
199 updateComputeConsolidationDataGroup(translateTo, novaNodeTemplate,
200 serverGroupTranslatedId.get());
205 private boolean isSchedulerHintsPropExist(Map<String, Object> properties) {
206 return !MapUtils.isEmpty(properties) && Objects.nonNull(properties.get("scheduler_hints"));
209 private void manageNovaServerBlockDeviceMapping(TranslateTo translateTo,
210 NodeTemplate novaNodeTemplate) {
211 String heatFileName = translateTo.getHeatFileName();
212 TranslationContext context = translateTo.getContext();
213 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
214 Resource resource = translateTo.getResource();
215 String resourceId = translateTo.getResourceId();
216 String novaServerTranslatedId = translateTo.getTranslatedId();
217 HeatOrchestrationTemplate heatOrchestrationTemplate = translateTo
218 .getHeatOrchestrationTemplate();
219 List<Map<String, Object>> blockDeviceMappingList = getBlockDeviceMappingList(resource);
220 if (CollectionUtils.isEmpty(blockDeviceMappingList)) {
224 Object volumeIdObject;
225 Object snapshotIdObject;
226 String volumeResourceId;
228 for (Map<String, Object> blockDeviceMapping : blockDeviceMappingList) {
229 volumeIdObject = blockDeviceMapping.get("volume_id");
230 snapshotIdObject = blockDeviceMapping.get("snapshot_id");
232 if (volumeIdObject == null && snapshotIdObject == null) {
233 logger.warn("Resource '" + resourceId
234 + "' has block_device_mapping property with empty/missing volume_id and snapshot_id "
235 + "properties. Entry number "
236 + (index + 1) + ", this entry will be ignored in TOSCA translation.");
240 if (volumeIdObject == null) {
241 Optional<AttachedResourceId> attachedSnapshotId = HeatToToscaUtil
242 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
244 if (attachedSnapshotId.isPresent()) {
245 volumeResourceId = novaServerTranslatedId + "_" + attachedSnapshotId.get().getEntityId();
246 String deviceName = (String) blockDeviceMapping.get("device_name");
247 String relationshipId = novaServerTranslatedId + "_" + index;
249 createVolumeAttachesToRelationship(serviceTemplate, deviceName, novaServerTranslatedId,
250 volumeResourceId, relationshipId);
251 createCinderVolumeNodeTemplate(serviceTemplate, translateTo.getResourceId(),
252 volumeResourceId, heatFileName, blockDeviceMapping, heatOrchestrationTemplate,
254 connectNovaServerToVolume(novaNodeTemplate, volumeResourceId, relationshipId,
258 Optional<AttachedResourceId> attachedVolumeId = HeatToToscaUtil
259 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context,
261 if (attachedVolumeId.isPresent() && attachedVolumeId.get().isGetResource()) {
262 connectNovaServerToVolume(novaNodeTemplate,
263 (String) attachedVolumeId.get().getTranslatedId(), null, translateTo);
270 private void connectNovaServerToVolume(NodeTemplate novaNodeTemplate, String volumeResourceId,
271 String relationshipId, TranslateTo translateTo) {
272 RequirementAssignment requirementAssignment = new RequirementAssignment();
273 requirementAssignment.setCapability(ToscaCapabilityType.NATIVE_ATTACHMENT);
274 requirementAssignment.setNode(volumeResourceId);
275 if (relationshipId != null) {
276 requirementAssignment.setRelationship(relationshipId);
278 requirementAssignment
279 .setRelationship(ToscaRelationshipType.NATIVE_ATTACHES_TO);
282 .addRequirementAssignment(novaNodeTemplate, ToscaConstants.LOCAL_STORAGE_REQUIREMENT_ID,
283 requirementAssignment);
284 //Add volume consolidation data
285 ConsolidationDataUtil.updateComputeConsolidationDataVolumes(translateTo, novaNodeTemplate
286 .getType(), translateTo.getTranslatedId(), ToscaConstants.LOCAL_STORAGE_REQUIREMENT_ID,
287 requirementAssignment);
290 private void createCinderVolumeNodeTemplate(ServiceTemplate serviceTemplate, String resourceId,
291 String volumeResourceId, String heatFileName,
292 Map<String, Object> blockDeviceMapping,
293 HeatOrchestrationTemplate heatOrchestrationTemplate,
294 TranslationContext context) {
295 NodeTemplate cinderVolumeNodeTemplate = new NodeTemplate();
296 cinderVolumeNodeTemplate.setType(ToscaNodeType.CINDER_VOLUME);
297 cinderVolumeNodeTemplate.setProperties(TranslatorHeatToToscaPropertyConverter
298 .getToscaPropertiesSimpleConversion(serviceTemplate, resourceId, blockDeviceMapping, null,
299 heatFileName, heatOrchestrationTemplate,
300 HeatResourcesTypes.CINDER_VOLUME_RESOURCE_TYPE.getHeatResource(),
301 cinderVolumeNodeTemplate, context));
302 DataModelUtil.addNodeTemplate(serviceTemplate, volumeResourceId, cinderVolumeNodeTemplate);
305 private void createVolumeAttachesToRelationship(ServiceTemplate serviceTemplate,
306 String deviceName, String novaServerTranslatedId,
307 String volumeId, String relationshipId) {
308 RelationshipTemplate relationshipTemplate = new RelationshipTemplate();
309 relationshipTemplate.setType(ToscaRelationshipType.CINDER_VOLUME_ATTACHES_TO);
310 Map<String, Object> properties = new HashMap<>();
311 properties.put("instance_uuid", novaServerTranslatedId);
312 properties.put("volume_id", volumeId);
313 if (deviceName != null) {
314 properties.put("device", deviceName);
316 relationshipTemplate.setProperties(properties);
318 DataModelUtil.addRelationshipTemplate(serviceTemplate, relationshipId, relationshipTemplate);
321 private List<Map<String, Object>> getBlockDeviceMappingList(Resource resource) {
322 if (Objects.isNull(resource.getProperties())) {
323 return Collections.emptyList();
325 List<Map<String, Object>> blockDeviceMappingList =
326 (List<Map<String, Object>>) resource.getProperties().get("block_device_mapping");
327 List<Map<String, Object>> blockDeviceMappingV2List =
328 (List<Map<String, Object>>) resource.getProperties().get("block_device_mapping_v2");
330 if (blockDeviceMappingList != null && blockDeviceMappingV2List != null) {
331 blockDeviceMappingList.addAll(blockDeviceMappingV2List);
332 } else if (CollectionUtils.isEmpty(blockDeviceMappingList)
333 && CollectionUtils.isEmpty(blockDeviceMappingV2List)) {
337 blockDeviceMappingList =
338 blockDeviceMappingList != null ? blockDeviceMappingList : blockDeviceMappingV2List;
340 return blockDeviceMappingList;
343 private void manageNovaServerNetwork(TranslateTo translateTo,
344 NodeTemplate novaNodeTemplate) {
345 Resource resource = translateTo.getResource();
346 String translatedId = translateTo.getTranslatedId();
348 if (resource.getProperties() == null) {
351 Object networks = resource.getProperties().get("networks");
352 if(Objects.isNull(networks)
353 || !(networks instanceof List)){
357 List<Map<String, Object>> heatNetworkList =
358 (List<Map<String, Object>>) networks;
360 for (Map<String, Object> heatNetwork : heatNetworkList) {
361 getOrTranslatePortTemplate(translateTo, heatNetwork.get(
362 Constants.PORT_PROPERTY_NAME), translatedId, novaNodeTemplate);
366 private void getOrTranslatePortTemplate(TranslateTo translateTo,
368 String novaServerResourceId,
369 NodeTemplate novaNodeTemplate) {
370 String heatFileName = translateTo.getHeatFileName();
371 HeatOrchestrationTemplate heatOrchestrationTemplate = translateTo
372 .getHeatOrchestrationTemplate();
373 ServiceTemplate serviceTemplate = translateTo.getServiceTemplate();
374 TranslationContext context = translateTo.getContext();
376 Optional<AttachedResourceId> attachedPortId = HeatToToscaUtil
377 .extractAttachedResourceId(heatFileName, heatOrchestrationTemplate, context, port);
379 if (!attachedPortId.isPresent()) {
383 if (attachedPortId.get().isGetResource()) {
384 String resourceId = (String) attachedPortId.get().getEntityId();
385 Resource portResource =
386 HeatToToscaUtil.getResource(heatOrchestrationTemplate, resourceId, heatFileName);
387 if (!Arrays.asList(HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource(),
388 HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE.getHeatResource())
389 .contains(portResource.getType())) {
390 logger.warn("NovaServer connect to port resource with id : " + resourceId + " and type : "
391 + portResource.getType()
392 + ". This resource type is not supported, therefore the connection to the port is "
393 + "ignored. Supported types are: "
394 + HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource() + ", "
395 + HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE
398 } else if (HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE
399 .getHeatResource().equals(portResource.getType())) {
400 Map<String, Object> properties = portResource.getProperties();
401 if (!MapUtils.isEmpty(properties) && Objects.nonNull(properties.get("port_tuple_refs"))) {
402 novaNodeTemplate.getProperties().put("contrail_service_instance_ind", true);
405 Optional<String> translatedPortId = ResourceTranslationFactory.getInstance(portResource)
406 .translateResource(heatFileName, serviceTemplate, heatOrchestrationTemplate, portResource,
407 resourceId, context);
408 if (translatedPortId.isPresent()) {
409 NodeTemplate portNodeTemplate =
410 DataModelUtil.getNodeTemplate(serviceTemplate, translatedPortId.get());
411 DataModelUtil.addBindingReqFromPortToCompute(novaServerResourceId, portNodeTemplate);
414 ConsolidationDataUtil.updatePortInConsolidationData(translateTo, novaNodeTemplate.getType(), resourceId,
415 portResource.getType(), translatedPortId.get());
417 logger.warn("NovaServer connect to port resource with id : " + resourceId + " and type : "
418 + portResource.getType()
419 + ". This resource type is not supported, therefore the connection to the port is "
426 private String createLocalNodeType(ServiceTemplate serviceTemplate, Resource resource, String
428 String translatedId, TranslationContext context) {
429 NameExtractor nodeTypeNameExtractor = context.getNameExtractorImpl(resource.getType());
430 String nodeTypeName =
431 nodeTypeNameExtractor.extractNodeTypeName(resource, resourceId, translatedId);
433 if (!isNodeTypeCreated(serviceTemplate, nodeTypeName)) {
434 DataModelUtil.addNodeType(serviceTemplate, nodeTypeName, createNodeType());
440 * Get property Regx matcher list.
442 * @return Regex exprission per nova resource property, while nova node type name is consider when
443 * setting the name value.
445 public List<PropertyRegexMatcher> getPropertyRegexMatchersForNovaNodeType() {
446 List<PropertyRegexMatcher> propertyRegexMatchers = new ArrayList<>();
447 propertyRegexMatchers
448 .add(new PropertyRegexMatcher(Constants.NAME_PROPERTY_NAME,
449 Arrays.asList(".+_name$", ".+_names$", ".+_name_[0-9]+"), "_name"));
450 propertyRegexMatchers
451 .add(new PropertyRegexMatcher("image", Collections.singletonList(".+_image_name$"),
453 propertyRegexMatchers
454 .add(new PropertyRegexMatcher("flavor", Collections.singletonList(".+_flavor_name$"),
456 return propertyRegexMatchers;
459 private boolean isNodeTypeCreated(ServiceTemplate serviceTemplate, String nodeTypeName) {
460 return !MapUtils.isEmpty(serviceTemplate.getNode_types())
461 && Objects.nonNull(serviceTemplate.getNode_types().get(nodeTypeName));
464 private NodeType createNodeType() {
465 NodeType nodeType = new NodeType();
466 nodeType.setDerived_from(ToscaNodeType.NOVA_SERVER);