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.MsoException;
72 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
73 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
74 import org.onap.so.openstack.utils.MsoHeatUtils;
75 import org.onap.so.openstack.utils.MsoKeystoneUtils;
76 import org.onap.so.openstack.utils.MsoMulticloudUtils;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79 import org.springframework.beans.factory.annotation.Autowired;
80 import org.springframework.core.env.Environment;
81 import org.springframework.stereotype.Component;
82 import org.springframework.transaction.annotation.Transactional;
83 import com.fasterxml.jackson.core.JsonParseException;
84 import com.fasterxml.jackson.databind.JsonNode;
85 import com.fasterxml.jackson.databind.ObjectMapper;
87 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
88 targetNamespace = "http://org.onap.so/vnf")
91 public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
93 private static Logger logger = LoggerFactory.getLogger(MsoVnfPluginAdapterImpl.class);
95 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
96 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
99 protected CloudConfig cloudConfig;
102 private VFModuleCustomizationRepository vfModuleCustomRepo;
105 private Environment environment;
108 protected MsoKeystoneUtils keystoneUtils;
111 protected MsoCloudifyUtils cloudifyUtils;
114 protected MsoHeatUtils heatUtils;
117 protected MsoMulticloudUtils multicloudUtils;
120 protected VfModuleCustomizationToVduMapper vduMapper;
123 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
125 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
127 public MsoVnfPluginAdapterImpl() {
132 * Health Check web method. Does nothing but return to show the adapter is deployed.
135 public void healthCheck() {
136 logger.debug("Health check call in VNF Plugin Adapter");
140 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
144 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
145 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
146 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
147 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
148 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
149 logger.debug("CreateVNF command attempted but not supported");
150 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
154 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
158 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
159 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
160 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
161 throws VnfException {
162 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
163 logger.debug("UpdateVNF command attempted but not supported");
164 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
168 * This is the "Query VNF" web service implementation.
170 * This really should be QueryVfModule, but nobody ever changed it.
172 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
173 * also be reflected back as its ID.
175 * @param cloudSiteId CLLI code of the cloud site in which to query
176 * @param tenantId Openstack tenant identifier
177 * @param vnfNameOrId VNF Name or ID to query
178 * @param msoRequest Request tracking information for logs
179 * @param vnfExists Flag reporting the result of the query
180 * @param vnfId Holder for output VNF ID
181 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
184 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfNameOrId,
185 MsoRequest msoRequest, Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
186 Holder<Map<String, String>> outputs) throws VnfException {
187 logger.debug("Querying VNF " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
189 // Will capture execution time for metrics
190 long startTime = System.currentTimeMillis();
191 long subStartTime = System.currentTimeMillis();
193 VduInstance vduInstance = null;
194 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
196 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
199 vduInstance = vduPlugin.queryVdu(cloudInfo, vnfNameOrId);
200 } catch (VduException e) {
201 // Failed to query the VDU due to a plugin exception.
202 // Convert to a generic VnfException
203 e.addContext("QueryVNF");
204 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
206 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfNameOrId, cloudOwner,
207 cloudSiteId, tenantId, "VDU", "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryVDU",
210 throw new VnfException(e);
213 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
214 vnfExists.value = Boolean.TRUE;
215 status.value = vduStatusToVnfStatus(vduInstance);
216 vnfId.value = vduInstance.getVduInstanceId();
217 outputs.value = copyStringOutputs(vduInstance.getOutputs());
219 logger.debug("VNF {} found, ID = {}", vnfNameOrId, vnfId.value);
221 vnfExists.value = Boolean.FALSE;
222 status.value = VnfStatus.NOTFOUND;
224 outputs.value = new HashMap<String, String>(); // Return as an empty map
226 logger.debug("VNF {} not found", vnfNameOrId);
233 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
237 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
238 throws VnfException {
240 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
241 logger.debug("DeleteVNF command attempted but not supported");
242 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
246 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
247 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
248 * to undo the creation.
250 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
253 public void rollbackVnf(VnfRollback rollback) throws VnfException {
254 long startTime = System.currentTimeMillis();
255 // rollback may be null (e.g. if stack already existed when Create was called)
256 if (rollback == null) {
257 logger.info("{} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
261 // Don't rollback if nothing was done originally
262 if (!rollback.getVnfCreated()) {
266 // Get the elements of the VnfRollback object for easier access
267 String cloudSiteId = rollback.getCloudSiteId();
268 String cloudOwner = rollback.getCloudOwner();
269 String tenantId = rollback.getTenantId();
270 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
272 String vfModuleId = rollback.getVfModuleStackId();
274 logger.debug("Rolling Back VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
276 VduInstance vduInstance = null;
278 // Use the VduPlugin to delete the VF Module.
279 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
281 long subStartTime = System.currentTimeMillis();
283 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
285 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
287 logger.debug("Rolled back VDU instantiation: {}", vduInstance.getVduInstanceId());
288 } catch (VduException ve) {
289 // Failed to rollback the VF Module due to a plugin exception.
290 // Convert to a generic VnfException
291 ve.addContext("RollbackVFModule");
292 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
293 + tenantId + ": " + ve;
294 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
295 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(), "Exception - DeleteVdu",
298 throw new VnfException(ve);
304 private VnfStatus vduStatusToVnfStatus(VduInstance vdu) {
305 // Determine the status based on last action & status
306 // DeploymentInfo object should be enhanced to report a better status internally.
307 VduStatus vduStatus = vdu.getStatus();
308 VduStateType status = vduStatus.getState();
310 if (status == null) {
311 return VnfStatus.UNKNOWN;
312 } else if (status == VduStateType.NOTFOUND) {
313 return VnfStatus.NOTFOUND;
314 } else if (status == VduStateType.INSTANTIATED) {
315 return VnfStatus.ACTIVE;
316 } else if (status == VduStateType.FAILED) {
317 return VnfStatus.FAILED;
320 return VnfStatus.UNKNOWN;
324 * Normalize an input value to an Object, based on the target parameter type. If the type is not recognized, it will
325 * just be returned unchanged (as a string).
327 private Object convertInputValue(Object inputValue, HeatTemplateParam templateParam) {
328 String type = templateParam.getParamType();
329 logger.debug("Parameter: {} is of type ", templateParam.getParamName(), type);
331 if (type.equalsIgnoreCase("number")) {
333 return Integer.valueOf(inputValue.toString());
334 } catch (Exception e) {
335 logger.debug("Unable to convert " + inputValue + " to an integer!", e);
338 } else if (type.equalsIgnoreCase("json")) {
340 JsonNode jsonNode = JSON_MAPPER.readTree(JSON_MAPPER.writeValueAsString(inputValue));
342 } catch (Exception e) {
343 logger.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
346 } else if (type.equalsIgnoreCase("boolean")) {
347 return new Boolean(inputValue.toString());
350 // Nothing else matched. Return the original string
354 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
355 Map<String, String> stringOutputs = new HashMap<String, String>();
356 for (String key : stackOutputs.keySet()) {
357 if (stackOutputs.get(key) instanceof String) {
358 stringOutputs.put(key, (String) stackOutputs.get(key));
359 } else if (stackOutputs.get(key) instanceof Integer) {
361 String str = "" + stackOutputs.get(key);
362 stringOutputs.put(key, str);
363 } catch (Exception e) {
364 logger.debug("Unable to add {} to outputs", key, e);
366 } else if (stackOutputs.get(key) instanceof JsonNode) {
368 String str = this.convertNode((JsonNode) stackOutputs.get(key));
369 stringOutputs.put(key, str);
370 } catch (Exception e) {
371 logger.debug("Unable to add {} to outputs - exception converting JsonNode", key, e);
373 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
375 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
376 stringOutputs.put(key, str);
377 } catch (Exception e) {
378 logger.debug("Unable to add {} to outputs - exception converting LinkedHashMap", key, e);
382 String str = stackOutputs.get(key).toString();
383 stringOutputs.put(key, str);
384 } catch (Exception e) {
385 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),
390 return stringOutputs;
394 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
396 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
397 if (inputs == null) {
399 } else if (inputs.size() < 1) {
400 sb.append("\tEMPTY");
402 for (String str : inputs.keySet()) {
405 outputString = inputs.get(str).toString();
406 } catch (Exception e) {
407 outputString = "Unable to call toString() on the value for " + str;
409 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
412 logger.debug(sb.toString());
416 private void sendMapToDebug(Map<String, Object> inputs) {
418 StringBuilder sb = new StringBuilder("inputs:");
419 if (inputs == null) {
421 } else if (inputs.size() < 1) {
422 sb.append("\tEMPTY");
424 for (String str : inputs.keySet()) {
425 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
428 logger.debug(sb.toString());
432 private String convertNode(final JsonNode node) {
434 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
435 final String json = JSON_MAPPER.writeValueAsString(obj);
437 } catch (JsonParseException jpe) {
438 logger.debug("Error converting json to string " + jpe.getMessage());
439 } catch (Exception e) {
440 logger.debug("Error converting json to string " + e.getMessage());
442 return "[Error converting json to string]";
445 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
446 if (objectMap == null) {
449 Map<String, String> stringMap = new HashMap<String, String>();
450 for (String key : objectMap.keySet()) {
451 if (!stringMap.containsKey(key)) {
452 Object obj = objectMap.get(key);
453 if (obj instanceof String) {
454 stringMap.put(key, (String) objectMap.get(key));
455 } else if (obj instanceof JsonNode) {
456 // This is a bit of mess - but I think it's the least impacting
457 // let's convert it BACK to a string - then it will get converted back later
459 String str = this.convertNode((JsonNode) obj);
460 stringMap.put(key, str);
461 } catch (Exception e) {
462 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
463 // okay in this instance - only string values (fqdn) are expected to be needed
465 } else if (obj instanceof java.util.LinkedHashMap) {
466 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
468 String str = JSON_MAPPER.writeValueAsString(obj);
469 stringMap.put(key, str);
470 } catch (Exception e) {
471 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
473 } else if (obj instanceof Integer) {
475 String str = "" + obj;
476 stringMap.put(key, str);
477 } catch (Exception e) {
478 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
482 String str = obj.toString();
483 stringMap.put(key, str);
484 } catch (Exception e) {
486 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")",
497 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
498 * type in the specified cloud and tenant. The tenant must exist before this service is called.
500 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
501 * value of the 'failIfExists' parameter.
503 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
504 * error will be returned. Within the catalog, each VF Module references (among other things) a collection of
505 * artifacts that are used to deploy the required cloud resources (VMs, networks, etc.).
507 * Depending on the module templates, a variable set of input parameters will be defined, some of which are
508 * required. The caller is responsible to pass the necessary input data for the module or an error will be thrown.
510 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
511 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
512 * VF module is successfully created but the orchestration fails on a subsequent step.
514 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
515 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
516 * @param tenantId Openstack tenant identifier
517 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
518 * modelCustomizationUuid
519 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
520 * also captured by modelCustomizationUuid
521 * @param vnfId - VNF ID
522 * @param vfModuleName Name to be assigned to the new VF Module
523 * @param vfModuleId Id fo the new VF Module
524 * @param requestType Indicates if this is a Volume Group or Module request
525 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
526 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
527 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
528 * @param inputs Map of key=value inputs for VNF stack creation
529 * @param failIfExists Flag whether already existing VNF should be considered
530 * @param backout Flag whether to suppress automatic backout (for testing)
531 * @param msoRequest Request tracking information for logs
532 * @param vnfId Holder for output VF Module instance ID in the cloud
533 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
534 * @param rollback Holder for returning VnfRollback object
537 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
538 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
539 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
540 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
541 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
542 // Will capture execution time for metrics
543 long startTime = System.currentTimeMillis();
545 // Require a model customization ID. Every VF Module definition must have one.
546 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
547 logger.debug("Missing required input: modelCustomizationUuid");
548 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
549 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
550 "VF Module ModelCustomizationUuid", "VDU", ErrorCode.DataError,
551 "Create VF Module: " + "Missing required input: modelCustomizationUuid");
553 throw new VnfException(error, MsoExceptionCategory.USERDATA);
556 // Clean up some inputs to make comparisons easier
557 if (requestType == null)
560 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
561 volumeGroupId = null;
563 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
564 baseVfModuleId = null;
566 if (inputs == null) {
567 // Create an empty set of inputs
568 inputs = new HashMap<>();
569 logger.debug("inputs == null - setting to empty");
571 this.sendMapToDebug(inputs);
574 // Check if this is for a "Volume" module
575 boolean isVolumeRequest = false;
576 if (requestType.startsWith("VOLUME")) {
577 isVolumeRequest = true;
580 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
583 // Build a default rollback object (no actions performed)
584 VnfRollback vfRollback = new VnfRollback();
585 vfRollback.setCloudSiteId(cloudSiteId);
586 vfRollback.setCloudOwner(cloudOwner);
587 vfRollback.setTenantId(tenantId);
588 vfRollback.setMsoRequest(msoRequest);
589 vfRollback.setRequestType(requestType);
590 vfRollback.setIsBase(false); // Until we know better
591 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
592 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
593 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
594 vfRollback.setMode("CFY");
596 rollback.value = vfRollback; // Default rollback - no updates performed
598 // Get the VNF/VF Module definition from the Catalog DB first.
599 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
601 VfModule vfModule = null;
602 VnfResource vnfResource = null;
603 VfModuleCustomization vfModuleCust = null;
607 vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
609 if (vfModuleCust == null) {
610 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
611 + modelCustomizationUuid;
613 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
614 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", ErrorCode.DataError,
616 throw new VnfException(error, MsoExceptionCategory.USERDATA);
618 logger.debug("Found vfModuleCust entry {}", vfModuleCust.toString());
621 // Get the vfModule and vnfResource records
622 vfModule = vfModuleCust.getVfModule();
623 vnfResource = vfModuleCust.getVfModule().getVnfResources();
624 } catch (Exception e) {
626 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
627 throw new VnfException("Exception during create VF " + e.getMessage());
630 // Perform a version check against cloudSite
631 // Obtain the cloud site information where we will create the VF Module
632 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
633 if (!cloudSiteOp.isPresent()) {
634 // If cloudSiteId is not present in the catalog DB, then default to multicloud
635 logger.debug("{} is not present in cloud_site catalog DB, defaulting to Multicloud plugin adapter",
638 CloudSite cloudSite = cloudSiteOp.get();
639 MavenLikeVersioning aicV = new MavenLikeVersioning();
640 aicV.setVersion(cloudSite.getCloudVersion());
642 String vnfMin = vnfResource.getAicVersionMin();
643 String vnfMax = vnfResource.getAicVersionMax();
645 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
646 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
649 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
650 + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: "
651 + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
652 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
653 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
655 throw new VnfException(error, MsoExceptionCategory.USERDATA);
661 VduInstance vduInstance = null;
662 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
664 // Use the VduPlugin.
665 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
667 long subStartTime1 = System.currentTimeMillis();
669 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleName);
670 } catch (VduException me) {
671 // Failed to query the VDU due to a plugin exception.
672 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
673 + tenantId + ": " + me;
674 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
675 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
676 "Exception - queryVdu", me);
678 // Convert to a generic VnfException
679 me.addContext("CreateVFModule");
680 throw new VnfException(me);
683 // More precise handling/messaging if the Module already exists
684 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
685 VduStateType status = vduInstance.getStatus().getState();
686 logger.debug("Found Existing VDU, status=" + status);
688 if (status == VduStateType.INSTANTIATED) {
689 if (failIfExists != null && failIfExists) {
691 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
692 + cloudSiteId + "/" + tenantId;
693 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(),
694 vfModuleName, cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu",
695 ErrorCode.DataError.getValue(), "VF Module " + vfModuleName + " already exists");
697 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
698 vduInstance.getVduInstanceId());
700 // Found existing deployment and client has not requested "failIfExists".
701 // Populate the outputs from the existing deployment.
703 vnfId.value = vduInstance.getVduInstanceId();
704 outputs.value = copyStringOutputs(vduInstance.getOutputs());
708 // Check through various detailed error cases
709 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING
710 || status == VduStateType.UPDATING) {
711 // fail - it's in progress - return meaningful error
712 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
713 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
714 + "; please wait for it to complete, or fix manually.";
715 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
716 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
717 "VF Module " + vfModuleName + " already exists");
719 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
720 vduInstance.getVduInstanceId());
721 } else if (status == VduStateType.FAILED) {
722 // fail - it exists and is in a FAILED state
723 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
724 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
725 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
726 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
727 "VF Module " + vfModuleName + " already exists and is in FAILED state");
729 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
730 vduInstance.getVduInstanceId());
731 } else if (status == VduStateType.UNKNOWN) {
732 // fail - it exists and is in a UNKNOWN state
733 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
734 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
735 + "; requires manual intervention.";
736 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
737 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
738 "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state");
740 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
741 vduInstance.getVduInstanceId());
743 // Unexpected, since all known status values have been tested for
744 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
745 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
746 + "; requires manual intervention.";
747 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
748 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
749 "VF Module " + vfModuleName + " already exists and is in an unknown state");
751 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
752 vduInstance.getVduInstanceId());
757 // Collect outputs from Base Modules and Volume Modules
758 Map<String, Object> baseModuleOutputs = null;
759 Map<String, Object> volumeGroupOutputs = null;
761 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
762 if (volumeGroupId != null) {
763 long subStartTime2 = System.currentTimeMillis();
764 VduInstance volumeVdu = null;
766 volumeVdu = vduPlugin.queryVdu(cloudInfo, volumeGroupId);
767 } catch (VduException me) {
768 // Failed to query the Volume Group VDU due to a plugin exception.
769 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
770 + cloudSiteId + "/" + tenantId + ": " + me;
771 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
772 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", ErrorCode.DataError.getValue(),
773 "Exception - queryVdu(volume)", me);
775 // Convert to a generic VnfException
776 me.addContext("CreateVFModule(QueryVolume)");
777 throw new VnfException(me);
780 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
781 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
782 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
783 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
784 cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)",
785 ErrorCode.BusinessProcesssError.getValue(),
786 "Create VFModule: Attached Volume Group " + "DOES NOT EXIST");
788 throw new VnfException(error, MsoExceptionCategory.USERDATA);
790 logger.debug("Found nested volume group");
791 volumeGroupOutputs = volumeVdu.getOutputs();
792 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
796 // If this is an Add-On Module, query the Base Module outputs
797 // Note: This will be performed whether or not the current request is for an
798 // Add-On Volume Group or Add-On VF Module
800 if (vfModule.getIsBase()) {
801 logger.debug("This is a BASE Module request");
802 vfRollback.setIsBase(true);
804 logger.debug("This is an Add-On Module request");
806 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
807 // Add-on Volume requests may or may not specify a base.
808 if (!isVolumeRequest && baseVfModuleId == null) {
809 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
812 if (baseVfModuleId != null) {
813 long subStartTime2 = System.currentTimeMillis();
814 VduInstance baseVdu = null;
816 baseVdu = vduPlugin.queryVdu(cloudInfo, baseVfModuleId);
817 } catch (MsoException me) {
818 // Failed to query the Base VF Module due to a Vdu Plugin exception.
819 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
820 + cloudSiteId + "/" + tenantId + ": " + me;
821 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
822 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", ErrorCode.DataError.getValue(),
823 "Exception - queryVdu(Base)", me);
825 // Convert to a generic VnfException
826 me.addContext("CreateVFModule(QueryBase)");
827 throw new VnfException(me);
830 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
831 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudOwner
832 + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
833 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(),
834 baseVfModuleId, cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)",
835 ErrorCode.BusinessProcesssError.getValue(), "Create VFModule: Base Module DOES NOT EXIST");
837 throw new VnfException(error, MsoExceptionCategory.USERDATA);
839 logger.debug("Found base module");
840 baseModuleOutputs = baseVdu.getOutputs();
841 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
847 // NOTE: For this section, heatTemplate is used for all template artifacts.
848 // In final implementation (post-POC), the template object would either be generic or there would
849 // be a separate DB Table/Object for different sub-orchestrators.
851 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
853 HeatTemplate heatTemplate = null;
854 HeatEnvironment heatEnvironment = null;
855 if (isVolumeRequest) {
856 heatTemplate = vfModule.getVolumeHeatTemplate();
857 heatEnvironment = vfModuleCust.getVolumeHeatEnv();
859 heatTemplate = vfModule.getModuleHeatTemplate();
860 heatEnvironment = vfModuleCust.getHeatEnvironment();
863 if (heatTemplate == null) {
864 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
865 + ", reqType=" + requestType;
866 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
867 vfModuleType, "VNF", ErrorCode.DataError.getValue(), error);
869 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
871 logger.debug("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
874 if (heatEnvironment == null) {
875 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
876 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
877 "OpenStack", ErrorCode.DataError.getValue(), error);
878 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
880 logger.debug("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
884 // Create the combined set of parameters from the incoming request, base-module outputs,
885 // volume-module outputs. Also, convert all variables to their native object types.
887 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
888 List<String> extraInputs = new ArrayList<String>();
890 Boolean skipInputChecks = false;
892 if (skipInputChecks) {
893 goldenInputs = new HashMap<String, Object>();
894 for (String key : inputs.keySet()) {
895 goldenInputs.put(key, inputs.get(key));
898 // Build maps for the parameters (including aliases) to simplify checks
899 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
901 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
902 logger.debug("paramSet has " + paramSet.size() + " entries");
904 for (HeatTemplateParam htp : paramSet) {
905 params.put(htp.getParamName(), htp);
908 String alias = htp.getParamAlias();
909 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
910 params.put(alias, htp);
914 // First, convert all inputs to their "template" type
915 for (String key : inputs.keySet()) {
916 if (params.containsKey(key)) {
917 Object value = convertInputValue(inputs.get(key), params.get(key));
919 goldenInputs.put(key, value);
921 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
922 + params.get(key).getParamType());
925 extraInputs.add(key);
929 if (!extraInputs.isEmpty()) {
930 // Add multicloud inputs
931 for (String key : MsoMulticloudUtils.MULTICLOUD_INPUTS) {
932 if (extraInputs.contains(key)) {
933 goldenInputs.put(key, inputs.get(key));
934 extraInputs.remove(key);
935 if (extraInputs.isEmpty()) {
940 logger.debug("Ignoring extra inputs: " + extraInputs);
943 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
944 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
945 for (String key : volumeGroupOutputs.keySet()) {
946 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
947 goldenInputs.put(key, volumeGroupOutputs.get(key));
952 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
953 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
954 for (String key : baseModuleOutputs.keySet()) {
955 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
956 goldenInputs.put(key, baseModuleOutputs.get(key));
961 // TODO: The model should support a mechanism to pre-assign default parameter values
962 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
963 // an Environment file. There is not a general mechanism in the model to handle this.
964 // For the general case, any such parameter/values can be added dynamically to the
965 // inputs (only if not already specified).
967 // Check that required parameters have been supplied from any of the sources
968 String missingParams = null;
969 boolean checkRequiredParameters = true;
971 String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
972 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
973 checkRequiredParameters = false;
974 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
975 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
977 } catch (Exception e) {
978 // No problem - default is true
979 logger.debug("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS,
983 // Do the actual parameter checking.
984 // Include looking at the ENV file as a valid definition of a parameter value.
985 // TODO: This handling of ENV applies only to Heat. A general mechanism to
986 // support pre-set parameter/values does not yet exist in the model.
988 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
989 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
990 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
991 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
992 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
993 logger.debug("Required parameter " + parm.getParamName()
994 + " appears to be in environment - do not count as missing");
996 logger.debug("adding to missing parameters list: " + parm.getParamName());
997 if (missingParams == null) {
998 missingParams = parm.getParamName();
1000 missingParams += "," + parm.getParamName();
1006 if (missingParams != null) {
1007 if (checkRequiredParameters) {
1008 // Problem - missing one or more required parameters
1009 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1010 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "VDU",
1011 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1012 logger.debug(error);
1013 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1015 logger.debug("found missing parameters [" + missingParams
1016 + "] - but checkRequiredParameters is false - " + "will not block");
1019 logger.debug("No missing parameters found - ok to proceed");
1022 } // NOTE: END PARAMETER CHECKING
1025 // Here we go... ready to deploy the VF Module.
1026 long instantiateVduStartTime = System.currentTimeMillis();
1027 if (backout == null)
1031 // Construct the VDU Model structure to pass to the targeted VduPlugin
1032 VduModelInfo vduModel = null;
1033 if (!isVolumeRequest) {
1034 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1036 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1039 // Invoke the VduPlugin to instantiate the VF Module
1040 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1042 } catch (VduException me) {
1043 // Failed to instantiate the VDU.
1044 me.addContext("CreateVFModule");
1045 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1047 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1048 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(), "MsoException - instantiateVdu", me);
1049 logger.debug(error);
1050 // Convert to a generic VnfException
1051 throw new VnfException(me);
1052 } catch (NullPointerException npe) {
1053 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1055 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1056 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(),
1057 "NullPointerException - instantiateVdu", npe);
1058 logger.debug(error);
1059 logger.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1060 throw new VnfException("NullPointerException during instantiateVdu");
1061 } catch (Exception e) {
1062 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1064 logger.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1065 logger.debug(error);
1066 throw new VnfException("Exception during instantiateVdu: " + e.getMessage());
1070 // Reach this point if create is successful.
1071 // Populate remaining rollback info and response parameters.
1072 vfRollback.setVnfCreated(true);
1073 vfRollback.setVnfId(vduInstance.getVduInstanceId());
1074 vnfId.value = vduInstance.getVduInstanceId();
1075 outputs.value = copyStringOutputs(vduInstance.getOutputs());
1077 rollback.value = vfRollback;
1079 logger.debug("VF Module " + vfModuleName + " successfully created");
1084 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId,
1085 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1087 logger.debug("Deleting VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1088 // Will capture execution time for metrics
1089 long startTime = System.currentTimeMillis();
1091 // Capture the output parameters on a delete, so need to query first
1092 VduInstance vduInstance = null;
1093 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
1095 // Use the VduPlugin.
1096 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
1099 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleId);
1100 } catch (VduException e) {
1101 // Failed to query the VDU due to a plugin exception.
1102 // Convert to a generic VnfException
1103 e.addContext("QueryVFModule");
1104 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
1105 + tenantId + ": " + e;
1106 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleId, cloudOwner,
1107 cloudSiteId, tenantId, "VDU", "QueryVFModule", ErrorCode.DataError.getValue(),
1108 "Exception - queryVDU", e);
1109 logger.debug(error);
1110 throw new VnfException(e);
1113 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1115 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1117 // Use the VduPlugin to delete the VDU.
1118 // The possible outcomes of deleteVdu are
1119 // - a vnfInstance object with status of DELETED (success)
1120 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1121 // - a vnfInstance object with status of FAILED (error)
1122 // Also, VduException could be thrown.
1123 long subStartTime = System.currentTimeMillis();
1125 // TODO: Get an appropriate timeout value - require access to the model
1126 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1127 } catch (VduException me) {
1128 me.addContext("DeleteVfModule");
1129 // Convert to a generic VnfException
1131 "Delete VF: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1132 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
1133 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(),
1134 "Exception - DeleteVdu: " + me.getMessage());
1135 logger.debug(error);
1136 throw new VnfException(me);
1139 // On success, nothing is returned.
1143 // Update VF Module not yet implemented for generic VDU plug-in model.
1145 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1146 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1147 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1148 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1149 throws VnfException {
1150 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1151 logger.debug("Update VF Module command attempted but not supported");
1152 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1156 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator" defined for the target
1157 * cloud. Should really be looking at the VNF Model (ochestration_mode) but we don't currently have access to that
1158 * in Query and Delete cases.
1160 private VduPlugin getVduPlugin(String cloudSiteId, String cloudOwner) {
1161 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
1162 if (cloudSiteOp.isPresent()) {
1163 CloudSite cloudSite = cloudSiteOp.get();
1164 String orchestrator = cloudSite.getOrchestrator();
1166 if (orchestrator.equalsIgnoreCase("CLOUDIFY")) {
1167 return cloudifyUtils;
1168 } else if (orchestrator.equalsIgnoreCase("HEAT")) {
1170 } else if (orchestrator.equalsIgnoreCase("MULTICLOUD")) {
1171 return multicloudUtils;
1173 // Default if cloudSite record exists - return HEAT plugin - will fail later
1177 // Default if no cloudSite record exists - return multicloud plugin
1178 return multicloudUtils;