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
25 * VF Module definition in the MSO catalog is expressed via a set of template and/or file
26 * artifacts that are appropriate for some specific sub-orchestrator that provides an
27 * implementation of the VduPlugin interface. This adapter handles all of the common
28 * VF Module logic, including:
29 * - catalog lookups for artifact retrieval
30 * - parameter filtering and validation
31 * - base and volume module queries
33 * - logging and error handling
35 * Then based on the orchestration mode of the VNF, it will invoke different VDU plug-ins
36 * to perform the low level instantiations, deletions, and queries. At this time, the
37 * set of available plug-ins is hard-coded, though in the future a dynamic selection
38 * is expected (e.g. via a service-provider interface).
40 package org.onap.so.adapters.vnf;
43 import java.util.ArrayList;
44 import java.util.HashMap;
45 import java.util.List;
47 import java.util.Optional;
50 import javax.jws.WebService;
51 import javax.xml.ws.Holder;
53 import org.onap.so.adapters.vdu.CloudInfo;
54 import org.onap.so.adapters.vdu.VduException;
55 import org.onap.so.adapters.vdu.VduInstance;
56 import org.onap.so.adapters.vdu.VduModelInfo;
57 import org.onap.so.adapters.vdu.VduPlugin;
58 import org.onap.so.adapters.vdu.VduStateType;
59 import org.onap.so.adapters.vdu.VduStatus;
60 import org.onap.so.adapters.vdu.mapper.VfModuleCustomizationToVduMapper;
61 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
62 import org.onap.so.adapters.vnf.exceptions.VnfException;
63 import org.onap.so.cloud.CloudConfig;
64 import org.onap.so.db.catalog.beans.CloudSite;
65 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
66 import org.onap.so.db.catalog.beans.HeatEnvironment;
67 import org.onap.so.db.catalog.beans.HeatTemplate;
68 import org.onap.so.db.catalog.beans.HeatTemplateParam;
69 import org.onap.so.db.catalog.beans.VfModule;
70 import org.onap.so.db.catalog.beans.VfModuleCustomization;
71 import org.onap.so.db.catalog.beans.VnfResource;
72 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
73 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
74 import org.onap.so.entity.MsoRequest;
75 import org.onap.so.logger.ErrorCode;
76 import org.onap.so.logger.MessageEnum;
78 import org.onap.so.openstack.beans.VnfRollback;
79 import org.onap.so.openstack.beans.VnfStatus;
80 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
81 import org.onap.so.openstack.exceptions.MsoException;
82 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
83 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
84 import org.onap.so.openstack.utils.MsoHeatUtils;
85 import org.onap.so.openstack.utils.MsoKeystoneUtils;
86 import org.onap.so.openstack.utils.MsoMulticloudUtils;
87 import org.slf4j.Logger;
88 import org.slf4j.LoggerFactory;
89 import org.springframework.beans.factory.annotation.Autowired;
90 import org.springframework.core.env.Environment;
91 import org.springframework.stereotype.Component;
92 import org.springframework.transaction.annotation.Transactional;
94 import com.fasterxml.jackson.core.JsonParseException;
95 import com.fasterxml.jackson.databind.JsonNode;
96 import com.fasterxml.jackson.databind.ObjectMapper;
98 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf")
101 public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
103 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
104 private static Logger logger = LoggerFactory.getLogger(MsoVnfPluginAdapterImpl.class);
106 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
107 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
110 protected CloudConfig cloudConfig;
113 private VFModuleCustomizationRepository vfModuleCustomRepo;
116 private Environment environment;
119 protected MsoKeystoneUtils keystoneUtils;
122 protected MsoCloudifyUtils cloudifyUtils;
125 protected MsoHeatUtils heatUtils;
128 protected MsoMulticloudUtils multicloudUtils;
131 protected VfModuleCustomizationToVduMapper vduMapper;
134 * Health Check web method. Does nothing but return to show the adapter is deployed.
137 public void healthCheck () {
138 logger.debug("Health check call in VNF Plugin Adapter");
142 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
143 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
145 public MsoVnfPluginAdapterImpl() {
150 * This is the "Create VNF" web service implementation.
151 * This function is now unsupported and will return an error.
155 public void createVnf (String cloudSiteId,
162 String volumeGroupHeatStackId,
163 Map <String, Object> inputs,
164 Boolean failIfExists,
166 Boolean enableBridge,
167 MsoRequest msoRequest,
168 Holder <String> vnfId,
169 Holder <Map <String, String>> outputs,
170 Holder <VnfRollback> rollback)
173 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
174 logger.debug("CreateVNF command attempted but not supported");
175 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
179 * This is the "Update VNF" web service implementation.
180 * This function is now unsupported and will return an error.
184 public void updateVnf (String cloudSiteId,
191 String volumeGroupHeatStackId,
192 Map <String, Object> inputs,
193 MsoRequest msoRequest,
194 Holder <Map <String, String>> outputs,
195 Holder <VnfRollback> rollback)
198 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
199 logger.debug("UpdateVNF command attempted but not supported");
200 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
204 * This is the "Query VNF" web service implementation.
206 * This really should be QueryVfModule, but nobody ever changed it.
208 * The method returns an indicator that the VNF exists, along with its status and outputs.
209 * The input "vnfName" will also be reflected back as its ID.
211 * @param cloudSiteId CLLI code of the cloud site in which to query
212 * @param tenantId Openstack tenant identifier
213 * @param vnfNameOrId VNF Name or ID to query
214 * @param msoRequest Request tracking information for logs
215 * @param vnfExists Flag reporting the result of the query
216 * @param vnfId Holder for output VNF ID
217 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
220 public void queryVnf (String cloudSiteId,
224 MsoRequest msoRequest,
225 Holder <Boolean> vnfExists,
226 Holder <String> vnfId,
227 Holder <VnfStatus> status,
228 Holder <Map <String, String>> outputs)
231 logger.debug("Querying VNF " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
233 // Will capture execution time for metrics
234 long startTime = System.currentTimeMillis ();
235 long subStartTime = System.currentTimeMillis ();
237 VduInstance vduInstance = null;
238 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
240 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
243 vduInstance = vduPlugin.queryVdu (cloudInfo, vnfNameOrId);
245 catch (VduException e) {
246 // Failed to query the VDU due to a plugin exception.
247 // Convert to a generic VnfException
248 e.addContext("QueryVNF");
249 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + e;
250 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfNameOrId, cloudOwner, cloudSiteId,
251 tenantId, "VDU", "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryVDU", e);
253 throw new VnfException(e);
256 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
257 vnfExists.value = Boolean.TRUE;
258 status.value = vduStatusToVnfStatus(vduInstance);
259 vnfId.value = vduInstance.getVduInstanceId();
260 outputs.value = copyStringOutputs(vduInstance.getOutputs());
262 logger.debug("VNF {} found, ID = {}", vnfNameOrId, vnfId.value);
265 vnfExists.value = Boolean.FALSE;
266 status.value = VnfStatus.NOTFOUND;
268 outputs.value = new HashMap<String, String>(); // Return as an empty map
270 logger.debug("VNF {} not found", vnfNameOrId);
277 * This is the "Delete VNF" web service implementation.
278 * This function is now unsupported and will return an error.
282 public void deleteVnf (String cloudSiteId,
286 MsoRequest msoRequest) throws VnfException {
288 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
289 logger.debug("DeleteVNF command attempted but not supported");
290 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
294 * This web service endpoint will rollback a previous Create VNF operation.
295 * A rollback object is returned to the client in a successful creation
296 * response. The client can pass that object as-is back to the rollbackVnf
297 * operation to undo the creation.
299 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
300 * but APIs were apparently never updated.
303 public void rollbackVnf (VnfRollback rollback) throws VnfException {
304 long startTime = System.currentTimeMillis ();
305 // rollback may be null (e.g. if stack already existed when Create was called)
306 if (rollback == null) {
307 logger.info("{} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
311 // Don't rollback if nothing was done originally
312 if (!rollback.getVnfCreated()) {
316 // Get the elements of the VnfRollback object for easier access
317 String cloudSiteId = rollback.getCloudSiteId ();
318 String cloudOwner = rollback.getCloudOwner();
319 String tenantId = rollback.getTenantId ();
320 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, cloudOwner, tenantId, null);
322 String vfModuleId = rollback.getVfModuleStackId ();
324 logger.debug("Rolling Back VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
326 VduInstance vduInstance = null;
328 // Use the VduPlugin to delete the VF Module.
329 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
331 long subStartTime = System.currentTimeMillis ();
333 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
334 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
336 logger.debug("Rolled back VDU instantiation: {}", vduInstance.getVduInstanceId());
338 catch (VduException ve) {
339 // Failed to rollback the VF Module due to a plugin exception.
340 // Convert to a generic VnfException
341 ve.addContext ("RollbackVFModule");
342 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + ve;
343 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
344 tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(), "Exception - DeleteVdu", ve);
346 throw new VnfException (ve);
352 private VnfStatus vduStatusToVnfStatus (VduInstance vdu) {
353 // Determine the status based on last action & status
354 // DeploymentInfo object should be enhanced to report a better status internally.
355 VduStatus vduStatus = vdu.getStatus();
356 VduStateType status = vduStatus.getState();
358 if (status == null) {
359 return VnfStatus.UNKNOWN;
361 else if (status == VduStateType.NOTFOUND) {
362 return VnfStatus.NOTFOUND;
364 else if (status == VduStateType.INSTANTIATED) {
365 return VnfStatus.ACTIVE;
367 else if (status == VduStateType.FAILED) {
368 return VnfStatus.FAILED;
371 return VnfStatus.UNKNOWN;
375 * Normalize an input value to an Object, based on the target parameter type.
376 * If the type is not recognized, it will just be returned unchanged (as a string).
378 private Object convertInputValue (Object inputValue, HeatTemplateParam templateParam)
380 String type = templateParam.getParamType();
381 logger.debug("Parameter: {} is of type ", templateParam.getParamName(), type);
383 if (type.equalsIgnoreCase("number")) {
385 return Integer.valueOf(inputValue.toString());
387 catch (Exception e) {
388 logger.debug("Unable to convert " + inputValue + " to an integer!" , e);
391 } else if (type.equalsIgnoreCase("json")) {
393 JsonNode jsonNode = JSON_MAPPER.readTree(JSON_MAPPER.writeValueAsString(inputValue));
396 catch (Exception e) {
397 logger.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
400 } else if (type.equalsIgnoreCase("boolean")) {
401 return new Boolean(inputValue.toString());
404 // Nothing else matched. Return the original string
408 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
409 Map <String, String> stringOutputs = new HashMap <String, String> ();
410 for (String key : stackOutputs.keySet ()) {
411 if (stackOutputs.get (key) instanceof String) {
412 stringOutputs.put (key, (String) stackOutputs.get (key));
413 } else if (stackOutputs.get(key) instanceof Integer) {
415 String str = "" + stackOutputs.get(key);
416 stringOutputs.put(key, str);
417 } catch (Exception e) {
418 logger.debug("Unable to add {} to outputs", key, e);
420 } else if (stackOutputs.get(key) instanceof JsonNode) {
422 String str = this.convertNode((JsonNode) stackOutputs.get(key));
423 stringOutputs.put(key, str);
424 } catch (Exception e) {
425 logger.debug("Unable to add {} to outputs - exception converting JsonNode", key, e);
427 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
429 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
430 stringOutputs.put(key, str);
431 } catch (Exception e) {
432 logger.debug("Unable to add {} to outputs - exception converting LinkedHashMap", key, e);
436 String str = stackOutputs.get(key).toString();
437 stringOutputs.put(key, str);
438 } catch (Exception e) {
440 .debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(), e);
444 return stringOutputs;
448 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
450 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
451 if (inputs == null) {
454 else if (inputs.size() < 1) {
455 sb.append("\tEMPTY");
457 for (String str : inputs.keySet()) {
460 outputString = inputs.get(str).toString();
461 } catch (Exception e) {
462 outputString = "Unable to call toString() on the value for " + str;
464 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
467 logger.debug(sb.toString());
471 private void sendMapToDebug(Map<String, Object> inputs) {
473 StringBuilder sb = new StringBuilder("inputs:");
474 if (inputs == null) {
477 else if (inputs.size() < 1) {
478 sb.append("\tEMPTY");
480 for (String str : inputs.keySet()) {
481 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
484 logger.debug(sb.toString());
488 private String convertNode(final JsonNode node) {
490 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
491 final String json = JSON_MAPPER.writeValueAsString(obj);
493 } catch (JsonParseException jpe) {
494 logger.debug("Error converting json to string " + jpe.getMessage());
495 } catch (Exception e) {
496 logger.debug("Error converting json to string " + e.getMessage());
498 return "[Error converting json to string]";
501 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
502 if (objectMap == null) {
505 Map<String, String> stringMap = new HashMap<String, String>();
506 for (String key : objectMap.keySet()) {
507 if (!stringMap.containsKey(key)) {
508 Object obj = objectMap.get(key);
509 if (obj instanceof String) {
510 stringMap.put(key, (String) objectMap.get(key));
511 } else if (obj instanceof JsonNode ){
512 // This is a bit of mess - but I think it's the least impacting
513 // let's convert it BACK to a string - then it will get converted back later
515 String str = this.convertNode((JsonNode) obj);
516 stringMap.put(key, str);
517 } catch (Exception e) {
518 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key, e);
519 //okay in this instance - only string values (fqdn) are expected to be needed
521 } else if (obj instanceof java.util.LinkedHashMap) {
522 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
524 String str = JSON_MAPPER.writeValueAsString(obj);
525 stringMap.put(key, str);
526 } catch (Exception e) {
527 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key, e);
529 } else if (obj instanceof Integer) {
531 String str = "" + obj;
532 stringMap.put(key, str);
533 } catch (Exception e) {
534 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key, e);
538 String str = obj.toString();
539 stringMap.put(key, str);
540 } catch (Exception e) {
541 logger.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")", e);
551 * This is the "Create VF Module" web service implementation.
552 * It will instantiate a new VF Module of the requested type in the specified cloud
553 * and tenant. The tenant must exist before this service is called.
555 * If a VF Module with the same name already exists, this can be considered a
556 * success or failure, depending on the value of the 'failIfExists' parameter.
558 * All VF Modules are defined in the MSO catalog. The caller must request one of
559 * the pre-defined module types or an error will be returned. Within the catalog,
560 * each VF Module references (among other things) a collection of artifacts that
561 * are used to deploy the required cloud resources (VMs, networks, etc.).
563 * Depending on the module templates, a variable set of input parameters will
564 * be defined, some of which are required. The caller is responsible to
565 * pass the necessary input data for the module or an error will be thrown.
567 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
568 * object. This last object can be passed as-is to the rollbackVnf operation to
569 * undo everything that was created for the Module. This is useful if a VF module
570 * is successfully created but the orchestration fails on a subsequent step.
572 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
573 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
574 * @param tenantId Openstack tenant identifier
575 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
576 * Deprecated - should use modelCustomizationUuid
577 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
578 * Deprecated - VF Module versions also captured by modelCustomizationUuid
579 * @param vnfId - VNF ID
580 * @param vfModuleName Name to be assigned to the new VF Module
581 * @param vfModuleId Id fo the new VF Module
582 * @param requestType Indicates if this is a Volume Group or Module request
583 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
584 * to attach to a VF Module
585 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
586 * this is an Add-on module
587 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
588 * the use of vfModuleType.
589 * @param inputs Map of key=value inputs for VNF stack creation
590 * @param failIfExists Flag whether already existing VNF should be considered
591 * @param backout Flag whether to suppress automatic backout (for testing)
592 * @param msoRequest Request tracking information for logs
593 * @param vnfId Holder for output VF Module instance ID in the cloud
594 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
595 * @param rollback Holder for returning VnfRollback object
598 public void createVfModule(String cloudSiteId,
607 String volumeGroupId,
608 String baseVfModuleId,
609 String modelCustomizationUuid,
610 Map <String, Object> inputs,
611 Boolean failIfExists,
613 Boolean enableBridge,
614 MsoRequest msoRequest,
615 Holder <String> vnfId,
616 Holder <Map <String, String>> outputs,
617 Holder <VnfRollback> rollback)
620 // Will capture execution time for metrics
621 long startTime = System.currentTimeMillis ();
623 // Require a model customization ID. Every VF Module definition must have one.
624 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
625 logger.debug("Missing required input: modelCustomizationUuid");
626 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
627 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
628 "VF Module ModelCustomizationUuid", "VDU", ErrorCode.DataError,
629 "Create VF Module: " + "Missing required input: modelCustomizationUuid");
631 throw new VnfException(error, MsoExceptionCategory.USERDATA);
634 // Clean up some inputs to make comparisons easier
635 if (requestType == null)
638 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
639 volumeGroupId = null;
641 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
642 baseVfModuleId = null;
644 if (inputs == null) {
645 // Create an empty set of inputs
646 inputs = new HashMap<>();
647 logger.debug("inputs == null - setting to empty");
649 this.sendMapToDebug(inputs);
652 // Check if this is for a "Volume" module
653 boolean isVolumeRequest = false;
654 if (requestType.startsWith("VOLUME")) {
655 isVolumeRequest = true;
658 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " +
661 // Build a default rollback object (no actions performed)
662 VnfRollback vfRollback = new VnfRollback();
663 vfRollback.setCloudSiteId(cloudSiteId);
664 vfRollback.setCloudOwner(cloudOwner);
665 vfRollback.setTenantId(tenantId);
666 vfRollback.setMsoRequest(msoRequest);
667 vfRollback.setRequestType(requestType);
668 vfRollback.setIsBase(false); // Until we know better
669 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
670 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
671 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
672 vfRollback.setMode("CFY");
674 rollback.value = vfRollback; // Default rollback - no updates performed
676 // Get the VNF/VF Module definition from the Catalog DB first.
677 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
679 VfModule vfModule = null;
680 VnfResource vnfResource = null;
681 VfModuleCustomization vfModuleCust = null;
684 vfModuleCust = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
686 if (vfModuleCust == null) {
687 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
688 + modelCustomizationUuid;
690 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
691 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb",
692 ErrorCode.DataError, error);
693 throw new VnfException(error, MsoExceptionCategory.USERDATA);
695 logger.debug("Found vfModuleCust entry {}", vfModuleCust.toString());
698 // Get the vfModule and vnfResource records
699 vfModule = vfModuleCust.getVfModule();
700 vnfResource = vfModuleCust.getVfModule().getVnfResources();
702 catch (Exception e) {
704 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
705 throw new VnfException("Exception during create VF " + e.getMessage());
708 // Perform a version check against cloudSite
709 // Obtain the cloud site information where we will create the VF Module
710 Boolean usingMulticloud = false;
711 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId);
712 if (!cloudSiteOp.isPresent()) {
713 // If cloudSiteId is not present in the catalog DB, then default to multicloud
714 usingMulticloud = true;
716 CloudSite cloudSite = cloudSiteOp.get();
717 MavenLikeVersioning aicV = new MavenLikeVersioning();
718 aicV.setVersion(cloudSite.getCloudVersion());
719 usingMulticloud = getUsingMulticloud(cloudSite);
721 String vnfMin = vnfResource.getAicVersionMin();
722 String vnfMax = vnfResource.getAicVersionMax();
724 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) || (vnfMax != null
725 && aicV.isMoreRecentThan(vnfMax))) {
728 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
729 + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId
730 + " with AIC_Version:" + cloudSite.getCloudVersion();
731 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
732 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
734 throw new VnfException(error, MsoExceptionCategory.USERDATA);
740 VduInstance vduInstance = null;
741 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, cloudOwner, tenantId, null);
743 // Use the VduPlugin.
744 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
746 // First, look up to see if the VF already exists, unless using multicloud adapter
748 long subStartTime1 = System.currentTimeMillis ();
749 if (!usingMulticloud) {
751 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName);
753 catch (VduException me) {
754 // Failed to query the VDU due to a plugin exception.
755 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
756 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
757 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
758 "Exception - queryVdu", me);
760 // Convert to a generic VnfException
761 me.addContext ("CreateVFModule");
762 throw new VnfException (me);
766 // More precise handling/messaging if the Module already exists
767 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
768 VduStateType status = vduInstance.getStatus().getState();
769 logger.debug("Found Existing VDU, status=" + status);
771 if (status == VduStateType.INSTANTIATED) {
772 if (failIfExists != null && failIfExists) {
775 "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId;
776 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
777 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
778 "VF Module " + vfModuleName + " already exists");
780 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, vduInstance.getVduInstanceId());
782 // Found existing deployment and client has not requested "failIfExists".
783 // Populate the outputs from the existing deployment.
785 vnfId.value = vduInstance.getVduInstanceId();
786 outputs.value = copyStringOutputs(vduInstance.getOutputs());
790 // Check through various detailed error cases
791 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING
792 || status == VduStateType.UPDATING) {
793 // fail - it's in progress - return meaningful error
795 "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString()
796 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
797 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
798 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
799 "VF Module " + vfModuleName + " already exists");
801 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, vduInstance.getVduInstanceId());
802 } else if (status == VduStateType.FAILED) {
803 // fail - it exists and is in a FAILED state
805 "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudOwner + "/" + cloudSiteId
806 + "/" + tenantId + "; requires manual intervention.";
807 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
808 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
809 "VF Module " + vfModuleName + " already exists and is in FAILED state");
811 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, vduInstance.getVduInstanceId());
812 } else if (status == VduStateType.UNKNOWN) {
813 // fail - it exists and is in a UNKNOWN state
815 "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString()
816 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
817 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
818 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
819 "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state");
821 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, vduInstance.getVduInstanceId());
823 // Unexpected, since all known status values have been tested for
825 "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status
826 .toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
827 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
828 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
829 "VF Module " + vfModuleName + " already exists and is in an unknown state");
831 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, vduInstance.getVduInstanceId());
836 // Collect outputs from Base Modules and Volume Modules
837 Map<String, Object> baseModuleOutputs = null;
838 Map<String, Object> volumeGroupOutputs = null;
840 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
841 if (!usingMulticloud && volumeGroupId != null) {
842 long subStartTime2 = System.currentTimeMillis ();
843 VduInstance volumeVdu = null;
845 volumeVdu = vduPlugin.queryVdu (cloudInfo, volumeGroupId);
847 catch (VduException me) {
848 // Failed to query the Volume Group VDU due to a plugin exception.
849 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
850 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
851 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", ErrorCode.DataError.getValue(),
852 "Exception - queryVdu(volume)", me);
854 // Convert to a generic VnfException
855 me.addContext ("CreateVFModule(QueryVolume)");
856 throw new VnfException (me);
859 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
860 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR" ;
861 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
862 cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)",
863 ErrorCode.BusinessProcesssError.getValue(),
864 "Create VFModule: Attached Volume Group " + "DOES NOT EXIST");
866 throw new VnfException (error, MsoExceptionCategory.USERDATA);
868 logger.debug("Found nested volume group");
869 volumeGroupOutputs = volumeVdu.getOutputs();
870 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
874 // If this is an Add-On Module, query the Base Module outputs
875 // Note: This will be performed whether or not the current request is for an
876 // Add-On Volume Group or Add-On VF Module
878 if (vfModule.getIsBase()) {
879 logger.debug("This is a BASE Module request");
880 vfRollback.setIsBase(true);
882 logger.debug("This is an Add-On Module request");
884 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
885 // Add-on Volume requests may or may not specify a base.
886 if (!isVolumeRequest && baseVfModuleId == null) {
887 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
890 // Need to verify if multicloud needs to have the vaseVfModuleId passed to it. Ignoring this for now.
891 if (!usingMulticloud && baseVfModuleId != null) {
892 long subStartTime2 = System.currentTimeMillis ();
893 VduInstance baseVdu = null;
895 baseVdu = vduPlugin.queryVdu (cloudInfo, baseVfModuleId);
897 catch (MsoException me) {
898 // Failed to query the Base VF Module due to a Vdu Plugin exception.
899 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
900 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
901 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", ErrorCode.DataError.getValue(),
902 "Exception - queryVdu(Base)", me);
904 // Convert to a generic VnfException
905 me.addContext ("CreateVFModule(QueryBase)");
906 throw new VnfException (me);
909 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
911 "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
912 + tenantId + " USER ERROR";
913 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
914 cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)",
915 ErrorCode.BusinessProcesssError.getValue(),
916 "Create VFModule: Base Module DOES NOT EXIST");
918 throw new VnfException(error, MsoExceptionCategory.USERDATA);
920 logger.debug("Found base module");
921 baseModuleOutputs = baseVdu.getOutputs();
922 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
928 // NOTE: For this section, heatTemplate is used for all template artifacts.
929 // In final implementation (post-POC), the template object would either be generic or there would
930 // be a separate DB Table/Object for different sub-orchestrators.
932 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
934 HeatTemplate heatTemplate = null;
935 HeatEnvironment heatEnvironment = null;
936 if (isVolumeRequest) {
937 heatTemplate = vfModule.getVolumeHeatTemplate();
938 heatEnvironment = vfModuleCust.getVolumeHeatEnv();
940 heatTemplate = vfModule.getModuleHeatTemplate();
941 heatEnvironment = vfModuleCust.getHeatEnvironment();
944 if (heatTemplate == null) {
945 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType="
947 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID", vfModuleType,
948 "VNF", ErrorCode.DataError.getValue(), error);
950 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
952 logger.debug("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
955 if (heatEnvironment == null) {
956 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
957 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
958 "OpenStack", ErrorCode.DataError.getValue(), error);
959 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
961 logger.debug("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
965 // Create the combined set of parameters from the incoming request, base-module outputs,
966 // volume-module outputs. Also, convert all variables to their native object types.
968 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
969 List<String> extraInputs = new ArrayList<String>();
971 Boolean skipInputChecks = false;
973 if (skipInputChecks) {
974 goldenInputs = new HashMap<String,Object>();
975 for (String key : inputs.keySet()) {
976 goldenInputs.put(key, inputs.get(key));
980 // Build maps for the parameters (including aliases) to simplify checks
981 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
983 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
984 logger.debug("paramSet has " + paramSet.size() + " entries");
986 for (HeatTemplateParam htp : paramSet) {
987 params.put(htp.getParamName(), htp);
990 String alias = htp.getParamAlias();
991 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
992 params.put(alias, htp);
996 // First, convert all inputs to their "template" type
997 for (String key : inputs.keySet()) {
998 if (params.containsKey(key)) {
999 Object value = convertInputValue(inputs.get(key), params.get(key));
1000 if (value != null) {
1001 goldenInputs.put(key, value);
1004 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key)
1008 extraInputs.add(key);
1012 if (!extraInputs.isEmpty()) {
1013 // Add multicloud inputs
1014 boolean multicloudInputs = false;
1015 for (String key : MsoMulticloudUtils.MULTICLOUD_INPUTS) {
1016 if (extraInputs.contains(key)) {
1017 goldenInputs.put(key, inputs.get(key));
1018 extraInputs.remove(key);
1019 multicloudInputs = true;
1020 if (extraInputs.isEmpty()) {
1025 logger.debug("Ignoring extra inputs: " + extraInputs);
1028 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
1029 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
1030 for (String key : volumeGroupOutputs.keySet()) {
1031 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
1032 goldenInputs.put(key, volumeGroupOutputs.get(key));
1037 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
1038 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
1039 for (String key : baseModuleOutputs.keySet()) {
1040 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
1041 goldenInputs.put(key, baseModuleOutputs.get(key));
1046 // TODO: The model should support a mechanism to pre-assign default parameter values
1047 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
1048 // an Environment file. There is not a general mechanism in the model to handle this.
1049 // For the general case, any such parameter/values can be added dynamically to the
1050 // inputs (only if not already specified).
1052 // Check that required parameters have been supplied from any of the sources
1053 String missingParams = null;
1054 boolean checkRequiredParameters = true;
1056 String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
1057 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1058 checkRequiredParameters = false;
1059 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1060 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
1062 } catch (Exception e) {
1063 // No problem - default is true
1064 logger.debug ("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS,
1068 // Do the actual parameter checking.
1069 // Include looking at the ENV file as a valid definition of a parameter value.
1070 // TODO: This handling of ENV applies only to Heat. A general mechanism to
1071 // support pre-set parameter/values does not yet exist in the model.
1073 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1074 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
1075 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1076 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1077 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1078 logger.debug ("Required parameter " + parm.getParamName ()
1079 + " appears to be in environment - do not count as missing");
1081 logger.debug("adding to missing parameters list: " + parm.getParamName ());
1082 if (missingParams == null) {
1083 missingParams = parm.getParamName ();
1085 missingParams += "," + parm.getParamName ();
1091 if (missingParams != null) {
1092 if (checkRequiredParameters) {
1093 // Problem - missing one or more required parameters
1094 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1095 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "VDU",
1096 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1097 logger.debug(error);
1098 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1101 "found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - "
1102 + "will not block");
1105 logger.debug("No missing parameters found - ok to proceed");
1108 } // NOTE: END PARAMETER CHECKING
1111 // Here we go... ready to deploy the VF Module.
1112 long instantiateVduStartTime = System.currentTimeMillis ();
1113 if (backout == null) backout = true;
1116 // Construct the VDU Model structure to pass to the targeted VduPlugin
1117 VduModelInfo vduModel = null;
1118 if (!isVolumeRequest) {
1119 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1121 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1124 // Invoke the VduPlugin to instantiate the VF Module
1125 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1127 } catch (VduException me) {
1128 // Failed to instantiate the VDU.
1129 me.addContext("CreateVFModule");
1130 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1131 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner, cloudSiteId,
1132 tenantId, "VDU", ErrorCode.DataError.getValue(), "MsoException - instantiateVdu", me);
1133 logger.debug(error);
1134 // Convert to a generic VnfException
1135 throw new VnfException(me);
1136 } catch (NullPointerException npe) {
1137 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + npe;
1138 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner, cloudSiteId,
1139 tenantId, "VDU", ErrorCode.DataError.getValue(), "NullPointerException - instantiateVdu",
1141 logger.debug(error);
1142 logger.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1143 throw new VnfException("NullPointerException during instantiateVdu");
1144 } catch (Exception e) {
1145 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + e;
1146 logger.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1147 logger.debug(error);
1148 throw new VnfException("Exception during instantiateVdu: " + e.getMessage());
1152 // Reach this point if create is successful.
1153 // Populate remaining rollback info and response parameters.
1154 vfRollback.setVnfCreated (true);
1155 vfRollback.setVnfId (vduInstance.getVduInstanceId());
1156 vnfId.value = vduInstance.getVduInstanceId();
1157 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
1159 rollback.value = vfRollback;
1161 logger.debug("VF Module " + vfModuleName + " successfully created");
1166 public void deleteVfModule (String cloudSiteId,
1170 MsoRequest msoRequest,
1171 Holder <Map <String, String>> outputs) throws VnfException
1174 logger.debug("Deleting VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1175 // Will capture execution time for metrics
1176 long startTime = System.currentTimeMillis ();
1178 // Capture the output parameters on a delete, so need to query first
1179 VduInstance vduInstance = null;
1180 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
1182 // Use the VduPlugin.
1183 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
1186 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleId);
1188 catch (VduException e) {
1189 // Failed to query the VDU due to a plugin exception.
1190 // Convert to a generic VnfException
1191 e.addContext("QueryVFModule");
1192 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + e;
1193 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
1194 tenantId, "VDU", "QueryVFModule", ErrorCode.DataError.getValue(), "Exception - queryVDU", e);
1195 logger.debug(error);
1196 throw new VnfException(e);
1199 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1200 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1202 // Use the VduPlugin to delete the VDU.
1203 // The possible outcomes of deleteVdu are
1204 // - a vnfInstance object with status of DELETED (success)
1205 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1206 // - a vnfInstance object with status of FAILED (error)
1207 // Also, VduException could be thrown.
1208 long subStartTime = System.currentTimeMillis ();
1210 // TODO: Get an appropriate timeout value - require access to the model
1211 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1212 } catch (VduException me) {
1213 me.addContext ("DeleteVfModule");
1214 // Convert to a generic VnfException
1215 String error = "Delete VF: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1216 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
1217 tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(),
1218 "Exception - DeleteVdu: " + me.getMessage());
1219 logger.debug(error);
1220 throw new VnfException (me);
1223 // On success, nothing is returned.
1227 // Update VF Module not yet implemented for generic VDU plug-in model.
1229 public void updateVfModule (String cloudSiteId,
1236 String volumeGroupHeatStackId,
1237 String baseVfHeatStackId,
1238 String vfModuleStackId,
1239 String modelCustomizationUuid,
1240 Map <String, Object> inputs,
1241 MsoRequest msoRequest,
1242 Holder <Map <String, String>> outputs,
1243 Holder <VnfRollback> rollback) throws VnfException
1245 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1246 logger.debug("Update VF Module command attempted but not supported");
1247 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1251 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator"
1252 * defined for the target cloud. Should really be looking at the VNF Model (ochestration_mode)
1253 * but we don't currently have access to that in Query and Delete cases.
1255 private VduPlugin getVduPlugin (String cloudSiteId, String cloudOwner) {
1256 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
1257 if (cloudSiteOp.isPresent()) {
1258 CloudSite cloudSite = cloudSiteOp.get();
1259 String orchestrator = cloudSite.getOrchestrator();
1261 if (orchestrator.equalsIgnoreCase("CLOUDIFY")) {
1262 return cloudifyUtils;
1264 else if (orchestrator.equalsIgnoreCase("HEAT")) {
1267 else if (orchestrator.equalsIgnoreCase("MULTICLOUD")) {
1268 return multicloudUtils;
1271 // Default if cloudSite record exists - return HEAT plugin - will fail later
1275 // Default if no cloudSite record exists - return multicloud plugin
1276 return multicloudUtils;
1279 private Boolean getUsingMulticloud (CloudSite cloudSite) {
1280 if (cloudSite.getOrchestrator().equalsIgnoreCase("MULTICLOUD")) {