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.adapters.vdu.CloudInfo;
46 import org.onap.so.adapters.vdu.VduException;
47 import org.onap.so.adapters.vdu.VduInstance;
48 import org.onap.so.adapters.vdu.VduModelInfo;
49 import org.onap.so.adapters.vdu.VduPlugin;
50 import org.onap.so.adapters.vdu.VduStateType;
51 import org.onap.so.adapters.vdu.VduStatus;
52 import org.onap.so.adapters.vdu.mapper.VfModuleCustomizationToVduMapper;
53 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
54 import org.onap.so.adapters.vnf.exceptions.VnfException;
55 import org.onap.so.cloud.CloudConfig;
56 import org.onap.so.db.catalog.beans.CloudSite;
57 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
58 import org.onap.so.db.catalog.beans.HeatEnvironment;
59 import org.onap.so.db.catalog.beans.HeatTemplate;
60 import org.onap.so.db.catalog.beans.HeatTemplateParam;
61 import org.onap.so.db.catalog.beans.VfModule;
62 import org.onap.so.db.catalog.beans.VfModuleCustomization;
63 import org.onap.so.db.catalog.beans.VnfResource;
64 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
65 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
66 import org.onap.so.entity.MsoRequest;
67 import org.onap.so.logger.ErrorCode;
68 import org.onap.so.logger.MessageEnum;
69 import org.onap.so.openstack.beans.VnfRollback;
70 import org.onap.so.openstack.beans.VnfStatus;
71 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
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 final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
95 private static Logger logger = LoggerFactory.getLogger(MsoVnfPluginAdapterImpl.class);
97 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
98 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
101 protected CloudConfig cloudConfig;
104 private VFModuleCustomizationRepository vfModuleCustomRepo;
107 private Environment environment;
110 protected MsoKeystoneUtils keystoneUtils;
113 protected MsoCloudifyUtils cloudifyUtils;
116 protected MsoHeatUtils heatUtils;
119 protected MsoMulticloudUtils multicloudUtils;
122 protected VfModuleCustomizationToVduMapper vduMapper;
125 * Health Check web method. Does nothing but return to show the adapter is deployed.
128 public void healthCheck() {
129 logger.debug("Health check call in VNF Plugin Adapter");
133 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
135 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
137 public MsoVnfPluginAdapterImpl() {
142 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
146 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
147 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
148 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
149 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
150 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
151 logger.debug("CreateVNF command attempted but not supported");
152 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
156 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
160 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
161 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
162 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
163 throws VnfException {
164 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
165 logger.debug("UpdateVNF command attempted but not supported");
166 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
170 * This is the "Query VNF" web service implementation.
172 * This really should be QueryVfModule, but nobody ever changed it.
174 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
175 * also be reflected back as its ID.
177 * @param cloudSiteId CLLI code of the cloud site in which to query
178 * @param tenantId Openstack tenant identifier
179 * @param vnfNameOrId VNF Name or ID to query
180 * @param msoRequest Request tracking information for logs
181 * @param vnfExists Flag reporting the result of the query
182 * @param vnfId Holder for output VNF ID
183 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
186 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfNameOrId,
187 MsoRequest msoRequest, Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
188 Holder<Map<String, String>> outputs) throws VnfException {
189 logger.debug("Querying VNF " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
191 // Will capture execution time for metrics
192 long startTime = System.currentTimeMillis();
193 long subStartTime = System.currentTimeMillis();
195 VduInstance vduInstance = null;
196 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
198 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
201 vduInstance = vduPlugin.queryVdu(cloudInfo, vnfNameOrId);
202 } catch (VduException e) {
203 // Failed to query the VDU due to a plugin exception.
204 // Convert to a generic VnfException
205 e.addContext("QueryVNF");
206 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
208 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfNameOrId, cloudOwner,
209 cloudSiteId, tenantId, "VDU", "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryVDU",
212 throw new VnfException(e);
215 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
216 vnfExists.value = Boolean.TRUE;
217 status.value = vduStatusToVnfStatus(vduInstance);
218 vnfId.value = vduInstance.getVduInstanceId();
219 outputs.value = copyStringOutputs(vduInstance.getOutputs());
221 logger.debug("VNF {} found, ID = {}", vnfNameOrId, vnfId.value);
223 vnfExists.value = Boolean.FALSE;
224 status.value = VnfStatus.NOTFOUND;
226 outputs.value = new HashMap<String, String>(); // Return as an empty map
228 logger.debug("VNF {} not found", vnfNameOrId);
235 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
239 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
240 throws VnfException {
242 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
243 logger.debug("DeleteVNF command attempted but not supported");
244 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
248 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
249 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
250 * to undo the creation.
252 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
255 public void rollbackVnf(VnfRollback rollback) throws VnfException {
256 long startTime = System.currentTimeMillis();
257 // rollback may be null (e.g. if stack already existed when Create was called)
258 if (rollback == null) {
259 logger.info("{} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
263 // Don't rollback if nothing was done originally
264 if (!rollback.getVnfCreated()) {
268 // Get the elements of the VnfRollback object for easier access
269 String cloudSiteId = rollback.getCloudSiteId();
270 String cloudOwner = rollback.getCloudOwner();
271 String tenantId = rollback.getTenantId();
272 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
274 String vfModuleId = rollback.getVfModuleStackId();
276 logger.debug("Rolling Back VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
278 VduInstance vduInstance = null;
280 // Use the VduPlugin to delete the VF Module.
281 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
283 long subStartTime = System.currentTimeMillis();
285 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
287 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
289 logger.debug("Rolled back VDU instantiation: {}", vduInstance.getVduInstanceId());
290 } catch (VduException ve) {
291 // Failed to rollback the VF Module due to a plugin exception.
292 // Convert to a generic VnfException
293 ve.addContext("RollbackVFModule");
294 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
295 + tenantId + ": " + ve;
296 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
297 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(), "Exception - DeleteVdu",
300 throw new VnfException(ve);
306 private VnfStatus vduStatusToVnfStatus(VduInstance vdu) {
307 // Determine the status based on last action & status
308 // DeploymentInfo object should be enhanced to report a better status internally.
309 VduStatus vduStatus = vdu.getStatus();
310 VduStateType status = vduStatus.getState();
312 if (status == null) {
313 return VnfStatus.UNKNOWN;
314 } else if (status == VduStateType.NOTFOUND) {
315 return VnfStatus.NOTFOUND;
316 } else if (status == VduStateType.INSTANTIATED) {
317 return VnfStatus.ACTIVE;
318 } else if (status == VduStateType.FAILED) {
319 return VnfStatus.FAILED;
322 return VnfStatus.UNKNOWN;
326 * Normalize an input value to an Object, based on the target parameter type. If the type is not recognized, it will
327 * just be returned unchanged (as a string).
329 private Object convertInputValue(Object inputValue, HeatTemplateParam templateParam) {
330 String type = templateParam.getParamType();
331 logger.debug("Parameter: {} is of type ", templateParam.getParamName(), type);
333 if (type.equalsIgnoreCase("number")) {
335 return Integer.valueOf(inputValue.toString());
336 } catch (Exception e) {
337 logger.debug("Unable to convert " + inputValue + " to an integer!", e);
340 } else if (type.equalsIgnoreCase("json")) {
342 JsonNode jsonNode = JSON_MAPPER.readTree(JSON_MAPPER.writeValueAsString(inputValue));
344 } catch (Exception e) {
345 logger.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
348 } else if (type.equalsIgnoreCase("boolean")) {
349 return new Boolean(inputValue.toString());
352 // Nothing else matched. Return the original string
356 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
357 Map<String, String> stringOutputs = new HashMap<String, String>();
358 for (String key : stackOutputs.keySet()) {
359 if (stackOutputs.get(key) instanceof String) {
360 stringOutputs.put(key, (String) stackOutputs.get(key));
361 } else if (stackOutputs.get(key) instanceof Integer) {
363 String str = "" + stackOutputs.get(key);
364 stringOutputs.put(key, str);
365 } catch (Exception e) {
366 logger.debug("Unable to add {} to outputs", key, e);
368 } else if (stackOutputs.get(key) instanceof JsonNode) {
370 String str = this.convertNode((JsonNode) stackOutputs.get(key));
371 stringOutputs.put(key, str);
372 } catch (Exception e) {
373 logger.debug("Unable to add {} to outputs - exception converting JsonNode", key, e);
375 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
377 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
378 stringOutputs.put(key, str);
379 } catch (Exception e) {
380 logger.debug("Unable to add {} to outputs - exception converting LinkedHashMap", key, e);
384 String str = stackOutputs.get(key).toString();
385 stringOutputs.put(key, str);
386 } catch (Exception e) {
387 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),
392 return stringOutputs;
396 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
398 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
399 if (inputs == null) {
401 } else if (inputs.size() < 1) {
402 sb.append("\tEMPTY");
404 for (String str : inputs.keySet()) {
407 outputString = inputs.get(str).toString();
408 } catch (Exception e) {
409 outputString = "Unable to call toString() on the value for " + str;
411 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
414 logger.debug(sb.toString());
418 private void sendMapToDebug(Map<String, Object> inputs) {
420 StringBuilder sb = new StringBuilder("inputs:");
421 if (inputs == null) {
423 } else if (inputs.size() < 1) {
424 sb.append("\tEMPTY");
426 for (String str : inputs.keySet()) {
427 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
430 logger.debug(sb.toString());
434 private String convertNode(final JsonNode node) {
436 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
437 final String json = JSON_MAPPER.writeValueAsString(obj);
439 } catch (JsonParseException jpe) {
440 logger.debug("Error converting json to string " + jpe.getMessage());
441 } catch (Exception e) {
442 logger.debug("Error converting json to string " + e.getMessage());
444 return "[Error converting json to string]";
447 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
448 if (objectMap == null) {
451 Map<String, String> stringMap = new HashMap<String, String>();
452 for (String key : objectMap.keySet()) {
453 if (!stringMap.containsKey(key)) {
454 Object obj = objectMap.get(key);
455 if (obj instanceof String) {
456 stringMap.put(key, (String) objectMap.get(key));
457 } else if (obj instanceof JsonNode) {
458 // This is a bit of mess - but I think it's the least impacting
459 // let's convert it BACK to a string - then it will get converted back later
461 String str = this.convertNode((JsonNode) obj);
462 stringMap.put(key, str);
463 } catch (Exception e) {
464 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
465 // okay in this instance - only string values (fqdn) are expected to be needed
467 } else if (obj instanceof java.util.LinkedHashMap) {
468 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
470 String str = JSON_MAPPER.writeValueAsString(obj);
471 stringMap.put(key, str);
472 } catch (Exception e) {
473 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
475 } else if (obj instanceof Integer) {
477 String str = "" + obj;
478 stringMap.put(key, str);
479 } catch (Exception e) {
480 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
484 String str = obj.toString();
485 stringMap.put(key, str);
486 } catch (Exception e) {
488 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")",
499 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
500 * type in the specified cloud and tenant. The tenant must exist before this service is called.
502 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
503 * value of the 'failIfExists' parameter.
505 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
506 * error will be returned. Within the catalog, each VF Module references (among other things) a collection of
507 * artifacts that are used to deploy the required cloud resources (VMs, networks, etc.).
509 * Depending on the module templates, a variable set of input parameters will be defined, some of which are
510 * required. The caller is responsible to pass the necessary input data for the module or an error will be thrown.
512 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
513 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
514 * VF module is successfully created but the orchestration fails on a subsequent step.
516 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
517 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
518 * @param tenantId Openstack tenant identifier
519 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
520 * modelCustomizationUuid
521 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
522 * also captured by modelCustomizationUuid
523 * @param vnfId - VNF ID
524 * @param vfModuleName Name to be assigned to the new VF Module
525 * @param vfModuleId Id fo the new VF Module
526 * @param requestType Indicates if this is a Volume Group or Module request
527 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
528 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
529 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
530 * @param inputs Map of key=value inputs for VNF stack creation
531 * @param failIfExists Flag whether already existing VNF should be considered
532 * @param backout Flag whether to suppress automatic backout (for testing)
533 * @param msoRequest Request tracking information for logs
534 * @param vnfId Holder for output VF Module instance ID in the cloud
535 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
536 * @param rollback Holder for returning VnfRollback object
539 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
540 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
541 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
542 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
543 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
544 // Will capture execution time for metrics
545 long startTime = System.currentTimeMillis();
547 // Require a model customization ID. Every VF Module definition must have one.
548 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
549 logger.debug("Missing required input: modelCustomizationUuid");
550 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
551 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
552 "VF Module ModelCustomizationUuid", "VDU", ErrorCode.DataError,
553 "Create VF Module: " + "Missing required input: modelCustomizationUuid");
555 throw new VnfException(error, MsoExceptionCategory.USERDATA);
558 // Clean up some inputs to make comparisons easier
559 if (requestType == null)
562 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
563 volumeGroupId = null;
565 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
566 baseVfModuleId = null;
568 if (inputs == null) {
569 // Create an empty set of inputs
570 inputs = new HashMap<>();
571 logger.debug("inputs == null - setting to empty");
573 this.sendMapToDebug(inputs);
576 // Check if this is for a "Volume" module
577 boolean isVolumeRequest = false;
578 if (requestType.startsWith("VOLUME")) {
579 isVolumeRequest = true;
582 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
585 // Build a default rollback object (no actions performed)
586 VnfRollback vfRollback = new VnfRollback();
587 vfRollback.setCloudSiteId(cloudSiteId);
588 vfRollback.setCloudOwner(cloudOwner);
589 vfRollback.setTenantId(tenantId);
590 vfRollback.setMsoRequest(msoRequest);
591 vfRollback.setRequestType(requestType);
592 vfRollback.setIsBase(false); // Until we know better
593 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
594 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
595 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
596 vfRollback.setMode("CFY");
598 rollback.value = vfRollback; // Default rollback - no updates performed
600 // Get the VNF/VF Module definition from the Catalog DB first.
601 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
603 VfModule vfModule = null;
604 VnfResource vnfResource = null;
605 VfModuleCustomization vfModuleCust = null;
609 vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
611 if (vfModuleCust == null) {
612 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
613 + modelCustomizationUuid;
615 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
616 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", ErrorCode.DataError,
618 throw new VnfException(error, MsoExceptionCategory.USERDATA);
620 logger.debug("Found vfModuleCust entry {}", vfModuleCust.toString());
623 // Get the vfModule and vnfResource records
624 vfModule = vfModuleCust.getVfModule();
625 vnfResource = vfModuleCust.getVfModule().getVnfResources();
626 } catch (Exception e) {
628 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
629 throw new VnfException("Exception during create VF " + e.getMessage());
632 // Perform a version check against cloudSite
633 // Obtain the cloud site information where we will create the VF Module
634 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
635 if (!cloudSiteOp.isPresent()) {
636 // If cloudSiteId is not present in the catalog DB, then default to multicloud
637 logger.debug("{} is not present in cloud_site catalog DB, defaulting to Multicloud plugin adapter",
640 CloudSite cloudSite = cloudSiteOp.get();
641 MavenLikeVersioning aicV = new MavenLikeVersioning();
642 aicV.setVersion(cloudSite.getCloudVersion());
644 String vnfMin = vnfResource.getAicVersionMin();
645 String vnfMax = vnfResource.getAicVersionMax();
647 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
648 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
651 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
652 + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: "
653 + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
654 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
655 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
657 throw new VnfException(error, MsoExceptionCategory.USERDATA);
663 VduInstance vduInstance = null;
664 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
666 // Use the VduPlugin.
667 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
669 long subStartTime1 = System.currentTimeMillis();
671 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleName);
672 } catch (VduException me) {
673 // Failed to query the VDU due to a plugin exception.
674 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
675 + tenantId + ": " + me;
676 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
677 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
678 "Exception - queryVdu", me);
680 // Convert to a generic VnfException
681 me.addContext("CreateVFModule");
682 throw new VnfException(me);
685 // More precise handling/messaging if the Module already exists
686 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
687 VduStateType status = vduInstance.getStatus().getState();
688 logger.debug("Found Existing VDU, status=" + status);
690 if (status == VduStateType.INSTANTIATED) {
691 if (failIfExists != null && failIfExists) {
693 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
694 + cloudSiteId + "/" + tenantId;
695 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(),
696 vfModuleName, cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu",
697 ErrorCode.DataError.getValue(), "VF Module " + vfModuleName + " already exists");
699 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
700 vduInstance.getVduInstanceId());
702 // Found existing deployment and client has not requested "failIfExists".
703 // Populate the outputs from the existing deployment.
705 vnfId.value = vduInstance.getVduInstanceId();
706 outputs.value = copyStringOutputs(vduInstance.getOutputs());
710 // Check through various detailed error cases
711 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING
712 || status == VduStateType.UPDATING) {
713 // fail - it's in progress - return meaningful error
714 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
715 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
716 + "; please wait for it to complete, or fix manually.";
717 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
718 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
719 "VF Module " + vfModuleName + " already exists");
721 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
722 vduInstance.getVduInstanceId());
723 } else if (status == VduStateType.FAILED) {
724 // fail - it exists and is in a FAILED state
725 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
726 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
727 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
728 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
729 "VF Module " + vfModuleName + " already exists and is in FAILED state");
731 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
732 vduInstance.getVduInstanceId());
733 } else if (status == VduStateType.UNKNOWN) {
734 // fail - it exists and is in a UNKNOWN state
735 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
736 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
737 + "; requires manual intervention.";
738 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
739 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
740 "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state");
742 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
743 vduInstance.getVduInstanceId());
745 // Unexpected, since all known status values have been tested for
746 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
747 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
748 + "; requires manual intervention.";
749 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
750 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
751 "VF Module " + vfModuleName + " already exists and is in an unknown state");
753 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
754 vduInstance.getVduInstanceId());
759 // Collect outputs from Base Modules and Volume Modules
760 Map<String, Object> baseModuleOutputs = null;
761 Map<String, Object> volumeGroupOutputs = null;
763 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
764 if (volumeGroupId != null) {
765 long subStartTime2 = System.currentTimeMillis();
766 VduInstance volumeVdu = null;
768 volumeVdu = vduPlugin.queryVdu(cloudInfo, volumeGroupId);
769 } catch (VduException me) {
770 // Failed to query the Volume Group VDU due to a plugin exception.
771 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
772 + cloudSiteId + "/" + tenantId + ": " + me;
773 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
774 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", ErrorCode.DataError.getValue(),
775 "Exception - queryVdu(volume)", me);
777 // Convert to a generic VnfException
778 me.addContext("CreateVFModule(QueryVolume)");
779 throw new VnfException(me);
782 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
783 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
784 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
785 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
786 cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)",
787 ErrorCode.BusinessProcesssError.getValue(),
788 "Create VFModule: Attached Volume Group " + "DOES NOT EXIST");
790 throw new VnfException(error, MsoExceptionCategory.USERDATA);
792 logger.debug("Found nested volume group");
793 volumeGroupOutputs = volumeVdu.getOutputs();
794 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
798 // If this is an Add-On Module, query the Base Module outputs
799 // Note: This will be performed whether or not the current request is for an
800 // Add-On Volume Group or Add-On VF Module
802 if (vfModule.getIsBase()) {
803 logger.debug("This is a BASE Module request");
804 vfRollback.setIsBase(true);
806 logger.debug("This is an Add-On Module request");
808 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
809 // Add-on Volume requests may or may not specify a base.
810 if (!isVolumeRequest && baseVfModuleId == null) {
811 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
814 if (baseVfModuleId != null) {
815 long subStartTime2 = System.currentTimeMillis();
816 VduInstance baseVdu = null;
818 baseVdu = vduPlugin.queryVdu(cloudInfo, baseVfModuleId);
819 } catch (MsoException me) {
820 // Failed to query the Base VF Module due to a Vdu Plugin exception.
821 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
822 + cloudSiteId + "/" + tenantId + ": " + me;
823 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
824 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", ErrorCode.DataError.getValue(),
825 "Exception - queryVdu(Base)", me);
827 // Convert to a generic VnfException
828 me.addContext("CreateVFModule(QueryBase)");
829 throw new VnfException(me);
832 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
833 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudOwner
834 + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
835 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(),
836 baseVfModuleId, cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)",
837 ErrorCode.BusinessProcesssError.getValue(), "Create VFModule: Base Module DOES NOT EXIST");
839 throw new VnfException(error, MsoExceptionCategory.USERDATA);
841 logger.debug("Found base module");
842 baseModuleOutputs = baseVdu.getOutputs();
843 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
849 // NOTE: For this section, heatTemplate is used for all template artifacts.
850 // In final implementation (post-POC), the template object would either be generic or there would
851 // be a separate DB Table/Object for different sub-orchestrators.
853 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
855 HeatTemplate heatTemplate = null;
856 HeatEnvironment heatEnvironment = null;
857 if (isVolumeRequest) {
858 heatTemplate = vfModule.getVolumeHeatTemplate();
859 heatEnvironment = vfModuleCust.getVolumeHeatEnv();
861 heatTemplate = vfModule.getModuleHeatTemplate();
862 heatEnvironment = vfModuleCust.getHeatEnvironment();
865 if (heatTemplate == null) {
866 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
867 + ", reqType=" + requestType;
868 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
869 vfModuleType, "VNF", ErrorCode.DataError.getValue(), error);
871 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
873 logger.debug("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
876 if (heatEnvironment == null) {
877 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
878 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
879 "OpenStack", ErrorCode.DataError.getValue(), error);
880 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
882 logger.debug("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
886 // Create the combined set of parameters from the incoming request, base-module outputs,
887 // volume-module outputs. Also, convert all variables to their native object types.
889 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
890 List<String> extraInputs = new ArrayList<String>();
892 Boolean skipInputChecks = false;
894 if (skipInputChecks) {
895 goldenInputs = new HashMap<String, Object>();
896 for (String key : inputs.keySet()) {
897 goldenInputs.put(key, inputs.get(key));
900 // Build maps for the parameters (including aliases) to simplify checks
901 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
903 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
904 logger.debug("paramSet has " + paramSet.size() + " entries");
906 for (HeatTemplateParam htp : paramSet) {
907 params.put(htp.getParamName(), htp);
910 String alias = htp.getParamAlias();
911 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
912 params.put(alias, htp);
916 // First, convert all inputs to their "template" type
917 for (String key : inputs.keySet()) {
918 if (params.containsKey(key)) {
919 Object value = convertInputValue(inputs.get(key), params.get(key));
921 goldenInputs.put(key, value);
923 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
924 + params.get(key).getParamType());
927 extraInputs.add(key);
931 if (!extraInputs.isEmpty()) {
932 // Add multicloud inputs
933 for (String key : MsoMulticloudUtils.MULTICLOUD_INPUTS) {
934 if (extraInputs.contains(key)) {
935 goldenInputs.put(key, inputs.get(key));
936 extraInputs.remove(key);
937 if (extraInputs.isEmpty()) {
942 logger.debug("Ignoring extra inputs: " + extraInputs);
945 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
946 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
947 for (String key : volumeGroupOutputs.keySet()) {
948 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
949 goldenInputs.put(key, volumeGroupOutputs.get(key));
954 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
955 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
956 for (String key : baseModuleOutputs.keySet()) {
957 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
958 goldenInputs.put(key, baseModuleOutputs.get(key));
963 // TODO: The model should support a mechanism to pre-assign default parameter values
964 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
965 // an Environment file. There is not a general mechanism in the model to handle this.
966 // For the general case, any such parameter/values can be added dynamically to the
967 // inputs (only if not already specified).
969 // Check that required parameters have been supplied from any of the sources
970 String missingParams = null;
971 boolean checkRequiredParameters = true;
973 String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
974 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
975 checkRequiredParameters = false;
976 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
977 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
979 } catch (Exception e) {
980 // No problem - default is true
981 logger.debug("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS,
985 // Do the actual parameter checking.
986 // Include looking at the ENV file as a valid definition of a parameter value.
987 // TODO: This handling of ENV applies only to Heat. A general mechanism to
988 // support pre-set parameter/values does not yet exist in the model.
990 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
991 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
992 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
993 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
994 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
995 logger.debug("Required parameter " + parm.getParamName()
996 + " appears to be in environment - do not count as missing");
998 logger.debug("adding to missing parameters list: " + parm.getParamName());
999 if (missingParams == null) {
1000 missingParams = parm.getParamName();
1002 missingParams += "," + parm.getParamName();
1008 if (missingParams != null) {
1009 if (checkRequiredParameters) {
1010 // Problem - missing one or more required parameters
1011 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1012 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "VDU",
1013 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1014 logger.debug(error);
1015 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1017 logger.debug("found missing parameters [" + missingParams
1018 + "] - but checkRequiredParameters is false - " + "will not block");
1021 logger.debug("No missing parameters found - ok to proceed");
1024 } // NOTE: END PARAMETER CHECKING
1027 // Here we go... ready to deploy the VF Module.
1028 long instantiateVduStartTime = System.currentTimeMillis();
1029 if (backout == null)
1033 // Construct the VDU Model structure to pass to the targeted VduPlugin
1034 VduModelInfo vduModel = null;
1035 if (!isVolumeRequest) {
1036 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1038 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1041 // Invoke the VduPlugin to instantiate the VF Module
1042 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1044 } catch (VduException me) {
1045 // Failed to instantiate the VDU.
1046 me.addContext("CreateVFModule");
1047 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1049 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1050 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(), "MsoException - instantiateVdu", me);
1051 logger.debug(error);
1052 // Convert to a generic VnfException
1053 throw new VnfException(me);
1054 } catch (NullPointerException npe) {
1055 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1057 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1058 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(),
1059 "NullPointerException - instantiateVdu", npe);
1060 logger.debug(error);
1061 logger.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1062 throw new VnfException("NullPointerException during instantiateVdu");
1063 } catch (Exception e) {
1064 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1066 logger.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1067 logger.debug(error);
1068 throw new VnfException("Exception during instantiateVdu: " + e.getMessage());
1072 // Reach this point if create is successful.
1073 // Populate remaining rollback info and response parameters.
1074 vfRollback.setVnfCreated(true);
1075 vfRollback.setVnfId(vduInstance.getVduInstanceId());
1076 vnfId.value = vduInstance.getVduInstanceId();
1077 outputs.value = copyStringOutputs(vduInstance.getOutputs());
1079 rollback.value = vfRollback;
1081 logger.debug("VF Module " + vfModuleName + " successfully created");
1086 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId,
1087 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1089 logger.debug("Deleting VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1090 // Will capture execution time for metrics
1091 long startTime = System.currentTimeMillis();
1093 // Capture the output parameters on a delete, so need to query first
1094 VduInstance vduInstance = null;
1095 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
1097 // Use the VduPlugin.
1098 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
1101 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleId);
1102 } catch (VduException e) {
1103 // Failed to query the VDU due to a plugin exception.
1104 // Convert to a generic VnfException
1105 e.addContext("QueryVFModule");
1106 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
1107 + tenantId + ": " + e;
1108 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleId, cloudOwner,
1109 cloudSiteId, tenantId, "VDU", "QueryVFModule", ErrorCode.DataError.getValue(),
1110 "Exception - queryVDU", e);
1111 logger.debug(error);
1112 throw new VnfException(e);
1115 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1117 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1119 // Use the VduPlugin to delete the VDU.
1120 // The possible outcomes of deleteVdu are
1121 // - a vnfInstance object with status of DELETED (success)
1122 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1123 // - a vnfInstance object with status of FAILED (error)
1124 // Also, VduException could be thrown.
1125 long subStartTime = System.currentTimeMillis();
1127 // TODO: Get an appropriate timeout value - require access to the model
1128 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1129 } catch (VduException me) {
1130 me.addContext("DeleteVfModule");
1131 // Convert to a generic VnfException
1133 "Delete VF: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1134 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
1135 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(),
1136 "Exception - DeleteVdu: " + me.getMessage());
1137 logger.debug(error);
1138 throw new VnfException(me);
1141 // On success, nothing is returned.
1145 // Update VF Module not yet implemented for generic VDU plug-in model.
1147 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1148 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1149 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1150 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1151 throws VnfException {
1152 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1153 logger.debug("Update VF Module command attempted but not supported");
1154 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1158 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator" defined for the target
1159 * cloud. Should really be looking at the VNF Model (ochestration_mode) but we don't currently have access to that
1160 * in Query and Delete cases.
1162 private VduPlugin getVduPlugin(String cloudSiteId, String cloudOwner) {
1163 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
1164 if (cloudSiteOp.isPresent()) {
1165 CloudSite cloudSite = cloudSiteOp.get();
1166 String orchestrator = cloudSite.getOrchestrator();
1168 if (orchestrator.equalsIgnoreCase("CLOUDIFY")) {
1169 return cloudifyUtils;
1170 } else if (orchestrator.equalsIgnoreCase("HEAT")) {
1172 } else if (orchestrator.equalsIgnoreCase("MULTICLOUD")) {
1173 return multicloudUtils;
1175 // Default if cloudSite record exists - return HEAT plugin - will fail later
1179 // Default if no cloudSite record exists - return multicloud plugin
1180 return multicloudUtils;