2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (c) 2019 Samsung
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
24 * This VNF Adapter implementation is based on the VDU Plugin model. It assumes that each VF Module definition in the
25 * MSO catalog is expressed via a set of template and/or file artifacts that are appropriate for some specific
26 * sub-orchestrator that provides an implementation of the VduPlugin interface. This adapter handles all of the common
27 * VF Module logic, including: - catalog lookups for artifact retrieval - parameter filtering and validation - base and
28 * volume module queries - rollback logic - logging and error handling
30 * Then based on the orchestration mode of the VNF, it will invoke different VDU plug-ins to perform the low level
31 * instantiations, deletions, and queries. At this time, the set of available plug-ins is hard-coded, though in the
32 * future a dynamic selection is expected (e.g. via a service-provider interface).
34 package org.onap.so.adapters.vnf;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
41 import java.util.Optional;
43 import javax.jws.WebService;
44 import javax.xml.ws.Holder;
45 import org.onap.so.logger.LoggingAnchor;
46 import org.onap.so.adapters.vdu.CloudInfo;
47 import org.onap.so.adapters.vdu.VduException;
48 import org.onap.so.adapters.vdu.VduInstance;
49 import org.onap.so.adapters.vdu.VduModelInfo;
50 import org.onap.so.adapters.vdu.VduPlugin;
51 import org.onap.so.adapters.vdu.VduStateType;
52 import org.onap.so.adapters.vdu.VduStatus;
53 import org.onap.so.adapters.vdu.mapper.VfModuleCustomizationToVduMapper;
54 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
55 import org.onap.so.adapters.vnf.exceptions.VnfException;
56 import org.onap.so.cloud.CloudConfig;
57 import org.onap.so.db.catalog.beans.CloudSite;
58 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
59 import org.onap.so.db.catalog.beans.HeatEnvironment;
60 import org.onap.so.db.catalog.beans.HeatTemplate;
61 import org.onap.so.db.catalog.beans.HeatTemplateParam;
62 import org.onap.so.db.catalog.beans.VfModule;
63 import org.onap.so.db.catalog.beans.VfModuleCustomization;
64 import org.onap.so.db.catalog.beans.VnfResource;
65 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
66 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
67 import org.onap.so.entity.MsoRequest;
68 import org.onap.so.logger.ErrorCode;
69 import org.onap.so.logger.MessageEnum;
70 import org.onap.so.openstack.beans.VnfRollback;
71 import org.onap.so.openstack.beans.VnfStatus;
72 import org.onap.so.openstack.exceptions.MsoException;
73 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
74 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
75 import org.onap.so.openstack.utils.MsoHeatUtils;
76 import org.onap.so.openstack.utils.MsoKeystoneUtils;
77 import org.onap.so.openstack.utils.MsoMulticloudUtils;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80 import org.springframework.beans.factory.annotation.Autowired;
81 import org.springframework.core.env.Environment;
82 import org.springframework.stereotype.Component;
83 import org.springframework.transaction.annotation.Transactional;
84 import com.fasterxml.jackson.core.JsonParseException;
85 import com.fasterxml.jackson.databind.JsonNode;
86 import com.fasterxml.jackson.databind.ObjectMapper;
88 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
89 targetNamespace = "http://org.onap.so/vnf")
92 public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
94 private static Logger logger = LoggerFactory.getLogger(MsoVnfPluginAdapterImpl.class);
96 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
97 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
100 protected CloudConfig cloudConfig;
103 private VFModuleCustomizationRepository vfModuleCustomRepo;
106 private Environment environment;
109 protected MsoKeystoneUtils keystoneUtils;
112 protected MsoCloudifyUtils cloudifyUtils;
115 protected MsoHeatUtils heatUtils;
118 protected MsoMulticloudUtils multicloudUtils;
121 protected VfModuleCustomizationToVduMapper vduMapper;
124 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
126 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
128 public MsoVnfPluginAdapterImpl() {
133 * Health Check web method. Does nothing but return to show the adapter is deployed.
136 public void healthCheck() {
137 logger.debug("Health check call in VNF Plugin Adapter");
141 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
145 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
146 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
147 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
148 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
149 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
150 logger.debug("CreateVNF command attempted but not supported");
151 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
155 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
159 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
160 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
161 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
162 throws VnfException {
163 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
164 logger.debug("UpdateVNF command attempted but not supported");
165 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
169 * This is the "Query VNF" web service implementation.
171 * This really should be QueryVfModule, but nobody ever changed it.
173 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
174 * also be reflected back as its ID.
176 * @param cloudSiteId CLLI code of the cloud site in which to query
177 * @param tenantId Openstack tenant identifier
178 * @param vnfNameOrId VNF Name or ID to query
179 * @param msoRequest Request tracking information for logs
180 * @param vnfExists Flag reporting the result of the query
181 * @param vnfId Holder for output VNF ID
182 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
185 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfNameOrId,
186 MsoRequest msoRequest, Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
187 Holder<Map<String, String>> outputs) throws VnfException {
188 logger.debug("Querying VNF " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
190 VduInstance vduInstance;
191 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
193 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
196 vduInstance = vduPlugin.queryVdu(cloudInfo, vnfNameOrId);
197 } catch (VduException e) {
198 // Failed to query the VDU due to a plugin exception.
199 // Convert to a generic VnfException
200 e.addContext("QueryVNF");
201 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
203 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfNameOrId, cloudOwner,
204 cloudSiteId, tenantId, "VDU", "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryVDU",
207 throw new VnfException(e);
210 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
211 vnfExists.value = Boolean.TRUE;
212 status.value = vduStatusToVnfStatus(vduInstance);
213 vnfId.value = vduInstance.getVduInstanceId();
214 outputs.value = copyStringOutputs(vduInstance.getOutputs());
216 logger.debug("VNF {} found, ID = {}", vnfNameOrId, vnfId.value);
218 vnfExists.value = Boolean.FALSE;
219 status.value = VnfStatus.NOTFOUND;
221 outputs.value = new HashMap<String, String>(); // Return as an empty map
223 logger.debug("VNF {} not found", vnfNameOrId);
230 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
234 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
235 throws VnfException {
237 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
238 logger.debug("DeleteVNF command attempted but not supported");
239 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
243 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
244 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
245 * to undo the creation.
247 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
250 public void rollbackVnf(VnfRollback rollback) throws VnfException {
251 // rollback may be null (e.g. if stack already existed when Create was called)
252 if (rollback == null) {
253 logger.info(LoggingAnchor.THREE, MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
257 // Don't rollback if nothing was done originally
258 if (!rollback.getVnfCreated()) {
262 // Get the elements of the VnfRollback object for easier access
263 String cloudSiteId = rollback.getCloudSiteId();
264 String cloudOwner = rollback.getCloudOwner();
265 String tenantId = rollback.getTenantId();
266 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
268 String vfModuleId = rollback.getVfModuleStackId();
270 logger.debug("Rolling Back VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
272 VduInstance vduInstance = null;
274 // Use the VduPlugin to delete the VF Module.
275 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
278 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
280 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
282 logger.debug("Rolled back VDU instantiation: {}", vduInstance.getVduInstanceId());
283 } catch (VduException ve) {
284 // Failed to rollback the VF Module due to a plugin exception.
285 // Convert to a generic VnfException
286 ve.addContext("RollbackVFModule");
287 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
288 + tenantId + ": " + ve;
289 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
290 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(), "Exception - DeleteVdu",
293 throw new VnfException(ve);
299 private VnfStatus vduStatusToVnfStatus(VduInstance vdu) {
300 // Determine the status based on last action & status
301 // DeploymentInfo object should be enhanced to report a better status internally.
302 VduStatus vduStatus = vdu.getStatus();
303 VduStateType status = vduStatus.getState();
305 if (status == null) {
306 return VnfStatus.UNKNOWN;
307 } else if (status == VduStateType.NOTFOUND) {
308 return VnfStatus.NOTFOUND;
309 } else if (status == VduStateType.INSTANTIATED) {
310 return VnfStatus.ACTIVE;
311 } else if (status == VduStateType.FAILED) {
312 return VnfStatus.FAILED;
315 return VnfStatus.UNKNOWN;
319 * Normalize an input value to an Object, based on the target parameter type. If the type is not recognized, it will
320 * just be returned unchanged (as a string).
322 private Object convertInputValue(Object inputValue, HeatTemplateParam templateParam) {
323 String type = templateParam.getParamType();
324 logger.debug("Parameter: {} is of type ", templateParam.getParamName(), type);
326 if (type.equalsIgnoreCase("number")) {
328 return Integer.valueOf(inputValue.toString());
329 } catch (Exception e) {
330 logger.debug("Unable to convert " + inputValue + " to an integer!", e);
333 } else if ("json".equalsIgnoreCase(type)) {
335 JsonNode jsonNode = JSON_MAPPER.readTree(JSON_MAPPER.writeValueAsString(inputValue));
337 } catch (Exception e) {
338 logger.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
341 } else if ("boolean".equalsIgnoreCase(type)) {
342 return new Boolean(inputValue.toString());
345 // Nothing else matched. Return the original string
349 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
350 Map<String, String> stringOutputs = new HashMap<>();
351 for (String key : stackOutputs.keySet()) {
352 if (stackOutputs.get(key) instanceof String) {
353 stringOutputs.put(key, (String) stackOutputs.get(key));
354 } else if (stackOutputs.get(key) instanceof Integer) {
356 String str = "" + stackOutputs.get(key);
357 stringOutputs.put(key, str);
358 } catch (Exception e) {
359 logger.debug("Unable to add {} to outputs", key, e);
361 } else if (stackOutputs.get(key) instanceof JsonNode) {
363 String str = this.convertNode((JsonNode) stackOutputs.get(key));
364 stringOutputs.put(key, str);
365 } catch (Exception e) {
366 logger.debug("Unable to add {} to outputs - exception converting JsonNode", key, e);
368 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
370 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
371 stringOutputs.put(key, str);
372 } catch (Exception e) {
373 logger.debug("Unable to add {} to outputs - exception converting LinkedHashMap", key, e);
377 String str = stackOutputs.get(key).toString();
378 stringOutputs.put(key, str);
379 } catch (Exception e) {
380 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),
385 return stringOutputs;
389 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
391 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
392 if (inputs == null) {
394 } else if (inputs.size() < 1) {
395 sb.append("\tEMPTY");
397 for (String str : inputs.keySet()) {
400 outputString = inputs.get(str).toString();
401 } catch (Exception e) {
402 outputString = "Unable to call toString() on the value for " + str;
404 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
407 logger.debug(sb.toString());
411 private void sendMapToDebug(Map<String, Object> inputs) {
413 StringBuilder sb = new StringBuilder("inputs:");
414 if (inputs == null) {
416 } else if (inputs.size() < 1) {
417 sb.append("\tEMPTY");
419 for (String str : inputs.keySet()) {
420 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
423 logger.debug(sb.toString());
427 private String convertNode(final JsonNode node) {
429 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
430 final String json = JSON_MAPPER.writeValueAsString(obj);
432 } catch (JsonParseException jpe) {
433 logger.debug("Error converting json to string " + jpe.getMessage());
434 } catch (Exception e) {
435 logger.debug("Error converting json to string " + e.getMessage());
437 return "[Error converting json to string]";
440 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
441 if (objectMap == null) {
444 Map<String, String> stringMap = new HashMap<>();
445 for (String key : objectMap.keySet()) {
446 if (!stringMap.containsKey(key)) {
447 Object obj = objectMap.get(key);
448 if (obj instanceof String) {
449 stringMap.put(key, (String) objectMap.get(key));
450 } else if (obj instanceof JsonNode) {
451 // This is a bit of mess - but I think it's the least impacting
452 // let's convert it BACK to a string - then it will get converted back later
454 String str = this.convertNode((JsonNode) obj);
455 stringMap.put(key, str);
456 } catch (Exception e) {
457 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
458 // okay in this instance - only string values (fqdn) are expected to be needed
460 } else if (obj instanceof java.util.LinkedHashMap) {
461 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
463 String str = JSON_MAPPER.writeValueAsString(obj);
464 stringMap.put(key, str);
465 } catch (Exception e) {
466 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
468 } else if (obj instanceof Integer) {
470 String str = "" + obj;
471 stringMap.put(key, str);
472 } catch (Exception e) {
473 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
477 String str = obj.toString();
478 stringMap.put(key, str);
479 } catch (Exception e) {
481 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")",
492 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
493 * type in the specified cloud and tenant. The tenant must exist before this service is called.
495 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
496 * value of the 'failIfExists' parameter.
498 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
499 * error will be returned. Within the catalog, each VF Module references (among other things) a collection of
500 * artifacts that are used to deploy the required cloud resources (VMs, networks, etc.).
502 * Depending on the module templates, a variable set of input parameters will be defined, some of which are
503 * required. The caller is responsible to pass the necessary input data for the module or an error will be thrown.
505 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
506 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
507 * VF module is successfully created but the orchestration fails on a subsequent step.
509 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
510 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
511 * @param tenantId Openstack tenant identifier
512 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
513 * modelCustomizationUuid
514 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
515 * also captured by modelCustomizationUuid
516 * @param vnfId - VNF ID
517 * @param vfModuleName Name to be assigned to the new VF Module
518 * @param vfModuleId Id fo the new VF Module
519 * @param requestType Indicates if this is a Volume Group or Module request
520 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
521 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
522 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
523 * @param inputs Map of key=value inputs for VNF stack creation
524 * @param failIfExists Flag whether already existing VNF should be considered
525 * @param backout Flag whether to suppress automatic backout (for testing)
526 * @param msoRequest Request tracking information for logs
527 * @param vnfId Holder for output VF Module instance ID in the cloud
528 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
529 * @param rollback Holder for returning VnfRollback object
532 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
533 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
534 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
535 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
536 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
538 // Require a model customization ID. Every VF Module definition must have one.
539 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
540 logger.debug("Missing required input: modelCustomizationUuid");
541 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
542 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
543 "VF Module ModelCustomizationUuid", "VDU", ErrorCode.DataError,
544 "Create VF Module: " + "Missing required input: modelCustomizationUuid");
546 throw new VnfException(error, MsoExceptionCategory.USERDATA);
549 // Clean up some inputs to make comparisons easier
550 if (requestType == null)
553 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
554 volumeGroupId = null;
556 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
557 baseVfModuleId = null;
559 if (inputs == null) {
560 // Create an empty set of inputs
561 inputs = new HashMap<>();
562 logger.debug("inputs == null - setting to empty");
564 this.sendMapToDebug(inputs);
567 // Check if this is for a "Volume" module
568 boolean isVolumeRequest = false;
569 if (requestType.startsWith("VOLUME")) {
570 isVolumeRequest = true;
573 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
576 // Build a default rollback object (no actions performed)
577 VnfRollback vfRollback = new VnfRollback();
578 vfRollback.setCloudSiteId(cloudSiteId);
579 vfRollback.setCloudOwner(cloudOwner);
580 vfRollback.setTenantId(tenantId);
581 vfRollback.setMsoRequest(msoRequest);
582 vfRollback.setRequestType(requestType);
583 vfRollback.setIsBase(false); // Until we know better
584 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
585 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
586 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
587 vfRollback.setMode("CFY");
589 rollback.value = vfRollback; // Default rollback - no updates performed
591 // Get the VNF/VF Module definition from the Catalog DB first.
592 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
594 VfModule vfModule = null;
595 VnfResource vnfResource = null;
596 VfModuleCustomization vfModuleCust = null;
600 vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
602 if (vfModuleCust == null) {
603 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
604 + modelCustomizationUuid;
606 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
607 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", ErrorCode.DataError,
609 throw new VnfException(error, MsoExceptionCategory.USERDATA);
611 logger.debug("Found vfModuleCust entry {}", vfModuleCust.toString());
614 // Get the vfModule and vnfResource records
615 vfModule = vfModuleCust.getVfModule();
616 vnfResource = vfModuleCust.getVfModule().getVnfResources();
617 } catch (Exception e) {
619 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
620 throw new VnfException("Exception during create VF " + e.getMessage());
623 // Perform a version check against cloudSite
624 // Obtain the cloud site information where we will create the VF Module
625 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
626 if (!cloudSiteOp.isPresent()) {
627 // If cloudSiteId is not present in the catalog DB, then default to multicloud
628 logger.debug("{} is not present in cloud_site catalog DB, defaulting to Multicloud plugin adapter",
631 CloudSite cloudSite = cloudSiteOp.get();
632 MavenLikeVersioning aicV = new MavenLikeVersioning();
633 aicV.setVersion(cloudSite.getCloudVersion());
635 String vnfMin = vnfResource.getAicVersionMin();
636 String vnfMax = vnfResource.getAicVersionMax();
638 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
639 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
642 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
643 + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: "
644 + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
645 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
646 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
648 throw new VnfException(error, MsoExceptionCategory.USERDATA);
654 VduInstance vduInstance = null;
655 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
657 // Use the VduPlugin.
658 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
661 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleName);
662 } catch (VduException me) {
663 // Failed to query the VDU due to a plugin exception.
664 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
665 + tenantId + ": " + me;
666 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
667 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(), "Exception - queryVdu",
670 // Convert to a generic VnfException
671 me.addContext("CreateVFModule");
672 throw new VnfException(me);
675 // More precise handling/messaging if the Module already exists
676 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
677 VduStateType status = vduInstance.getStatus().getState();
678 logger.debug("Found Existing VDU, status=" + status);
680 if (status == VduStateType.INSTANTIATED) {
681 if (failIfExists != null && failIfExists) {
683 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
684 + cloudSiteId + "/" + tenantId;
685 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
686 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
687 "VF Module " + vfModuleName + " already exists");
689 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
690 vduInstance.getVduInstanceId());
692 // Found existing deployment and client has not requested "failIfExists".
693 // Populate the outputs from the existing deployment.
695 vnfId.value = vduInstance.getVduInstanceId();
696 outputs.value = copyStringOutputs(vduInstance.getOutputs());
700 // Check through various detailed error cases
701 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING
702 || status == VduStateType.UPDATING) {
703 // fail - it's in progress - return meaningful error
704 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
705 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
706 + "; please wait for it to complete, or fix manually.";
707 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
708 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
709 "VF Module " + vfModuleName + " already exists");
711 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
712 vduInstance.getVduInstanceId());
713 } else if (status == VduStateType.FAILED) {
714 // fail - it exists and is in a FAILED state
715 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
716 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
717 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
718 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
719 "VF Module " + vfModuleName + " already exists and is in FAILED state");
721 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
722 vduInstance.getVduInstanceId());
723 } else if (status == VduStateType.UNKNOWN) {
724 // fail - it exists and is in a UNKNOWN state
725 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
726 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
727 + "; requires manual intervention.";
728 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
729 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
730 "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state");
732 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
733 vduInstance.getVduInstanceId());
735 // Unexpected, since all known status values have been tested for
736 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
737 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
738 + "; requires manual intervention.";
739 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
740 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
741 "VF Module " + vfModuleName + " already exists and is in an unknown state");
743 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
744 vduInstance.getVduInstanceId());
749 // Collect outputs from Base Modules and Volume Modules
750 Map<String, Object> baseModuleOutputs = null;
751 Map<String, Object> volumeGroupOutputs = null;
753 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
754 if (volumeGroupId != null) {
755 VduInstance volumeVdu;
757 volumeVdu = vduPlugin.queryVdu(cloudInfo, volumeGroupId);
758 } catch (VduException me) {
759 // Failed to query the Volume Group VDU due to a plugin exception.
760 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
761 + cloudSiteId + "/" + tenantId + ": " + me;
762 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner,
763 cloudSiteId, tenantId, "VDU", "queryVdu(volume)", ErrorCode.DataError.getValue(),
764 "Exception - queryVdu(volume)", me);
766 // Convert to a generic VnfException
767 me.addContext("CreateVFModule(QueryVolume)");
768 throw new VnfException(me);
771 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
772 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
773 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
774 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner,
775 cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)",
776 ErrorCode.BusinessProcesssError.getValue(),
777 "Create VFModule: Attached Volume Group " + "DOES NOT EXIST");
779 throw new VnfException(error, MsoExceptionCategory.USERDATA);
781 logger.debug("Found nested volume group");
782 volumeGroupOutputs = volumeVdu.getOutputs();
783 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
787 // If this is an Add-On Module, query the Base Module outputs
788 // Note: This will be performed whether or not the current request is for an
789 // Add-On Volume Group or Add-On VF Module
791 if (vfModule.getIsBase()) {
792 logger.debug("This is a BASE Module request");
793 vfRollback.setIsBase(true);
795 logger.debug("This is an Add-On Module request");
797 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
798 // Add-on Volume requests may or may not specify a base.
799 if (!isVolumeRequest && baseVfModuleId == null) {
800 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
803 if (baseVfModuleId != null) {
806 baseVdu = vduPlugin.queryVdu(cloudInfo, baseVfModuleId);
807 } catch (MsoException me) {
808 // Failed to query the Base VF Module due to a Vdu Plugin exception.
809 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
810 + cloudSiteId + "/" + tenantId + ": " + me;
811 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
812 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", ErrorCode.DataError.getValue(),
813 "Exception - queryVdu(Base)", me);
815 // Convert to a generic VnfException
816 me.addContext("CreateVFModule(QueryBase)");
817 throw new VnfException(me);
820 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
821 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudOwner
822 + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
823 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudOwner,
824 cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)",
825 ErrorCode.BusinessProcesssError.getValue(), "Create VFModule: Base Module DOES NOT EXIST");
827 throw new VnfException(error, MsoExceptionCategory.USERDATA);
829 logger.debug("Found base module");
830 baseModuleOutputs = baseVdu.getOutputs();
831 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
837 // NOTE: For this section, heatTemplate is used for all template artifacts.
838 // In final implementation (post-POC), the template object would either be generic or there would
839 // be a separate DB Table/Object for different sub-orchestrators.
841 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
843 HeatTemplate heatTemplate = null;
844 HeatEnvironment heatEnvironment = null;
845 if (isVolumeRequest) {
846 heatTemplate = vfModule.getVolumeHeatTemplate();
847 heatEnvironment = vfModuleCust.getVolumeHeatEnv();
849 heatTemplate = vfModule.getModuleHeatTemplate();
850 heatEnvironment = vfModuleCust.getHeatEnvironment();
853 if (heatTemplate == null) {
854 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
855 + ", modelCustomizationUuid=" + modelCustomizationUuid + ", vfModuleUuid=" + vfModule.getModelUUID()
856 + ", reqType=" + requestType;
857 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
858 vfModuleType, "VNF", ErrorCode.DataError.getValue(), error);
860 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
862 logger.debug("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
865 if (heatEnvironment == null) {
866 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + ", modelCustomizationUuid="
867 + modelCustomizationUuid + ", vfModuleUuid=" + vfModule.getModelUUID() + ", reqType=" + requestType;
868 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
869 "OpenStack", ErrorCode.DataError.getValue(), error);
870 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
872 logger.debug("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
876 // Create the combined set of parameters from the incoming request, base-module outputs,
877 // volume-module outputs. Also, convert all variables to their native object types.
879 HashMap<String, Object> goldenInputs = new HashMap<>();
880 List<String> extraInputs = new ArrayList<>();
882 Boolean skipInputChecks = false;
884 if (skipInputChecks) {
885 goldenInputs = new HashMap<>();
886 for (String key : inputs.keySet()) {
887 goldenInputs.put(key, inputs.get(key));
890 // Build maps for the parameters (including aliases) to simplify checks
891 HashMap<String, HeatTemplateParam> params = new HashMap<>();
893 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
894 logger.debug("paramSet has " + paramSet.size() + " entries");
896 for (HeatTemplateParam htp : paramSet) {
897 params.put(htp.getParamName(), htp);
900 String alias = htp.getParamAlias();
901 if (alias != null && !"".equals(alias) && !params.containsKey(alias)) {
902 params.put(alias, htp);
906 // First, convert all inputs to their "template" type
907 for (String key : inputs.keySet()) {
908 if (params.containsKey(key)) {
909 Object value = convertInputValue(inputs.get(key), params.get(key));
911 goldenInputs.put(key, value);
913 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
914 + params.get(key).getParamType());
917 extraInputs.add(key);
921 if (!extraInputs.isEmpty()) {
922 // Add multicloud inputs
923 for (String key : MsoMulticloudUtils.MULTICLOUD_INPUTS) {
924 if (extraInputs.contains(key)) {
925 goldenInputs.put(key, inputs.get(key));
926 extraInputs.remove(key);
927 if (extraInputs.isEmpty()) {
932 logger.debug("Ignoring extra inputs: " + extraInputs);
935 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
936 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
937 for (String key : volumeGroupOutputs.keySet()) {
938 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
939 goldenInputs.put(key, volumeGroupOutputs.get(key));
944 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
945 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
946 for (String key : baseModuleOutputs.keySet()) {
947 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
948 goldenInputs.put(key, baseModuleOutputs.get(key));
953 // TODO: The model should support a mechanism to pre-assign default parameter values
954 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
955 // an Environment file. There is not a general mechanism in the model to handle this.
956 // For the general case, any such parameter/values can be added dynamically to the
957 // inputs (only if not already specified).
959 // Check that required parameters have been supplied from any of the sources
960 String missingParams = null;
961 boolean checkRequiredParameters = true;
963 String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
964 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
965 checkRequiredParameters = false;
966 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
967 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
969 } catch (Exception e) {
970 // No problem - default is true
971 logger.debug("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS,
975 // Do the actual parameter checking.
976 // Include looking at the ENV file as a valid definition of a parameter value.
977 // TODO: This handling of ENV applies only to Heat. A general mechanism to
978 // support pre-set parameter/values does not yet exist in the model.
980 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
981 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
982 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
983 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
984 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
985 logger.debug("Required parameter " + parm.getParamName()
986 + " appears to be in environment - do not count as missing");
988 logger.debug("adding to missing parameters list: " + parm.getParamName());
989 if (missingParams == null) {
990 missingParams = parm.getParamName();
992 missingParams += "," + parm.getParamName();
998 if (missingParams != null) {
999 if (checkRequiredParameters) {
1000 // Problem - missing one or more required parameters
1001 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1002 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "VDU",
1003 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1004 logger.debug(error);
1005 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1007 logger.debug("found missing parameters [" + missingParams
1008 + "] - but checkRequiredParameters is false - " + "will not block");
1011 logger.debug("No missing parameters found - ok to proceed");
1014 } // NOTE: END PARAMETER CHECKING
1017 // Here we go... ready to deploy the VF Module.
1018 if (backout == null)
1022 // Construct the VDU Model structure to pass to the targeted VduPlugin
1023 VduModelInfo vduModel = null;
1024 if (!isVolumeRequest) {
1025 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1027 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1030 // Invoke the VduPlugin to instantiate the VF Module
1031 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1033 } catch (VduException me) {
1034 // Failed to instantiate the VDU.
1035 me.addContext("CreateVFModule");
1036 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1038 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1039 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(), "MsoException - instantiateVdu", me);
1040 logger.debug(error);
1041 // Convert to a generic VnfException
1042 throw new VnfException(me);
1043 } catch (NullPointerException npe) {
1044 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1046 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1047 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(),
1048 "NullPointerException - instantiateVdu", npe);
1049 logger.debug(error);
1050 logger.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1051 throw new VnfException("NullPointerException during instantiateVdu");
1052 } catch (Exception e) {
1053 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1055 logger.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1056 logger.debug(error);
1057 throw new VnfException("Exception during instantiateVdu: " + e.getMessage());
1061 // Reach this point if create is successful.
1062 // Populate remaining rollback info and response parameters.
1063 vfRollback.setVnfCreated(true);
1064 vfRollback.setVnfId(vduInstance.getVduInstanceId());
1065 vnfId.value = vduInstance.getVduInstanceId();
1066 outputs.value = copyStringOutputs(vduInstance.getOutputs());
1068 rollback.value = vfRollback;
1070 logger.debug("VF Module " + vfModuleName + " successfully created");
1075 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId,
1076 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1078 logger.debug("Deleting VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1080 // Capture the output parameters on a delete, so need to query first
1081 VduInstance vduInstance;
1082 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
1084 // Use the VduPlugin.
1085 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
1088 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleId);
1089 } catch (VduException e) {
1090 // Failed to query the VDU due to a plugin exception.
1091 // Convert to a generic VnfException
1092 e.addContext("QueryVFModule");
1093 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
1094 + tenantId + ": " + e;
1095 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleId, cloudOwner,
1096 cloudSiteId, tenantId, "VDU", "QueryVFModule", ErrorCode.DataError.getValue(),
1097 "Exception - queryVDU", e);
1098 logger.debug(error);
1099 throw new VnfException(e);
1102 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1104 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1106 // Use the VduPlugin to delete the VDU.
1107 // The possible outcomes of deleteVdu are
1108 // - a vnfInstance object with status of DELETED (success)
1109 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1110 // - a vnfInstance object with status of FAILED (error)
1111 // Also, VduException could be thrown.
1113 // TODO: Get an appropriate timeout value - require access to the model
1114 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1115 } catch (VduException me) {
1116 me.addContext("DeleteVfModule");
1117 // Convert to a generic VnfException
1119 "Delete VF: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1120 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
1121 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(),
1122 "Exception - DeleteVdu: " + me.getMessage());
1123 logger.debug(error);
1124 throw new VnfException(me);
1127 // On success, nothing is returned.
1131 // Update VF Module not yet implemented for generic VDU plug-in model.
1133 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1134 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1135 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1136 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1137 throws VnfException {
1138 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1139 logger.debug("Update VF Module command attempted but not supported");
1140 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1144 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator" defined for the target
1145 * cloud. Should really be looking at the VNF Model (ochestration_mode) but we don't currently have access to that
1146 * in Query and Delete cases.
1148 private VduPlugin getVduPlugin(String cloudSiteId, String cloudOwner) {
1149 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
1150 if (cloudSiteOp.isPresent()) {
1151 CloudSite cloudSite = cloudSiteOp.get();
1152 String orchestrator = cloudSite.getOrchestrator();
1154 if ("CLOUDIFY".equalsIgnoreCase(orchestrator)) {
1155 return cloudifyUtils;
1156 } else if ("HEAT".equalsIgnoreCase(orchestrator)) {
1158 } else if ("MULTICLOUD".equalsIgnoreCase(orchestrator)) {
1159 return multicloudUtils;
1161 // Default if cloudSite record exists - return HEAT plugin - will fail later
1165 // Default if no cloudSite record exists - return multicloud plugin
1166 return multicloudUtils;