2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
22 * This VNF Adapter implementation is based on the VDU Plugin model. It assumes that each
23 * VF Module definition in the MSO catalog is expressed via a set of template and/or file
24 * artifacts that are appropriate for some specific sub-orchestrator that provides an
25 * implementation of the VduPlugin interface. This adapter handles all of the common
26 * VF Module logic, including:
27 * - catalog lookups for artifact retrieval
28 * - parameter filtering and validation
29 * - base and volume module queries
31 * - logging and error handling
33 * Then based on the orchestration mode of the VNF, it will invoke different VDU plug-ins
34 * to perform the low level instantiations, deletions, and queries. At this time, the
35 * set of available plug-ins is hard-coded, though in the future a dynamic selection
36 * is expected (e.g. via a service-provider interface).
38 package org.onap.so.adapters.vnf;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.List;
45 import java.util.Optional;
48 import javax.jws.WebService;
49 import javax.xml.ws.Holder;
51 import org.onap.so.adapters.vdu.CloudInfo;
52 import org.onap.so.adapters.vdu.VduException;
53 import org.onap.so.adapters.vdu.VduInstance;
54 import org.onap.so.adapters.vdu.VduModelInfo;
55 import org.onap.so.adapters.vdu.VduPlugin;
56 import org.onap.so.adapters.vdu.VduStateType;
57 import org.onap.so.adapters.vdu.VduStatus;
58 import org.onap.so.adapters.vdu.mapper.VfModuleCustomizationToVduMapper;
59 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
60 import org.onap.so.adapters.vnf.exceptions.VnfException;
61 import org.onap.so.cloud.CloudConfig;
62 import org.onap.so.db.catalog.beans.CloudSite;
63 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
64 import org.onap.so.db.catalog.beans.HeatEnvironment;
65 import org.onap.so.db.catalog.beans.HeatTemplate;
66 import org.onap.so.db.catalog.beans.HeatTemplateParam;
67 import org.onap.so.db.catalog.beans.VfModule;
68 import org.onap.so.db.catalog.beans.VfModuleCustomization;
69 import org.onap.so.db.catalog.beans.VnfResource;
70 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
71 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
72 import org.onap.so.entity.MsoRequest;
73 import org.onap.so.logger.MessageEnum;
75 import org.onap.so.logger.MsoLogger;
76 import org.onap.so.openstack.beans.VnfRollback;
77 import org.onap.so.openstack.beans.VnfStatus;
78 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
79 import org.onap.so.openstack.exceptions.MsoException;
80 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
81 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
82 import org.onap.so.openstack.utils.MsoHeatUtils;
83 import org.onap.so.openstack.utils.MsoKeystoneUtils;
84 import org.onap.so.openstack.utils.MsoMulticloudUtils;
85 import org.springframework.beans.factory.annotation.Autowired;
86 import org.springframework.core.env.Environment;
87 import org.springframework.stereotype.Component;
88 import org.springframework.transaction.annotation.Transactional;
90 import com.fasterxml.jackson.core.JsonParseException;
91 import com.fasterxml.jackson.databind.JsonNode;
92 import com.fasterxml.jackson.databind.ObjectMapper;
94 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf")
97 public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
99 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
100 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfPluginAdapterImpl.class);
102 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
103 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
106 protected CloudConfig cloudConfig;
109 private VFModuleCustomizationRepository vfModuleCustomRepo;
112 private Environment environment;
115 protected MsoKeystoneUtils keystoneUtils;
118 protected MsoCloudifyUtils cloudifyUtils;
121 protected MsoHeatUtils heatUtils;
124 protected MsoMulticloudUtils multicloudUtils;
127 protected VfModuleCustomizationToVduMapper vduMapper;
130 * Health Check web method. Does nothing but return to show the adapter is deployed.
133 public void healthCheck () {
134 LOGGER.debug ("Health check call in VNF Plugin Adapter");
138 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
139 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
141 public MsoVnfPluginAdapterImpl() {
146 * This is the "Create VNF" web service implementation.
147 * This function is now unsupported and will return an error.
151 public void createVnf (String cloudSiteId,
157 String volumeGroupHeatStackId,
158 Map <String, Object> inputs,
159 Boolean failIfExists,
161 Boolean enableBridge,
162 MsoRequest msoRequest,
163 Holder <String> vnfId,
164 Holder <Map <String, String>> outputs,
165 Holder <VnfRollback> rollback)
168 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
169 LOGGER.debug ("CreateVNF command attempted but not supported");
170 throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
174 * This is the "Update VNF" web service implementation.
175 * This function is now unsupported and will return an error.
179 public void updateVnf (String cloudSiteId,
185 String volumeGroupHeatStackId,
186 Map <String, Object> inputs,
187 MsoRequest msoRequest,
188 Holder <Map <String, String>> outputs,
189 Holder <VnfRollback> rollback)
192 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
193 LOGGER.debug ("UpdateVNF command attempted but not supported");
194 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
198 * This is the "Query VNF" web service implementation.
200 * This really should be QueryVfModule, but nobody ever changed it.
202 * The method returns an indicator that the VNF exists, along with its status and outputs.
203 * The input "vnfName" will also be reflected back as its ID.
205 * @param cloudSiteId CLLI code of the cloud site in which to query
206 * @param tenantId Openstack tenant identifier
207 * @param vnfNameOrId VNF Name or ID to query
208 * @param msoRequest Request tracking information for logs
209 * @param vnfExists Flag reporting the result of the query
210 * @param vnfId Holder for output VNF ID
211 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
214 public void queryVnf (String cloudSiteId,
217 MsoRequest msoRequest,
218 Holder <Boolean> vnfExists,
219 Holder <String> vnfId,
220 Holder <VnfStatus> status,
221 Holder <Map <String, String>> outputs)
224 MsoLogger.setLogContext (msoRequest);
225 MsoLogger.setServiceName ("QueryVnf");
226 LOGGER.debug ("Querying VNF " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId);
228 // Will capture execution time for metrics
229 long startTime = System.currentTimeMillis ();
230 long subStartTime = System.currentTimeMillis ();
232 VduInstance vduInstance = null;
233 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null);
235 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
238 vduInstance = vduPlugin.queryVdu (cloudInfo, vnfNameOrId);
239 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vnfNameOrId);
241 catch (VduException e) {
242 // Failed to query the VDU due to a plugin exception.
243 // Convert to a generic VnfException
244 e.addContext ("QueryVNF");
245 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId + ": " + e;
246 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vnfNameOrId);
247 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfNameOrId, cloudSiteId, tenantId, "VDU", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e);
248 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
249 throw new VnfException (e);
252 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
253 vnfExists.value = Boolean.TRUE;
254 status.value = vduStatusToVnfStatus(vduInstance);
255 vnfId.value = vduInstance.getVduInstanceId();
256 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
258 LOGGER.debug ("VNF " + vnfNameOrId + " found, ID = " + vnfId.value);
261 vnfExists.value = Boolean.FALSE;
262 status.value = VnfStatus.NOTFOUND;
264 outputs.value = new HashMap <String, String> (); // Return as an empty map
266 LOGGER.debug ("VNF " + vnfNameOrId + " not found");
268 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
274 * This is the "Delete VNF" web service implementation.
275 * This function is now unsupported and will return an error.
279 public void deleteVnf (String cloudSiteId,
282 MsoRequest msoRequest) throws VnfException {
283 MsoLogger.setLogContext (msoRequest);
284 MsoLogger.setServiceName ("DeleteVnf");
286 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
287 LOGGER.debug ("DeleteVNF command attempted but not supported");
288 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
292 * This web service endpoint will rollback a previous Create VNF operation.
293 * A rollback object is returned to the client in a successful creation
294 * response. The client can pass that object as-is back to the rollbackVnf
295 * operation to undo the creation.
297 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
298 * but APIs were apparently never updated.
301 public void rollbackVnf (VnfRollback rollback) throws VnfException {
302 long startTime = System.currentTimeMillis ();
303 MsoLogger.setServiceName ("RollbackVnf");
304 // rollback may be null (e.g. if stack already existed when Create was called)
305 if (rollback == null) {
306 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf", MsoLogger.getServiceName());
307 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
311 // Don't rollback if nothing was done originally
312 if (!rollback.getVnfCreated()) {
313 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back");
317 // Get the elements of the VnfRollback object for easier access
318 String cloudSiteId = rollback.getCloudSiteId ();
319 String tenantId = rollback.getTenantId ();
320 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null);
322 String vfModuleId = rollback.getVfModuleStackId ();
324 MsoLogger.setLogContext (rollback.getMsoRequest());
326 LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
328 VduInstance vduInstance = null;
330 // Use the VduPlugin to delete the VF Module.
331 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
333 long subStartTime = System.currentTimeMillis ();
335 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
336 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
338 LOGGER.debug("Rolled back VDU instantiation: " + vduInstance.getVduInstanceId());
339 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VDU Plugin", "VDU", "DeleteVdu", null);
341 catch (VduException ve) {
342 // Failed to rollback the VF Module due to a plugin exception.
343 // Convert to a generic VnfException
344 ve.addContext ("RollbackVFModule");
345 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + ve;
346 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "DeleteVdu", null);
347 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu", ve);
348 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
349 throw new VnfException (ve);
351 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module");
356 private VnfStatus vduStatusToVnfStatus (VduInstance vdu) {
357 // Determine the status based on last action & status
358 // DeploymentInfo object should be enhanced to report a better status internally.
359 VduStatus vduStatus = vdu.getStatus();
360 VduStateType status = vduStatus.getState();
362 if (status == null) {
363 return VnfStatus.UNKNOWN;
365 else if (status == VduStateType.NOTFOUND) {
366 return VnfStatus.NOTFOUND;
368 else if (status == VduStateType.INSTANTIATED) {
369 return VnfStatus.ACTIVE;
371 else if (status == VduStateType.FAILED) {
372 return VnfStatus.FAILED;
375 return VnfStatus.UNKNOWN;
379 * Normalize an input value to an Object, based on the target parameter type.
380 * If the type is not recognized, it will just be returned unchanged (as a string).
382 private Object convertInputValue (Object inputValue, HeatTemplateParam templateParam)
384 String type = templateParam.getParamType();
385 LOGGER.debug("Parameter: " + templateParam.getParamName() + " is of type " + type);
387 if (type.equalsIgnoreCase("number")) {
389 return Integer.valueOf(inputValue.toString());
391 catch (Exception e) {
392 LOGGER.debug("Unable to convert " + inputValue + " to an integer!" , e);
395 } else if (type.equalsIgnoreCase("json")) {
397 JsonNode jsonNode = JSON_MAPPER.readTree(JSON_MAPPER.writeValueAsString(inputValue));
400 catch (Exception e) {
401 LOGGER.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
404 } else if (type.equalsIgnoreCase("boolean")) {
405 return new Boolean(inputValue.toString());
408 // Nothing else matched. Return the original string
412 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
413 Map <String, String> stringOutputs = new HashMap <String, String> ();
414 for (String key : stackOutputs.keySet ()) {
415 if (stackOutputs.get (key) instanceof String) {
416 stringOutputs.put (key, (String) stackOutputs.get (key));
417 } else if (stackOutputs.get(key) instanceof Integer) {
419 String str = "" + stackOutputs.get(key);
420 stringOutputs.put(key, str);
421 } catch (Exception e) {
422 LOGGER.debug("Unable to add " + key + " to outputs", e);
424 } else if (stackOutputs.get(key) instanceof JsonNode) {
426 String str = this.convertNode((JsonNode) stackOutputs.get(key));
427 stringOutputs.put(key, str);
428 } catch (Exception e) {
429 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode", e);
431 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
433 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
434 stringOutputs.put(key, str);
435 } catch (Exception e) {
436 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap", e);
440 String str = stackOutputs.get(key).toString();
441 stringOutputs.put(key, str);
442 } catch (Exception e) {
443 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(), e);
447 return stringOutputs;
451 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
453 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
454 if (inputs == null) {
457 else if (inputs.size() < 1) {
458 sb.append("\tEMPTY");
460 for (String str : inputs.keySet()) {
463 outputString = inputs.get(str).toString();
464 } catch (Exception e) {
465 outputString = "Unable to call toString() on the value for " + str;
467 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
470 LOGGER.debug(sb.toString());
474 private void sendMapToDebug(Map<String, Object> inputs) {
476 StringBuilder sb = new StringBuilder("inputs:");
477 if (inputs == null) {
480 else if (inputs.size() < 1) {
481 sb.append("\tEMPTY");
483 for (String str : inputs.keySet()) {
484 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
487 LOGGER.debug(sb.toString());
491 private String convertNode(final JsonNode node) {
493 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
494 final String json = JSON_MAPPER.writeValueAsString(obj);
496 } catch (JsonParseException jpe) {
497 LOGGER.debug("Error converting json to string " + jpe.getMessage());
498 } catch (Exception e) {
499 LOGGER.debug("Error converting json to string " + e.getMessage());
501 return "[Error converting json to string]";
504 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
505 if (objectMap == null) {
508 Map<String, String> stringMap = new HashMap<String, String>();
509 for (String key : objectMap.keySet()) {
510 if (!stringMap.containsKey(key)) {
511 Object obj = objectMap.get(key);
512 if (obj instanceof String) {
513 stringMap.put(key, (String) objectMap.get(key));
514 } else if (obj instanceof JsonNode ){
515 // This is a bit of mess - but I think it's the least impacting
516 // let's convert it BACK to a string - then it will get converted back later
518 String str = this.convertNode((JsonNode) obj);
519 stringMap.put(key, str);
520 } catch (Exception e) {
521 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key, e);
522 //okay in this instance - only string values (fqdn) are expected to be needed
524 } else if (obj instanceof java.util.LinkedHashMap) {
525 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
527 String str = JSON_MAPPER.writeValueAsString(obj);
528 stringMap.put(key, str);
529 } catch (Exception e) {
530 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key, e);
532 } else if (obj instanceof Integer) {
534 String str = "" + obj;
535 stringMap.put(key, str);
536 } catch (Exception e) {
537 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key, e);
541 String str = obj.toString();
542 stringMap.put(key, str);
543 } catch (Exception e) {
544 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")", e);
554 * This is the "Create VF Module" web service implementation.
555 * It will instantiate a new VF Module of the requested type in the specified cloud
556 * and tenant. The tenant must exist before this service is called.
558 * If a VF Module with the same name already exists, this can be considered a
559 * success or failure, depending on the value of the 'failIfExists' parameter.
561 * All VF Modules are defined in the MSO catalog. The caller must request one of
562 * the pre-defined module types or an error will be returned. Within the catalog,
563 * each VF Module references (among other things) a collection of artifacts that
564 * are used to deploy the required cloud resources (VMs, networks, etc.).
566 * Depending on the module templates, a variable set of input parameters will
567 * be defined, some of which are required. The caller is responsible to
568 * pass the necessary input data for the module or an error will be thrown.
570 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
571 * object. This last object can be passed as-is to the rollbackVnf operation to
572 * undo everything that was created for the Module. This is useful if a VF module
573 * is successfully created but the orchestration fails on a subsequent step.
575 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
576 * @param tenantId Openstack tenant identifier
577 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
578 * Deprecated - should use modelCustomizationUuid
579 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
580 * Deprecated - VF Module versions also captured by modelCustomizationUuid
581 * @param vnfId - VNF ID
582 * @param vfModuleName Name to be assigned to the new VF Module
583 * @param vfModuleId Id fo the new VF Module
584 * @param requestType Indicates if this is a Volume Group or Module request
585 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
586 * to attach to a VF Module
587 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
588 * this is an Add-on module
589 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
590 * the use of vfModuleType.
591 * @param inputs Map of key=value inputs for VNF stack creation
592 * @param failIfExists Flag whether already existing VNF should be considered
593 * @param backout Flag whether to suppress automatic backout (for testing)
594 * @param msoRequest Request tracking information for logs
595 * @param vnfId Holder for output VF Module instance ID in the cloud
596 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
597 * @param rollback Holder for returning VnfRollback object
600 public void createVfModule(String cloudSiteId,
608 String volumeGroupId,
609 String baseVfModuleId,
610 String modelCustomizationUuid,
611 Map <String, Object> inputs,
612 Boolean failIfExists,
614 Boolean enableBridge,
615 MsoRequest msoRequest,
616 Holder <String> vnfId,
617 Holder <Map <String, String>> outputs,
618 Holder <VnfRollback> rollback)
621 // Will capture execution time for metrics
622 long startTime = System.currentTimeMillis ();
624 MsoLogger.setLogContext (msoRequest);
625 MsoLogger.setServiceName ("CreateVfModule");
627 // Require a model customization ID. Every VF Module definition must have one.
628 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
629 LOGGER.debug("Missing required input: modelCustomizationUuid");
630 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
631 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
632 "VF Module ModelCustomizationUuid", "null", "VDU", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid");
633 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
634 throw new VnfException(error, MsoExceptionCategory.USERDATA);
637 // Clean up some inputs to make comparisons easier
638 if (requestType == null)
641 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
642 volumeGroupId = null;
644 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
645 baseVfModuleId = null;
647 if (inputs == null) {
648 // Create an empty set of inputs
649 inputs = new HashMap<>();
650 LOGGER.debug("inputs == null - setting to empty");
652 this.sendMapToDebug(inputs);
655 // Check if this is for a "Volume" module
656 boolean isVolumeRequest = false;
657 if (requestType.startsWith("VOLUME")) {
658 isVolumeRequest = true;
661 LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId);
663 // Build a default rollback object (no actions performed)
664 VnfRollback vfRollback = new VnfRollback();
665 vfRollback.setCloudSiteId(cloudSiteId);
666 vfRollback.setTenantId(tenantId);
667 vfRollback.setMsoRequest(msoRequest);
668 vfRollback.setRequestType(requestType);
669 vfRollback.setIsBase(false); // Until we know better
670 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
671 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
672 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
673 vfRollback.setMode("CFY");
675 rollback.value = vfRollback; // Default rollback - no updates performed
677 // Get the VNF/VF Module definition from the Catalog DB first.
678 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
680 VfModule vfModule = null;
681 VnfResource vnfResource = null;
682 VfModuleCustomization vfModuleCust = null;
685 vfModuleCust = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
687 if (vfModuleCust == null) {
688 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid;
690 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
691 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error);
692 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
693 throw new VnfException(error, MsoExceptionCategory.USERDATA);
695 LOGGER.debug("Found vfModuleCust entry " + vfModuleCust.toString());
698 // Get the vfModule and vnfResource records
699 vfModule = vfModuleCust.getVfModule();
700 vnfResource = vfModuleCust.getVfModule().getVnfResources();
702 catch (Exception e) {
704 LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage());
705 throw new VnfException("Exception during create VF " + e.getMessage());
708 // Perform a version check against cloudSite
709 // Obtain the cloud site information where we will create the VF Module
710 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId);
711 if (!cloudSiteOp.isPresent()) {
712 throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId));
714 CloudSite cloudSite = cloudSiteOp.get();
715 MavenLikeVersioning aicV = new MavenLikeVersioning();
716 aicV.setVersion(cloudSite.getCloudVersion());
717 Boolean usingMulticloud = getUsingMulticloud(cloudSite);
719 String vnfMin = vnfResource.getAicVersionMin();
720 String vnfMax = vnfResource.getAicVersionMax();
722 if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) ||
723 (vnfMax != null && aicV.isMoreRecentThan(vnfMax)))
726 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
727 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
729 throw new VnfException(error, MsoExceptionCategory.USERDATA);
734 VduInstance vduInstance = null;
735 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null);
737 // Use the VduPlugin.
738 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
740 // First, look up to see if the VF already exists, unless using multicloud adapter
742 long subStartTime1 = System.currentTimeMillis ();
743 if (!usingMulticloud) {
745 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName);
746 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "QueryVDU", vfModuleName);
748 catch (VduException me) {
749 // Failed to query the VDU due to a plugin exception.
750 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
751 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "Exception - queryVdu", me);
752 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu", vfModuleName);
753 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
755 // Convert to a generic VnfException
756 me.addContext ("CreateVFModule");
757 throw new VnfException (me);
761 // More precise handling/messaging if the Module already exists
762 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
763 VduStateType status = vduInstance.getStatus().getState();
764 LOGGER.debug ("Found Existing VDU, status=" + status);
766 if (status == VduStateType.INSTANTIATED) {
767 if (failIfExists != null && failIfExists) {
769 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
770 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists");
771 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
772 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
774 // Found existing deployment and client has not requested "failIfExists".
775 // Populate the outputs from the existing deployment.
777 vnfId.value = vduInstance.getVduInstanceId();
778 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
779 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)");
783 // Check through various detailed error cases
784 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING || status == VduStateType.UPDATING) {
785 // fail - it's in progress - return meaningful error
786 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
787 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists");
788 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
789 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
791 else if (status == VduStateType.FAILED) {
792 // fail - it exists and is in a FAILED state
793 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
794 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in FAILED state");
795 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
796 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
798 else if (status == VduStateType.UNKNOWN) {
799 // fail - it exists and is in a UNKNOWN state
800 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
801 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state");
802 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
803 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
806 // Unexpected, since all known status values have been tested for
807 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
808 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in an unknown state");
809 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
810 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
815 // Collect outputs from Base Modules and Volume Modules
816 Map<String, Object> baseModuleOutputs = null;
817 Map<String, Object> volumeGroupOutputs = null;
819 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
820 if (!usingMulticloud && volumeGroupId != null) {
821 long subStartTime2 = System.currentTimeMillis ();
822 VduInstance volumeVdu = null;
824 volumeVdu = vduPlugin.queryVdu (cloudInfo, volumeGroupId);
825 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu", volumeGroupId);
827 catch (VduException me) {
828 // Failed to query the Volume Group VDU due to a plugin exception.
829 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
830 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(volume)", me);
831 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(volume)", volumeGroupId);
832 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
834 // Convert to a generic VnfException
835 me.addContext ("CreateVFModule(QueryVolume)");
836 throw new VnfException (me);
839 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
840 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
841 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached Volume Group DOES NOT EXIST");
842 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
844 throw new VnfException (error, MsoExceptionCategory.USERDATA);
846 LOGGER.debug("Found nested volume group");
847 volumeGroupOutputs = volumeVdu.getOutputs();
848 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
852 // If this is an Add-On Module, query the Base Module outputs
853 // Note: This will be performed whether or not the current request is for an
854 // Add-On Volume Group or Add-On VF Module
856 if (vfModule.getIsBase()) {
857 LOGGER.debug("This is a BASE Module request");
858 vfRollback.setIsBase(true);
860 LOGGER.debug("This is an Add-On Module request");
862 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
863 // Add-on Volume requests may or may not specify a base.
864 if (!isVolumeRequest && baseVfModuleId == null) {
865 LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided");
868 // Need to verify if multicloud needs to have the vaseVfModuleId passed to it. Ignoring this for now.
869 if (!usingMulticloud && baseVfModuleId != null) {
870 long subStartTime2 = System.currentTimeMillis ();
871 VduInstance baseVdu = null;
873 baseVdu = vduPlugin.queryVdu (cloudInfo, baseVfModuleId);
874 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu(Base)", baseVfModuleId);
876 catch (MsoException me) {
877 // Failed to query the Base VF Module due to a Vdu Plugin exception.
878 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
879 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(Base)", me);
880 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(Base)", baseVfModuleId);
881 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
883 // Convert to a generic VnfException
884 me.addContext ("CreateVFModule(QueryBase)");
885 throw new VnfException (me);
888 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
889 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
890 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module DOES NOT EXIST");
891 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
893 throw new VnfException (error, MsoExceptionCategory.USERDATA);
895 LOGGER.debug("Found base module");
896 baseModuleOutputs = baseVdu.getOutputs();
897 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
903 // NOTE: For this section, heatTemplate is used for all template artifacts.
904 // In final implementation (post-POC), the template object would either be generic or there would
905 // be a separate DB Table/Object for different sub-orchestrators.
907 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
909 HeatTemplate heatTemplate = null;
910 HeatEnvironment heatEnvironment = null;
911 if (isVolumeRequest) {
912 heatTemplate = vfModule.getVolumeHeatTemplate();
913 heatEnvironment = vfModuleCust.getVolumeHeatEnv();
915 heatTemplate = vfModule.getModuleHeatTemplate();
916 heatEnvironment = vfModuleCust.getHeatEnvironment();
919 if (heatTemplate == null) {
920 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType;
921 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "VNF", "", MsoLogger.ErrorCode.DataError, error);
922 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
923 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
925 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
928 if (heatEnvironment == null) {
929 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
930 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
931 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
932 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
934 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
938 // Create the combined set of parameters from the incoming request, base-module outputs,
939 // volume-module outputs. Also, convert all variables to their native object types.
941 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
942 List<String> extraInputs = new ArrayList<String>();
944 Boolean skipInputChecks = false;
946 if (skipInputChecks) {
947 goldenInputs = new HashMap<String,Object>();
948 for (String key : inputs.keySet()) {
949 goldenInputs.put(key, inputs.get(key));
953 // Build maps for the parameters (including aliases) to simplify checks
954 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
956 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
957 LOGGER.debug("paramSet has " + paramSet.size() + " entries");
959 for (HeatTemplateParam htp : paramSet) {
960 params.put(htp.getParamName(), htp);
963 String alias = htp.getParamAlias();
964 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
965 params.put(alias, htp);
969 // First, convert all inputs to their "template" type
970 for (String key : inputs.keySet()) {
971 if (params.containsKey(key)) {
972 Object value = convertInputValue(inputs.get(key), params.get(key));
974 goldenInputs.put(key, value);
977 LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType());
980 extraInputs.add(key);
984 if (!extraInputs.isEmpty()) {
985 // Add multicloud inputs
986 boolean multicloudInputs = false;
987 for (String key : MsoMulticloudUtils.MULTICLOUD_INPUTS) {
988 if (extraInputs.contains(key)) {
989 goldenInputs.put(key, inputs.get(key));
990 extraInputs.remove(key);
991 multicloudInputs = true;
992 if (extraInputs.isEmpty()) {
997 LOGGER.debug("Ignoring extra inputs: " + extraInputs);
1000 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
1001 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
1002 for (String key : volumeGroupOutputs.keySet()) {
1003 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
1004 goldenInputs.put(key, volumeGroupOutputs.get(key));
1009 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
1010 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
1011 for (String key : baseModuleOutputs.keySet()) {
1012 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
1013 goldenInputs.put(key, baseModuleOutputs.get(key));
1018 // TODO: The model should support a mechanism to pre-assign default parameter values
1019 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
1020 // an Environment file. There is not a general mechanism in the model to handle this.
1021 // For the general case, any such parameter/values can be added dynamically to the
1022 // inputs (only if not already specified).
1024 // Check that required parameters have been supplied from any of the sources
1025 String missingParams = null;
1026 boolean checkRequiredParameters = true;
1028 String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
1029 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1030 checkRequiredParameters = false;
1031 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1032 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
1034 } catch (Exception e) {
1035 // No problem - default is true
1036 LOGGER.debug ("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS, e);
1039 // Do the actual parameter checking.
1040 // Include looking at the ENV file as a valid definition of a parameter value.
1041 // TODO: This handling of ENV applies only to Heat. A general mechanism to
1042 // support pre-set parameter/values does not yet exist in the model.
1044 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1045 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
1046 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1047 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1048 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1049 LOGGER.debug ("Required parameter " + parm.getParamName ()
1050 + " appears to be in environment - do not count as missing");
1052 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1053 if (missingParams == null) {
1054 missingParams = parm.getParamName ();
1056 missingParams += "," + parm.getParamName ();
1062 if (missingParams != null) {
1063 if (checkRequiredParameters) {
1064 // Problem - missing one or more required parameters
1065 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1066 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "VDU", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1067 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1068 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1070 LOGGER.debug ("found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - will not block");
1073 LOGGER.debug ("No missing parameters found - ok to proceed");
1076 } // NOTE: END PARAMETER CHECKING
1079 // Here we go... ready to deploy the VF Module.
1080 long instantiateVduStartTime = System.currentTimeMillis ();
1081 if (backout == null) backout = true;
1084 // Construct the VDU Model structure to pass to the targeted VduPlugin
1085 VduModelInfo vduModel = null;
1086 if (! isVolumeRequest) {
1087 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1089 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1092 // Invoke the VduPlugin to instantiate the VF Module
1093 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1095 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "instantiateVdu", vfModuleName);
1097 catch (VduException me) {
1098 // Failed to instantiate the VDU.
1099 me.addContext ("CreateVFModule");
1100 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1101 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "instantiateVdu", vfModuleName);
1102 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "MsoException - instantiateVdu", me);
1103 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1104 // Convert to a generic VnfException
1105 throw new VnfException (me);
1107 catch (NullPointerException npe) {
1108 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1109 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error, "VDU", "instantiateVdu", vfModuleName);
1110 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "NullPointerException - instantiateVdu", npe);
1111 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
1112 LOGGER.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1113 throw new VnfException ("NullPointerException during instantiateVdu");
1115 catch (Exception e) {
1116 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + e;
1117 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error, "VDU", "instantiateVdu", vfModuleName);
1118 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error);
1119 LOGGER.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1120 throw new VnfException("Exception during instantiateVdu: " + e.getMessage());
1124 // Reach this point if create is successful.
1125 // Populate remaining rollback info and response parameters.
1126 vfRollback.setVnfCreated (true);
1127 vfRollback.setVnfId (vduInstance.getVduInstanceId());
1128 vnfId.value = vduInstance.getVduInstanceId();
1129 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
1131 rollback.value = vfRollback;
1133 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1134 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1139 public void deleteVfModule (String cloudSiteId,
1142 MsoRequest msoRequest,
1143 Holder <Map <String, String>> outputs) throws VnfException
1145 MsoLogger.setLogContext (msoRequest);
1146 MsoLogger.setServiceName ("DeleteVfModule");
1148 LOGGER.debug ("Deleting VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
1149 // Will capture execution time for metrics
1150 long startTime = System.currentTimeMillis ();
1152 // Capture the output parameters on a delete, so need to query first
1153 VduInstance vduInstance = null;
1154 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null);
1156 // Use the VduPlugin.
1157 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
1160 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleId);
1161 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vfModuleId);
1163 catch (VduException e) {
1164 // Failed to query the VDU due to a plugin exception.
1165 // Convert to a generic VnfException
1166 e.addContext ("QueryVFModule");
1167 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + e;
1168 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vfModuleId);
1169 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "QueryVFModule", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e);
1170 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1171 throw new VnfException (e);
1174 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1175 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1177 // Use the VduPlugin to delete the VDU.
1178 // The possible outcomes of deleteVdu are
1179 // - a vnfInstance object with status of DELETED (success)
1180 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1181 // - a vnfInstance object with status of FAILED (error)
1182 // Also, VduException could be thrown.
1183 long subStartTime = System.currentTimeMillis ();
1185 // TODO: Get an appropriate timeout value - require access to the model
1186 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1187 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from deleteVdu", "VDU", "DeleteVdu", vfModuleId);
1188 } catch (VduException me) {
1189 me.addContext ("DeleteVfModule");
1190 // Convert to a generic VnfException
1191 String error = "Delete VF: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1192 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteVdu", "DeleteVdu", vfModuleId);
1193 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu: " + me.getMessage());
1194 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1195 throw new VnfException (me);
1198 // On success, nothing is returned.
1199 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1203 // Update VF Module not yet implemented for generic VDU plug-in model.
1205 public void updateVfModule (String cloudSiteId,
1211 String volumeGroupHeatStackId,
1212 String baseVfHeatStackId,
1213 String vfModuleStackId,
1214 String modelCustomizationUuid,
1215 Map <String, Object> inputs,
1216 MsoRequest msoRequest,
1217 Holder <Map <String, String>> outputs,
1218 Holder <VnfRollback> rollback) throws VnfException
1220 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1221 LOGGER.debug ("Update VF Module command attempted but not supported");
1222 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1226 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator"
1227 * defined for the target cloud. Should really be looking at the VNF Model (ochestration_mode)
1228 * but we don't currently have access to that in Query and Delete cases.
1230 private VduPlugin getVduPlugin (String cloudSiteId) {
1231 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
1232 if (cloudSiteOp.isPresent()) {
1233 CloudSite cloudSite = cloudSiteOp.get();
1234 String orchestrator = cloudSite.getOrchestrator();
1236 if (orchestrator.equalsIgnoreCase("CLOUDIFY")) {
1237 return cloudifyUtils;
1239 else if (orchestrator.equalsIgnoreCase("HEAT")) {
1242 if (orchestrator.equalsIgnoreCase("MULTICLOUD")) {
1243 LOGGER.debug ("Got MulticloudUtils for vduPlugin");
1244 return multicloudUtils; }
1246 // Default - return HEAT plugin, though will fail later
1250 private Boolean getUsingMulticloud (CloudSite cloudSite) {
1251 if (cloudSite.getOrchestrator().equalsIgnoreCase("MULTICLOUD")) {