2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (c) 2019 Samsung
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
24 * This VNF Adapter implementation is based on the VDU Plugin model. It assumes that each VF Module definition in the
25 * MSO catalog is expressed via a set of template and/or file artifacts that are appropriate for some specific
26 * sub-orchestrator that provides an implementation of the VduPlugin interface. This adapter handles all of the common
27 * VF Module logic, including: - catalog lookups for artifact retrieval - parameter filtering and validation - base and
28 * volume module queries - rollback logic - logging and error handling
30 * Then based on the orchestration mode of the VNF, it will invoke different VDU plug-ins to perform the low level
31 * instantiations, deletions, and queries. At this time, the set of available plug-ins is hard-coded, though in the
32 * future a dynamic selection is expected (e.g. via a service-provider interface).
34 package org.onap.so.adapters.vnf;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
41 import java.util.Optional;
43 import javax.jws.WebService;
44 import javax.xml.ws.Holder;
45 import org.onap.so.logger.LoggingAnchor;
46 import org.onap.so.adapters.vdu.CloudInfo;
47 import org.onap.so.adapters.vdu.VduException;
48 import org.onap.so.adapters.vdu.VduInstance;
49 import org.onap.so.adapters.vdu.VduModelInfo;
50 import org.onap.so.adapters.vdu.VduPlugin;
51 import org.onap.so.adapters.vdu.VduStateType;
52 import org.onap.so.adapters.vdu.VduStatus;
53 import org.onap.so.adapters.vdu.mapper.VfModuleCustomizationToVduMapper;
54 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
55 import org.onap.so.adapters.vnf.exceptions.VnfException;
56 import org.onap.so.cloud.CloudConfig;
57 import org.onap.so.db.catalog.beans.CloudSite;
58 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
59 import org.onap.so.db.catalog.beans.HeatEnvironment;
60 import org.onap.so.db.catalog.beans.HeatTemplate;
61 import org.onap.so.db.catalog.beans.HeatTemplateParam;
62 import org.onap.so.db.catalog.beans.VfModule;
63 import org.onap.so.db.catalog.beans.VfModuleCustomization;
64 import org.onap.so.db.catalog.beans.VnfResource;
65 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
66 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
67 import org.onap.so.entity.MsoRequest;
68 import org.onap.so.logger.ErrorCode;
69 import org.onap.so.logger.MessageEnum;
70 import org.onap.so.openstack.beans.VnfRollback;
71 import org.onap.so.openstack.beans.VnfStatus;
72 import org.onap.so.openstack.exceptions.MsoException;
73 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
74 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
75 import org.onap.so.openstack.utils.MsoHeatUtils;
76 import org.onap.so.openstack.utils.MsoKeystoneUtils;
77 import org.onap.so.openstack.utils.MsoMulticloudUtils;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80 import org.springframework.beans.factory.annotation.Autowired;
81 import org.springframework.core.env.Environment;
82 import org.springframework.stereotype.Component;
83 import org.springframework.transaction.annotation.Transactional;
84 import com.fasterxml.jackson.core.JsonParseException;
85 import com.fasterxml.jackson.databind.JsonNode;
86 import com.fasterxml.jackson.databind.ObjectMapper;
88 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
89 targetNamespace = "http://org.onap.so/vnf")
92 public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
94 private static Logger logger = LoggerFactory.getLogger(MsoVnfPluginAdapterImpl.class);
96 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
97 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
100 protected CloudConfig cloudConfig;
103 private VFModuleCustomizationRepository vfModuleCustomRepo;
106 private Environment environment;
109 protected MsoKeystoneUtils keystoneUtils;
112 protected MsoCloudifyUtils cloudifyUtils;
115 protected MsoHeatUtils heatUtils;
118 protected MsoMulticloudUtils multicloudUtils;
121 protected VfModuleCustomizationToVduMapper vduMapper;
124 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
126 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
128 public MsoVnfPluginAdapterImpl() {
133 * Health Check web method. Does nothing but return to show the adapter is deployed.
136 public void healthCheck() {
137 logger.debug("Health check call in VNF Plugin Adapter");
141 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
145 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
146 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
147 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
148 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
149 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
150 logger.debug("CreateVNF command attempted but not supported");
151 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
155 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
159 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
160 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
161 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
162 throws VnfException {
163 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
164 logger.debug("UpdateVNF command attempted but not supported");
165 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
169 * This is the "Query VNF" web service implementation.
171 * This really should be QueryVfModule, but nobody ever changed it.
173 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
174 * also be reflected back as its ID.
176 * @param cloudSiteId CLLI code of the cloud site in which to query
177 * @param tenantId Openstack tenant identifier
178 * @param vnfNameOrId VNF Name or ID to query
179 * @param msoRequest Request tracking information for logs
180 * @param vnfExists Flag reporting the result of the query
181 * @param vnfId Holder for output VNF ID
182 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
185 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfNameOrId,
186 MsoRequest msoRequest, Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
187 Holder<Map<String, String>> outputs) throws VnfException {
188 logger.debug("Querying VNF " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
190 // Will capture execution time for metrics
191 long startTime = System.currentTimeMillis();
192 long subStartTime = System.currentTimeMillis();
194 VduInstance vduInstance = null;
195 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
197 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
200 vduInstance = vduPlugin.queryVdu(cloudInfo, vnfNameOrId);
201 } catch (VduException e) {
202 // Failed to query the VDU due to a plugin exception.
203 // Convert to a generic VnfException
204 e.addContext("QueryVNF");
205 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
207 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfNameOrId, cloudOwner,
208 cloudSiteId, tenantId, "VDU", "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryVDU",
211 throw new VnfException(e);
214 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
215 vnfExists.value = Boolean.TRUE;
216 status.value = vduStatusToVnfStatus(vduInstance);
217 vnfId.value = vduInstance.getVduInstanceId();
218 outputs.value = copyStringOutputs(vduInstance.getOutputs());
220 logger.debug("VNF {} found, ID = {}", vnfNameOrId, vnfId.value);
222 vnfExists.value = Boolean.FALSE;
223 status.value = VnfStatus.NOTFOUND;
225 outputs.value = new HashMap<String, String>(); // Return as an empty map
227 logger.debug("VNF {} not found", vnfNameOrId);
234 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
238 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
239 throws VnfException {
241 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
242 logger.debug("DeleteVNF command attempted but not supported");
243 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
247 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
248 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
249 * to undo the creation.
251 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
254 public void rollbackVnf(VnfRollback rollback) throws VnfException {
255 long startTime = System.currentTimeMillis();
256 // rollback may be null (e.g. if stack already existed when Create was called)
257 if (rollback == null) {
258 logger.info(LoggingAnchor.THREE, MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
262 // Don't rollback if nothing was done originally
263 if (!rollback.getVnfCreated()) {
267 // Get the elements of the VnfRollback object for easier access
268 String cloudSiteId = rollback.getCloudSiteId();
269 String cloudOwner = rollback.getCloudOwner();
270 String tenantId = rollback.getTenantId();
271 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
273 String vfModuleId = rollback.getVfModuleStackId();
275 logger.debug("Rolling Back VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
277 VduInstance vduInstance = null;
279 // Use the VduPlugin to delete the VF Module.
280 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
282 long subStartTime = System.currentTimeMillis();
284 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
286 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
288 logger.debug("Rolled back VDU instantiation: {}", vduInstance.getVduInstanceId());
289 } catch (VduException ve) {
290 // Failed to rollback the VF Module due to a plugin exception.
291 // Convert to a generic VnfException
292 ve.addContext("RollbackVFModule");
293 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
294 + tenantId + ": " + ve;
295 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
296 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(), "Exception - DeleteVdu",
299 throw new VnfException(ve);
305 private VnfStatus vduStatusToVnfStatus(VduInstance vdu) {
306 // Determine the status based on last action & status
307 // DeploymentInfo object should be enhanced to report a better status internally.
308 VduStatus vduStatus = vdu.getStatus();
309 VduStateType status = vduStatus.getState();
311 if (status == null) {
312 return VnfStatus.UNKNOWN;
313 } else if (status == VduStateType.NOTFOUND) {
314 return VnfStatus.NOTFOUND;
315 } else if (status == VduStateType.INSTANTIATED) {
316 return VnfStatus.ACTIVE;
317 } else if (status == VduStateType.FAILED) {
318 return VnfStatus.FAILED;
321 return VnfStatus.UNKNOWN;
325 * Normalize an input value to an Object, based on the target parameter type. If the type is not recognized, it will
326 * just be returned unchanged (as a string).
328 private Object convertInputValue(Object inputValue, HeatTemplateParam templateParam) {
329 String type = templateParam.getParamType();
330 logger.debug("Parameter: {} is of type ", templateParam.getParamName(), type);
332 if (type.equalsIgnoreCase("number")) {
334 return Integer.valueOf(inputValue.toString());
335 } catch (Exception e) {
336 logger.debug("Unable to convert " + inputValue + " to an integer!", e);
339 } else if (type.equalsIgnoreCase("json")) {
341 JsonNode jsonNode = JSON_MAPPER.readTree(JSON_MAPPER.writeValueAsString(inputValue));
343 } catch (Exception e) {
344 logger.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
347 } else if (type.equalsIgnoreCase("boolean")) {
348 return new Boolean(inputValue.toString());
351 // Nothing else matched. Return the original string
355 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
356 Map<String, String> stringOutputs = new HashMap<String, String>();
357 for (String key : stackOutputs.keySet()) {
358 if (stackOutputs.get(key) instanceof String) {
359 stringOutputs.put(key, (String) stackOutputs.get(key));
360 } else if (stackOutputs.get(key) instanceof Integer) {
362 String str = "" + stackOutputs.get(key);
363 stringOutputs.put(key, str);
364 } catch (Exception e) {
365 logger.debug("Unable to add {} to outputs", key, e);
367 } else if (stackOutputs.get(key) instanceof JsonNode) {
369 String str = this.convertNode((JsonNode) stackOutputs.get(key));
370 stringOutputs.put(key, str);
371 } catch (Exception e) {
372 logger.debug("Unable to add {} to outputs - exception converting JsonNode", key, e);
374 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
376 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
377 stringOutputs.put(key, str);
378 } catch (Exception e) {
379 logger.debug("Unable to add {} to outputs - exception converting LinkedHashMap", key, e);
383 String str = stackOutputs.get(key).toString();
384 stringOutputs.put(key, str);
385 } catch (Exception e) {
386 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),
391 return stringOutputs;
395 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
397 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
398 if (inputs == null) {
400 } else if (inputs.size() < 1) {
401 sb.append("\tEMPTY");
403 for (String str : inputs.keySet()) {
406 outputString = inputs.get(str).toString();
407 } catch (Exception e) {
408 outputString = "Unable to call toString() on the value for " + str;
410 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
413 logger.debug(sb.toString());
417 private void sendMapToDebug(Map<String, Object> inputs) {
419 StringBuilder sb = new StringBuilder("inputs:");
420 if (inputs == null) {
422 } else if (inputs.size() < 1) {
423 sb.append("\tEMPTY");
425 for (String str : inputs.keySet()) {
426 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
429 logger.debug(sb.toString());
433 private String convertNode(final JsonNode node) {
435 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
436 final String json = JSON_MAPPER.writeValueAsString(obj);
438 } catch (JsonParseException jpe) {
439 logger.debug("Error converting json to string " + jpe.getMessage());
440 } catch (Exception e) {
441 logger.debug("Error converting json to string " + e.getMessage());
443 return "[Error converting json to string]";
446 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
447 if (objectMap == null) {
450 Map<String, String> stringMap = new HashMap<String, String>();
451 for (String key : objectMap.keySet()) {
452 if (!stringMap.containsKey(key)) {
453 Object obj = objectMap.get(key);
454 if (obj instanceof String) {
455 stringMap.put(key, (String) objectMap.get(key));
456 } else if (obj instanceof JsonNode) {
457 // This is a bit of mess - but I think it's the least impacting
458 // let's convert it BACK to a string - then it will get converted back later
460 String str = this.convertNode((JsonNode) obj);
461 stringMap.put(key, str);
462 } catch (Exception e) {
463 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
464 // okay in this instance - only string values (fqdn) are expected to be needed
466 } else if (obj instanceof java.util.LinkedHashMap) {
467 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
469 String str = JSON_MAPPER.writeValueAsString(obj);
470 stringMap.put(key, str);
471 } catch (Exception e) {
472 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
474 } else if (obj instanceof Integer) {
476 String str = "" + obj;
477 stringMap.put(key, str);
478 } catch (Exception e) {
479 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
483 String str = obj.toString();
484 stringMap.put(key, str);
485 } catch (Exception e) {
487 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")",
498 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
499 * type in the specified cloud and tenant. The tenant must exist before this service is called.
501 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
502 * value of the 'failIfExists' parameter.
504 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
505 * error will be returned. Within the catalog, each VF Module references (among other things) a collection of
506 * artifacts that are used to deploy the required cloud resources (VMs, networks, etc.).
508 * Depending on the module templates, a variable set of input parameters will be defined, some of which are
509 * required. The caller is responsible to pass the necessary input data for the module or an error will be thrown.
511 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
512 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
513 * VF module is successfully created but the orchestration fails on a subsequent step.
515 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
516 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
517 * @param tenantId Openstack tenant identifier
518 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
519 * modelCustomizationUuid
520 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
521 * also captured by modelCustomizationUuid
522 * @param vnfId - VNF ID
523 * @param vfModuleName Name to be assigned to the new VF Module
524 * @param vfModuleId Id fo the new VF Module
525 * @param requestType Indicates if this is a Volume Group or Module request
526 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
527 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
528 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
529 * @param inputs Map of key=value inputs for VNF stack creation
530 * @param failIfExists Flag whether already existing VNF should be considered
531 * @param backout Flag whether to suppress automatic backout (for testing)
532 * @param msoRequest Request tracking information for logs
533 * @param vnfId Holder for output VF Module instance ID in the cloud
534 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
535 * @param rollback Holder for returning VnfRollback object
538 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
539 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
540 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
541 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
542 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
543 // Will capture execution time for metrics
544 long startTime = System.currentTimeMillis();
546 // Require a model customization ID. Every VF Module definition must have one.
547 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
548 logger.debug("Missing required input: modelCustomizationUuid");
549 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
550 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
551 "VF Module ModelCustomizationUuid", "VDU", ErrorCode.DataError,
552 "Create VF Module: " + "Missing required input: modelCustomizationUuid");
554 throw new VnfException(error, MsoExceptionCategory.USERDATA);
557 // Clean up some inputs to make comparisons easier
558 if (requestType == null)
561 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
562 volumeGroupId = null;
564 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
565 baseVfModuleId = null;
567 if (inputs == null) {
568 // Create an empty set of inputs
569 inputs = new HashMap<>();
570 logger.debug("inputs == null - setting to empty");
572 this.sendMapToDebug(inputs);
575 // Check if this is for a "Volume" module
576 boolean isVolumeRequest = false;
577 if (requestType.startsWith("VOLUME")) {
578 isVolumeRequest = true;
581 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
584 // Build a default rollback object (no actions performed)
585 VnfRollback vfRollback = new VnfRollback();
586 vfRollback.setCloudSiteId(cloudSiteId);
587 vfRollback.setCloudOwner(cloudOwner);
588 vfRollback.setTenantId(tenantId);
589 vfRollback.setMsoRequest(msoRequest);
590 vfRollback.setRequestType(requestType);
591 vfRollback.setIsBase(false); // Until we know better
592 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
593 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
594 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
595 vfRollback.setMode("CFY");
597 rollback.value = vfRollback; // Default rollback - no updates performed
599 // Get the VNF/VF Module definition from the Catalog DB first.
600 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
602 VfModule vfModule = null;
603 VnfResource vnfResource = null;
604 VfModuleCustomization vfModuleCust = null;
608 vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
610 if (vfModuleCust == null) {
611 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
612 + modelCustomizationUuid;
614 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
615 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", ErrorCode.DataError,
617 throw new VnfException(error, MsoExceptionCategory.USERDATA);
619 logger.debug("Found vfModuleCust entry {}", vfModuleCust.toString());
622 // Get the vfModule and vnfResource records
623 vfModule = vfModuleCust.getVfModule();
624 vnfResource = vfModuleCust.getVfModule().getVnfResources();
625 } catch (Exception e) {
627 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
628 throw new VnfException("Exception during create VF " + e.getMessage());
631 // Perform a version check against cloudSite
632 // Obtain the cloud site information where we will create the VF Module
633 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
634 if (!cloudSiteOp.isPresent()) {
635 // If cloudSiteId is not present in the catalog DB, then default to multicloud
636 logger.debug("{} is not present in cloud_site catalog DB, defaulting to Multicloud plugin adapter",
639 CloudSite cloudSite = cloudSiteOp.get();
640 MavenLikeVersioning aicV = new MavenLikeVersioning();
641 aicV.setVersion(cloudSite.getCloudVersion());
643 String vnfMin = vnfResource.getAicVersionMin();
644 String vnfMax = vnfResource.getAicVersionMax();
646 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
647 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
650 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
651 + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: "
652 + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
653 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
654 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
656 throw new VnfException(error, MsoExceptionCategory.USERDATA);
662 VduInstance vduInstance = null;
663 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
665 // Use the VduPlugin.
666 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
668 long subStartTime1 = System.currentTimeMillis();
670 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleName);
671 } catch (VduException me) {
672 // Failed to query the VDU due to a plugin exception.
673 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
674 + tenantId + ": " + me;
675 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
676 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(), "Exception - queryVdu",
679 // Convert to a generic VnfException
680 me.addContext("CreateVFModule");
681 throw new VnfException(me);
684 // More precise handling/messaging if the Module already exists
685 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
686 VduStateType status = vduInstance.getStatus().getState();
687 logger.debug("Found Existing VDU, status=" + status);
689 if (status == VduStateType.INSTANTIATED) {
690 if (failIfExists != null && failIfExists) {
692 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
693 + cloudSiteId + "/" + tenantId;
694 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
695 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
696 "VF Module " + vfModuleName + " already exists");
698 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
699 vduInstance.getVduInstanceId());
701 // Found existing deployment and client has not requested "failIfExists".
702 // Populate the outputs from the existing deployment.
704 vnfId.value = vduInstance.getVduInstanceId();
705 outputs.value = copyStringOutputs(vduInstance.getOutputs());
709 // Check through various detailed error cases
710 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING
711 || status == VduStateType.UPDATING) {
712 // fail - it's in progress - return meaningful error
713 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
714 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
715 + "; please wait for it to complete, or fix manually.";
716 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
717 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
718 "VF Module " + vfModuleName + " already exists");
720 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
721 vduInstance.getVduInstanceId());
722 } else if (status == VduStateType.FAILED) {
723 // fail - it exists and is in a FAILED state
724 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
725 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
726 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
727 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
728 "VF Module " + vfModuleName + " already exists and is in FAILED state");
730 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
731 vduInstance.getVduInstanceId());
732 } else if (status == VduStateType.UNKNOWN) {
733 // fail - it exists and is in a UNKNOWN state
734 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
735 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
736 + "; requires manual intervention.";
737 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
738 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
739 "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state");
741 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
742 vduInstance.getVduInstanceId());
744 // Unexpected, since all known status values have been tested for
745 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
746 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
747 + "; requires manual intervention.";
748 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
749 cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(),
750 "VF Module " + vfModuleName + " already exists and is in an unknown state");
752 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
753 vduInstance.getVduInstanceId());
758 // Collect outputs from Base Modules and Volume Modules
759 Map<String, Object> baseModuleOutputs = null;
760 Map<String, Object> volumeGroupOutputs = null;
762 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
763 if (volumeGroupId != null) {
764 long subStartTime2 = System.currentTimeMillis();
765 VduInstance volumeVdu = null;
767 volumeVdu = vduPlugin.queryVdu(cloudInfo, volumeGroupId);
768 } catch (VduException me) {
769 // Failed to query the Volume Group VDU due to a plugin exception.
770 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
771 + cloudSiteId + "/" + tenantId + ": " + me;
772 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner,
773 cloudSiteId, tenantId, "VDU", "queryVdu(volume)", ErrorCode.DataError.getValue(),
774 "Exception - queryVdu(volume)", me);
776 // Convert to a generic VnfException
777 me.addContext("CreateVFModule(QueryVolume)");
778 throw new VnfException(me);
781 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
782 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
783 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
784 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner,
785 cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)",
786 ErrorCode.BusinessProcesssError.getValue(),
787 "Create VFModule: Attached Volume Group " + "DOES NOT EXIST");
789 throw new VnfException(error, MsoExceptionCategory.USERDATA);
791 logger.debug("Found nested volume group");
792 volumeGroupOutputs = volumeVdu.getOutputs();
793 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
797 // If this is an Add-On Module, query the Base Module outputs
798 // Note: This will be performed whether or not the current request is for an
799 // Add-On Volume Group or Add-On VF Module
801 if (vfModule.getIsBase()) {
802 logger.debug("This is a BASE Module request");
803 vfRollback.setIsBase(true);
805 logger.debug("This is an Add-On Module request");
807 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
808 // Add-on Volume requests may or may not specify a base.
809 if (!isVolumeRequest && baseVfModuleId == null) {
810 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
813 if (baseVfModuleId != null) {
814 long subStartTime2 = System.currentTimeMillis();
815 VduInstance baseVdu = null;
817 baseVdu = vduPlugin.queryVdu(cloudInfo, baseVfModuleId);
818 } catch (MsoException me) {
819 // Failed to query the Base VF Module due to a Vdu Plugin exception.
820 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
821 + cloudSiteId + "/" + tenantId + ": " + me;
822 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
823 cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", ErrorCode.DataError.getValue(),
824 "Exception - queryVdu(Base)", me);
826 // Convert to a generic VnfException
827 me.addContext("CreateVFModule(QueryBase)");
828 throw new VnfException(me);
831 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
832 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudOwner
833 + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
834 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudOwner,
835 cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)",
836 ErrorCode.BusinessProcesssError.getValue(), "Create VFModule: Base Module DOES NOT EXIST");
838 throw new VnfException(error, MsoExceptionCategory.USERDATA);
840 logger.debug("Found base module");
841 baseModuleOutputs = baseVdu.getOutputs();
842 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
848 // NOTE: For this section, heatTemplate is used for all template artifacts.
849 // In final implementation (post-POC), the template object would either be generic or there would
850 // be a separate DB Table/Object for different sub-orchestrators.
852 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
854 HeatTemplate heatTemplate = null;
855 HeatEnvironment heatEnvironment = null;
856 if (isVolumeRequest) {
857 heatTemplate = vfModule.getVolumeHeatTemplate();
858 heatEnvironment = vfModuleCust.getVolumeHeatEnv();
860 heatTemplate = vfModule.getModuleHeatTemplate();
861 heatEnvironment = vfModuleCust.getHeatEnvironment();
864 if (heatTemplate == null) {
865 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
866 + ", modelCustomizationUuid=" + modelCustomizationUuid + ", vfModuleUuid=" + vfModule.getModelUUID()
867 + ", reqType=" + requestType;
868 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
869 vfModuleType, "VNF", ErrorCode.DataError.getValue(), error);
871 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
873 logger.debug("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
876 if (heatEnvironment == null) {
877 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + ", modelCustomizationUuid="
878 + modelCustomizationUuid + ", vfModuleUuid=" + vfModule.getModelUUID() + ", reqType=" + requestType;
879 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
880 "OpenStack", ErrorCode.DataError.getValue(), error);
881 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
883 logger.debug("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
887 // Create the combined set of parameters from the incoming request, base-module outputs,
888 // volume-module outputs. Also, convert all variables to their native object types.
890 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
891 List<String> extraInputs = new ArrayList<String>();
893 Boolean skipInputChecks = false;
895 if (skipInputChecks) {
896 goldenInputs = new HashMap<String, Object>();
897 for (String key : inputs.keySet()) {
898 goldenInputs.put(key, inputs.get(key));
901 // Build maps for the parameters (including aliases) to simplify checks
902 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
904 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
905 logger.debug("paramSet has " + paramSet.size() + " entries");
907 for (HeatTemplateParam htp : paramSet) {
908 params.put(htp.getParamName(), htp);
911 String alias = htp.getParamAlias();
912 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
913 params.put(alias, htp);
917 // First, convert all inputs to their "template" type
918 for (String key : inputs.keySet()) {
919 if (params.containsKey(key)) {
920 Object value = convertInputValue(inputs.get(key), params.get(key));
922 goldenInputs.put(key, value);
924 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
925 + params.get(key).getParamType());
928 extraInputs.add(key);
932 if (!extraInputs.isEmpty()) {
933 // Add multicloud inputs
934 for (String key : MsoMulticloudUtils.MULTICLOUD_INPUTS) {
935 if (extraInputs.contains(key)) {
936 goldenInputs.put(key, inputs.get(key));
937 extraInputs.remove(key);
938 if (extraInputs.isEmpty()) {
943 logger.debug("Ignoring extra inputs: " + extraInputs);
946 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
947 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
948 for (String key : volumeGroupOutputs.keySet()) {
949 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
950 goldenInputs.put(key, volumeGroupOutputs.get(key));
955 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
956 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
957 for (String key : baseModuleOutputs.keySet()) {
958 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
959 goldenInputs.put(key, baseModuleOutputs.get(key));
964 // TODO: The model should support a mechanism to pre-assign default parameter values
965 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
966 // an Environment file. There is not a general mechanism in the model to handle this.
967 // For the general case, any such parameter/values can be added dynamically to the
968 // inputs (only if not already specified).
970 // Check that required parameters have been supplied from any of the sources
971 String missingParams = null;
972 boolean checkRequiredParameters = true;
974 String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
975 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
976 checkRequiredParameters = false;
977 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
978 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
980 } catch (Exception e) {
981 // No problem - default is true
982 logger.debug("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS,
986 // Do the actual parameter checking.
987 // Include looking at the ENV file as a valid definition of a parameter value.
988 // TODO: This handling of ENV applies only to Heat. A general mechanism to
989 // support pre-set parameter/values does not yet exist in the model.
991 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
992 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
993 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
994 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
995 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
996 logger.debug("Required parameter " + parm.getParamName()
997 + " appears to be in environment - do not count as missing");
999 logger.debug("adding to missing parameters list: " + parm.getParamName());
1000 if (missingParams == null) {
1001 missingParams = parm.getParamName();
1003 missingParams += "," + parm.getParamName();
1009 if (missingParams != null) {
1010 if (checkRequiredParameters) {
1011 // Problem - missing one or more required parameters
1012 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1013 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "VDU",
1014 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1015 logger.debug(error);
1016 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1018 logger.debug("found missing parameters [" + missingParams
1019 + "] - but checkRequiredParameters is false - " + "will not block");
1022 logger.debug("No missing parameters found - ok to proceed");
1025 } // NOTE: END PARAMETER CHECKING
1028 // Here we go... ready to deploy the VF Module.
1029 long instantiateVduStartTime = System.currentTimeMillis();
1030 if (backout == null)
1034 // Construct the VDU Model structure to pass to the targeted VduPlugin
1035 VduModelInfo vduModel = null;
1036 if (!isVolumeRequest) {
1037 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1039 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1042 // Invoke the VduPlugin to instantiate the VF Module
1043 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1045 } catch (VduException me) {
1046 // Failed to instantiate the VDU.
1047 me.addContext("CreateVFModule");
1048 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1050 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1051 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(), "MsoException - instantiateVdu", me);
1052 logger.debug(error);
1053 // Convert to a generic VnfException
1054 throw new VnfException(me);
1055 } catch (NullPointerException npe) {
1056 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1058 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1059 cloudSiteId, tenantId, "VDU", ErrorCode.DataError.getValue(),
1060 "NullPointerException - instantiateVdu", npe);
1061 logger.debug(error);
1062 logger.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1063 throw new VnfException("NullPointerException during instantiateVdu");
1064 } catch (Exception e) {
1065 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1067 logger.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1068 logger.debug(error);
1069 throw new VnfException("Exception during instantiateVdu: " + e.getMessage());
1073 // Reach this point if create is successful.
1074 // Populate remaining rollback info and response parameters.
1075 vfRollback.setVnfCreated(true);
1076 vfRollback.setVnfId(vduInstance.getVduInstanceId());
1077 vnfId.value = vduInstance.getVduInstanceId();
1078 outputs.value = copyStringOutputs(vduInstance.getOutputs());
1080 rollback.value = vfRollback;
1082 logger.debug("VF Module " + vfModuleName + " successfully created");
1087 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId,
1088 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1090 logger.debug("Deleting VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1091 // Will capture execution time for metrics
1092 long startTime = System.currentTimeMillis();
1094 // Capture the output parameters on a delete, so need to query first
1095 VduInstance vduInstance = null;
1096 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, cloudOwner, tenantId, null);
1098 // Use the VduPlugin.
1099 VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner);
1102 vduInstance = vduPlugin.queryVdu(cloudInfo, vfModuleId);
1103 } catch (VduException e) {
1104 // Failed to query the VDU due to a plugin exception.
1105 // Convert to a generic VnfException
1106 e.addContext("QueryVFModule");
1107 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
1108 + tenantId + ": " + e;
1109 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleId, cloudOwner,
1110 cloudSiteId, tenantId, "VDU", "QueryVFModule", ErrorCode.DataError.getValue(),
1111 "Exception - queryVDU", e);
1112 logger.debug(error);
1113 throw new VnfException(e);
1116 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1118 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1120 // Use the VduPlugin to delete the VDU.
1121 // The possible outcomes of deleteVdu are
1122 // - a vnfInstance object with status of DELETED (success)
1123 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1124 // - a vnfInstance object with status of FAILED (error)
1125 // Also, VduException could be thrown.
1126 long subStartTime = System.currentTimeMillis();
1128 // TODO: Get an appropriate timeout value - require access to the model
1129 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1130 } catch (VduException me) {
1131 me.addContext("DeleteVfModule");
1132 // Convert to a generic VnfException
1134 "Delete VF: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1135 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
1136 cloudSiteId, tenantId, "VDU", "DeleteVdu", ErrorCode.DataError.getValue(),
1137 "Exception - DeleteVdu: " + me.getMessage());
1138 logger.debug(error);
1139 throw new VnfException(me);
1142 // On success, nothing is returned.
1146 // Update VF Module not yet implemented for generic VDU plug-in model.
1148 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1149 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1150 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1151 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1152 throws VnfException {
1153 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1154 logger.debug("Update VF Module command attempted but not supported");
1155 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1159 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator" defined for the target
1160 * cloud. Should really be looking at the VNF Model (ochestration_mode) but we don't currently have access to that
1161 * in Query and Delete cases.
1163 private VduPlugin getVduPlugin(String cloudSiteId, String cloudOwner) {
1164 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
1165 if (cloudSiteOp.isPresent()) {
1166 CloudSite cloudSite = cloudSiteOp.get();
1167 String orchestrator = cloudSite.getOrchestrator();
1169 if (orchestrator.equalsIgnoreCase("CLOUDIFY")) {
1170 return cloudifyUtils;
1171 } else if (orchestrator.equalsIgnoreCase("HEAT")) {
1173 } else if (orchestrator.equalsIgnoreCase("MULTICLOUD")) {
1174 return multicloudUtils;
1176 // Default if cloudSite record exists - return HEAT plugin - will fail later
1180 // Default if no cloudSite record exists - return multicloud plugin
1181 return multicloudUtils;