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;
74 import org.onap.so.logger.MsoAlarmLogger;
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.springframework.beans.factory.annotation.Autowired;
85 import org.springframework.core.env.Environment;
86 import org.springframework.stereotype.Component;
87 import org.springframework.transaction.annotation.Transactional;
89 import com.fasterxml.jackson.core.JsonParseException;
90 import com.fasterxml.jackson.databind.JsonNode;
91 import com.fasterxml.jackson.databind.ObjectMapper;
93 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf")
96 public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
98 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
99 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfPluginAdapterImpl.class);
100 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
101 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
102 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
105 protected CloudConfig cloudConfig;
108 private VFModuleCustomizationRepository vfModuleCustomRepo;
111 private Environment environment;
114 protected MsoKeystoneUtils keystoneUtils;
117 protected MsoCloudifyUtils cloudifyUtils;
120 protected MsoHeatUtils heatUtils;
123 protected VfModuleCustomizationToVduMapper vduMapper;
126 * Health Check web method. Does nothing but return to show the adapter is deployed.
129 public void healthCheck () {
130 LOGGER.debug ("Health check call in VNF Plugin Adapter");
134 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
135 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
137 public MsoVnfPluginAdapterImpl() {
142 * This is the "Create VNF" web service implementation.
143 * This function is now unsupported and will return an error.
147 public void createVnf (String cloudSiteId,
153 String volumeGroupHeatStackId,
154 Map <String, String> inputs,
155 Boolean failIfExists,
157 Boolean enableBridge,
158 MsoRequest msoRequest,
159 Holder <String> vnfId,
160 Holder <Map <String, String>> outputs,
161 Holder <VnfRollback> rollback)
164 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
165 LOGGER.debug ("CreateVNF command attempted but not supported");
166 throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
170 * This is the "Update VNF" web service implementation.
171 * This function is now unsupported and will return an error.
175 public void updateVnf (String cloudSiteId,
181 String volumeGroupHeatStackId,
182 Map <String, String> inputs,
183 MsoRequest msoRequest,
184 Holder <Map <String, String>> outputs,
185 Holder <VnfRollback> rollback)
188 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
189 LOGGER.debug ("UpdateVNF command attempted but not supported");
190 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
194 * This is the "Query VNF" web service implementation.
196 * This really should be QueryVfModule, but nobody ever changed it.
198 * The method returns an indicator that the VNF exists, along with its status and outputs.
199 * The input "vnfName" will also be reflected back as its ID.
201 * @param cloudSiteId CLLI code of the cloud site in which to query
202 * @param tenantId Openstack tenant identifier
203 * @param vnfNameOrId VNF Name or ID to query
204 * @param msoRequest Request tracking information for logs
205 * @param vnfExists Flag reporting the result of the query
206 * @param vnfId Holder for output VNF ID
207 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
210 public void queryVnf (String cloudSiteId,
213 MsoRequest msoRequest,
214 Holder <Boolean> vnfExists,
215 Holder <String> vnfId,
216 Holder <VnfStatus> status,
217 Holder <Map <String, String>> outputs)
220 MsoLogger.setLogContext (msoRequest);
221 MsoLogger.setServiceName ("QueryVnf");
222 LOGGER.debug ("Querying VNF " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId);
224 // Will capture execution time for metrics
225 long startTime = System.currentTimeMillis ();
226 long subStartTime = System.currentTimeMillis ();
228 VduInstance vduInstance = null;
229 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null);
231 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
234 vduInstance = vduPlugin.queryVdu (cloudInfo, vnfNameOrId);
235 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vnfNameOrId);
237 catch (VduException e) {
238 // Failed to query the VDU due to a plugin exception.
239 // Convert to a generic VnfException
240 e.addContext ("QueryVNF");
241 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId + ": " + e;
242 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vnfNameOrId);
243 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfNameOrId, cloudSiteId, tenantId, "VDU", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e);
244 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
245 throw new VnfException (e);
248 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
249 vnfExists.value = Boolean.TRUE;
250 status.value = vduStatusToVnfStatus(vduInstance);
251 vnfId.value = vduInstance.getVduInstanceId();
252 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
254 LOGGER.debug ("VNF " + vnfNameOrId + " found, ID = " + vnfId.value);
257 vnfExists.value = Boolean.FALSE;
258 status.value = VnfStatus.NOTFOUND;
260 outputs.value = new HashMap <String, String> (); // Return as an empty map
262 LOGGER.debug ("VNF " + vnfNameOrId + " not found");
264 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
270 * This is the "Delete VNF" web service implementation.
271 * This function is now unsupported and will return an error.
275 public void deleteVnf (String cloudSiteId,
278 MsoRequest msoRequest) throws VnfException {
279 MsoLogger.setLogContext (msoRequest);
280 MsoLogger.setServiceName ("DeleteVnf");
282 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
283 LOGGER.debug ("DeleteVNF command attempted but not supported");
284 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
288 * This web service endpoint will rollback a previous Create VNF operation.
289 * A rollback object is returned to the client in a successful creation
290 * response. The client can pass that object as-is back to the rollbackVnf
291 * operation to undo the creation.
293 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
294 * but APIs were apparently never updated.
297 public void rollbackVnf (VnfRollback rollback) throws VnfException {
298 long startTime = System.currentTimeMillis ();
299 MsoLogger.setServiceName ("RollbackVnf");
300 // rollback may be null (e.g. if stack already existed when Create was called)
301 if (rollback == null) {
302 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf", MsoLogger.getServiceName());
303 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
307 // Don't rollback if nothing was done originally
308 if (!rollback.getVnfCreated()) {
309 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back");
313 // Get the elements of the VnfRollback object for easier access
314 String cloudSiteId = rollback.getCloudSiteId ();
315 String tenantId = rollback.getTenantId ();
316 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null);
318 String vfModuleId = rollback.getVfModuleStackId ();
320 MsoLogger.setLogContext (rollback.getMsoRequest());
322 LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
324 VduInstance vduInstance = null;
326 // Use the VduPlugin to delete the VF Module.
327 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
329 long subStartTime = System.currentTimeMillis ();
331 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
332 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
334 LOGGER.debug("Rolled back VDU instantiation: " + vduInstance.getVduInstanceId());
335 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VDU Plugin", "VDU", "DeleteVdu", null);
337 catch (VduException ve) {
338 // Failed to rollback the VF Module due to a plugin exception.
339 // Convert to a generic VnfException
340 ve.addContext ("RollbackVFModule");
341 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + ve;
342 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "DeleteVdu", null);
343 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu", ve);
344 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
345 throw new VnfException (ve);
347 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module");
352 private VnfStatus vduStatusToVnfStatus (VduInstance vdu) {
353 // Determine the status based on last action & status
354 // DeploymentInfo object should be enhanced to report a better status internally.
355 VduStatus vduStatus = vdu.getStatus();
356 VduStateType status = vduStatus.getState();
358 if (status == null) {
359 return VnfStatus.UNKNOWN;
361 else if (status == VduStateType.NOTFOUND) {
362 return VnfStatus.NOTFOUND;
364 else if (status == VduStateType.INSTANTIATED) {
365 return VnfStatus.ACTIVE;
367 else if (status == VduStateType.FAILED) {
368 return VnfStatus.FAILED;
371 return VnfStatus.UNKNOWN;
375 * Normalize an input value to an Object, based on the target parameter type.
376 * If the type is not recognized, it will just be returned unchanged (as a string).
378 private Object convertInputValue (String inputValue, HeatTemplateParam templateParam)
380 String type = templateParam.getParamType();
381 LOGGER.debug("Parameter: " + templateParam.getParamName() + " is of type " + type);
383 if (type.equalsIgnoreCase("number")) {
385 return Integer.valueOf(inputValue);
387 catch (Exception e) {
388 LOGGER.debug("Unable to convert " + inputValue + " to an integer!" , e);
391 } else if (type.equalsIgnoreCase("json")) {
393 JsonNode jsonNode = new ObjectMapper().readTree(inputValue);
396 catch (Exception e) {
397 LOGGER.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
400 } else if (type.equalsIgnoreCase("boolean")) {
401 return new Boolean(inputValue);
404 // Nothing else matched. Return the original string
408 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
409 Map <String, String> stringOutputs = new HashMap <String, String> ();
410 for (String key : stackOutputs.keySet ()) {
411 if (stackOutputs.get (key) instanceof String) {
412 stringOutputs.put (key, (String) stackOutputs.get (key));
413 } else if (stackOutputs.get(key) instanceof Integer) {
415 String str = "" + stackOutputs.get(key);
416 stringOutputs.put(key, str);
417 } catch (Exception e) {
418 LOGGER.debug("Unable to add " + key + " to outputs", e);
420 } else if (stackOutputs.get(key) instanceof JsonNode) {
422 String str = this.convertNode((JsonNode) stackOutputs.get(key));
423 stringOutputs.put(key, str);
424 } catch (Exception e) {
425 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode", e);
427 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
429 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
430 stringOutputs.put(key, str);
431 } catch (Exception e) {
432 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap", e);
436 String str = stackOutputs.get(key).toString();
437 stringOutputs.put(key, str);
438 } catch (Exception e) {
439 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(), e);
443 return stringOutputs;
447 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
449 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
450 if (inputs == null) {
453 else if (inputs.size() < 1) {
454 sb.append("\tEMPTY");
456 for (String str : inputs.keySet()) {
459 outputString = inputs.get(str).toString();
460 } catch (Exception e) {
461 outputString = "Unable to call toString() on the value for " + str;
463 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
466 LOGGER.debug(sb.toString());
470 private void sendMapToDebug(Map<String, String> inputs) {
472 StringBuilder sb = new StringBuilder("inputs:");
473 if (inputs == null) {
476 else if (inputs.size() < 1) {
477 sb.append("\tEMPTY");
479 for (String str : inputs.keySet()) {
480 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
483 LOGGER.debug(sb.toString());
487 private String convertNode(final JsonNode node) {
489 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
490 final String json = JSON_MAPPER.writeValueAsString(obj);
492 } catch (JsonParseException jpe) {
493 LOGGER.debug("Error converting json to string " + jpe.getMessage());
494 } catch (Exception e) {
495 LOGGER.debug("Error converting json to string " + e.getMessage());
497 return "[Error converting json to string]";
500 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
501 if (objectMap == null) {
504 Map<String, String> stringMap = new HashMap<String, String>();
505 for (String key : objectMap.keySet()) {
506 if (!stringMap.containsKey(key)) {
507 Object obj = objectMap.get(key);
508 if (obj instanceof String) {
509 stringMap.put(key, (String) objectMap.get(key));
510 } else if (obj instanceof JsonNode ){
511 // This is a bit of mess - but I think it's the least impacting
512 // let's convert it BACK to a string - then it will get converted back later
514 String str = this.convertNode((JsonNode) obj);
515 stringMap.put(key, str);
516 } catch (Exception e) {
517 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key, e);
518 //okay in this instance - only string values (fqdn) are expected to be needed
520 } else if (obj instanceof java.util.LinkedHashMap) {
521 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
523 String str = JSON_MAPPER.writeValueAsString(obj);
524 stringMap.put(key, str);
525 } catch (Exception e) {
526 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key, e);
528 } else if (obj instanceof Integer) {
530 String str = "" + obj;
531 stringMap.put(key, str);
532 } catch (Exception e) {
533 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key, e);
537 String str = obj.toString();
538 stringMap.put(key, str);
539 } catch (Exception e) {
540 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")", e);
550 * This is the "Create VF Module" web service implementation.
551 * It will instantiate a new VF Module of the requested type in the specified cloud
552 * and tenant. The tenant must exist before this service is called.
554 * If a VF Module with the same name already exists, this can be considered a
555 * success or failure, depending on the value of the 'failIfExists' parameter.
557 * All VF Modules are defined in the MSO catalog. The caller must request one of
558 * the pre-defined module types or an error will be returned. Within the catalog,
559 * each VF Module references (among other things) a collection of artifacts that
560 * are used to deploy the required cloud resources (VMs, networks, etc.).
562 * Depending on the module templates, a variable set of input parameters will
563 * be defined, some of which are required. The caller is responsible to
564 * pass the necessary input data for the module or an error will be thrown.
566 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
567 * object. This last object can be passed as-is to the rollbackVnf operation to
568 * undo everything that was created for the Module. This is useful if a VF module
569 * is successfully created but the orchestration fails on a subsequent step.
571 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
572 * @param tenantId Openstack tenant identifier
573 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
574 * Deprecated - should use modelCustomizationUuid
575 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
576 * Deprecated - VF Module versions also captured by modelCustomizationUuid
577 * @param vfModuleName Name to be assigned to the new VF Module
578 * @param requestType Indicates if this is a Volume Group or Module request
579 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
580 * to attach to a VF Module
581 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
582 * this is an Add-on module
583 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
584 * the use of vfModuleType.
585 * @param inputs Map of key=value inputs for VNF stack creation
586 * @param failIfExists Flag whether already existing VNF should be considered
587 * @param backout Flag whether to suppress automatic backout (for testing)
588 * @param msoRequest Request tracking information for logs
589 * @param vnfId Holder for output VF Module instance ID in the cloud
590 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
591 * @param rollback Holder for returning VnfRollback object
594 public void createVfModule(String cloudSiteId,
600 String volumeGroupId,
601 String baseVfModuleId,
602 String modelCustomizationUuid,
603 Map <String, String> inputs,
604 Boolean failIfExists,
606 Boolean enableBridge,
607 MsoRequest msoRequest,
608 Holder <String> vnfId,
609 Holder <Map <String, String>> outputs,
610 Holder <VnfRollback> rollback)
613 // Will capture execution time for metrics
614 long startTime = System.currentTimeMillis ();
616 MsoLogger.setLogContext (msoRequest);
617 MsoLogger.setServiceName ("CreateVfModule");
619 // Require a model customization ID. Every VF Module definition must have one.
620 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
621 LOGGER.debug("Missing required input: modelCustomizationUuid");
622 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
623 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
624 "VF Module ModelCustomizationUuid", "null", "VDU", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid");
625 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
626 throw new VnfException(error, MsoExceptionCategory.USERDATA);
629 // Clean up some inputs to make comparisons easier
630 if (requestType == null)
633 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
634 volumeGroupId = null;
636 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
637 baseVfModuleId = null;
639 if (inputs == null) {
640 // Create an empty set of inputs
641 inputs = new HashMap<>();
642 LOGGER.debug("inputs == null - setting to empty");
644 this.sendMapToDebug(inputs);
647 // Check if this is for a "Volume" module
648 boolean isVolumeRequest = false;
649 if (requestType.startsWith("VOLUME")) {
650 isVolumeRequest = true;
653 LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId);
655 // Build a default rollback object (no actions performed)
656 VnfRollback vfRollback = new VnfRollback();
657 vfRollback.setCloudSiteId(cloudSiteId);
658 vfRollback.setTenantId(tenantId);
659 vfRollback.setMsoRequest(msoRequest);
660 vfRollback.setRequestType(requestType);
661 vfRollback.setIsBase(false); // Until we know better
662 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
663 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
664 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
665 vfRollback.setMode("CFY");
667 rollback.value = vfRollback; // Default rollback - no updates performed
669 // Get the VNF/VF Module definition from the Catalog DB first.
670 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
672 VfModule vfModule = null;
673 VnfResource vnfResource = null;
674 VfModuleCustomization vfModuleCust = null;
677 vfModuleCust = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
679 if (vfModuleCust == null) {
680 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid;
682 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
683 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error);
684 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
685 throw new VnfException(error, MsoExceptionCategory.USERDATA);
687 LOGGER.debug("Found vfModuleCust entry " + vfModuleCust.toString());
690 // Get the vfModule and vnfResource records
691 vfModule = vfModuleCust.getVfModule();
692 vnfResource = vfModuleCust.getVfModule().getVnfResources();
694 catch (Exception e) {
696 LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage());
697 throw new VnfException("Exception during create VF " + e.getMessage());
700 // Perform a version check against cloudSite
701 // Obtain the cloud site information where we will create the VF Module
702 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId);
703 if (!cloudSiteOp.isPresent()) {
704 throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId));
706 CloudSite cloudSite = cloudSiteOp.get();
707 MavenLikeVersioning aicV = new MavenLikeVersioning();
708 aicV.setVersion(cloudSite.getCloudVersion());
710 String vnfMin = vnfResource.getAicVersionMin();
711 String vnfMax = vnfResource.getAicVersionMax();
713 if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) ||
714 (vnfMax != null && aicV.isMoreRecentThan(vnfMax)))
717 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
718 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
720 throw new VnfException(error, MsoExceptionCategory.USERDATA);
725 VduInstance vduInstance = null;
726 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null);
728 // Use the VduPlugin.
729 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
731 // First, look up to see if the VF already exists.
733 long subStartTime1 = System.currentTimeMillis ();
735 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName);
736 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "QueryVDU", vfModuleName);
738 catch (VduException me) {
739 // Failed to query the VDU due to a plugin exception.
740 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
741 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "Exception - queryVdu", me);
742 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu", vfModuleName);
743 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
745 // Convert to a generic VnfException
746 me.addContext ("CreateVFModule");
747 throw new VnfException (me);
750 // More precise handling/messaging if the Module already exists
751 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
752 VduStateType status = vduInstance.getStatus().getState();
753 LOGGER.debug ("Found Existing VDU, status=" + status);
755 if (status == VduStateType.INSTANTIATED) {
756 if (failIfExists != null && failIfExists) {
758 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
759 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists");
760 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
761 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
763 // Found existing deployment and client has not requested "failIfExists".
764 // Populate the outputs from the existing deployment.
766 vnfId.value = vduInstance.getVduInstanceId();
767 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
768 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)");
772 // Check through various detailed error cases
773 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING || status == VduStateType.UPDATING) {
774 // fail - it's in progress - return meaningful error
775 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.";
776 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists");
777 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
778 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
780 else if (status == VduStateType.FAILED) {
781 // fail - it exists and is in a FAILED state
782 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
783 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");
784 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
785 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
787 else if (status == VduStateType.UNKNOWN) {
788 // fail - it exists and is in a UNKNOWN state
789 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
790 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");
791 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
792 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
795 // Unexpected, since all known status values have been tested for
796 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
797 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");
798 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
799 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
804 // Collect outputs from Base Modules and Volume Modules
805 Map<String, Object> baseModuleOutputs = null;
806 Map<String, Object> volumeGroupOutputs = null;
808 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
809 if (volumeGroupId != null) {
810 long subStartTime2 = System.currentTimeMillis ();
811 VduInstance volumeVdu = null;
813 volumeVdu = vduPlugin.queryVdu (cloudInfo, volumeGroupId);
814 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu", volumeGroupId);
816 catch (VduException me) {
817 // Failed to query the Volume Group VDU due to a plugin exception.
818 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
819 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(volume)", me);
820 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(volume)", volumeGroupId);
821 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
823 // Convert to a generic VnfException
824 me.addContext ("CreateVFModule(QueryVolume)");
825 throw new VnfException (me);
828 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
829 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
830 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");
831 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
833 throw new VnfException (error, MsoExceptionCategory.USERDATA);
835 LOGGER.debug("Found nested volume group");
836 volumeGroupOutputs = volumeVdu.getOutputs();
837 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
841 // If this is an Add-On Module, query the Base Module outputs
842 // Note: This will be performed whether or not the current request is for an
843 // Add-On Volume Group or Add-On VF Module
845 if (vfModule.getIsBase()) {
846 LOGGER.debug("This is a BASE Module request");
847 vfRollback.setIsBase(true);
849 LOGGER.debug("This is an Add-On Module request");
851 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
852 // Add-on Volume requests may or may not specify a base.
853 if (!isVolumeRequest && baseVfModuleId == null) {
854 LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided");
857 if (baseVfModuleId != null) {
858 long subStartTime2 = System.currentTimeMillis ();
859 VduInstance baseVdu = null;
861 baseVdu = vduPlugin.queryVdu (cloudInfo, baseVfModuleId);
862 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu(Base)", baseVfModuleId);
864 catch (MsoException me) {
865 // Failed to query the Base VF Module due to a Vdu Plugin exception.
866 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
867 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(Base)", me);
868 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(Base)", baseVfModuleId);
869 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
871 // Convert to a generic VnfException
872 me.addContext ("CreateVFModule(QueryBase)");
873 throw new VnfException (me);
876 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
877 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
878 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module DOES NOT EXIST");
879 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
881 throw new VnfException (error, MsoExceptionCategory.USERDATA);
883 LOGGER.debug("Found base module");
884 baseModuleOutputs = baseVdu.getOutputs();
885 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
891 // NOTE: For this section, heatTemplate is used for all template artifacts.
892 // In final implementation (post-POC), the template object would either be generic or there would
893 // be a separate DB Table/Object for different sub-orchestrators.
895 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
897 HeatTemplate heatTemplate = null;
898 HeatEnvironment heatEnvironment = null;
899 if (isVolumeRequest) {
900 heatTemplate = vfModule.getVolumeHeatTemplate();
901 heatEnvironment = vfModuleCust.getVolumeHeatEnv();
903 heatTemplate = vfModule.getModuleHeatTemplate();
904 heatEnvironment = vfModuleCust.getHeatEnvironment();
907 if (heatTemplate == null) {
908 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType;
909 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "VNF", "", MsoLogger.ErrorCode.DataError, error);
910 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
911 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
912 MsoAlarmLogger.CRITICAL, error);
913 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
915 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
918 if (heatEnvironment == null) {
919 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
920 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
921 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
922 // Alarm on this error, configuration must be fixed
923 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
925 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
927 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
931 // Create the combined set of parameters from the incoming request, base-module outputs,
932 // volume-module outputs. Also, convert all variables to their native object types.
934 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
935 List<String> extraInputs = new ArrayList<String>();
937 Boolean skipInputChecks = false;
939 if (skipInputChecks) {
940 goldenInputs = new HashMap<String,Object>();
941 for (String key : inputs.keySet()) {
942 goldenInputs.put(key, inputs.get(key));
946 // Build maps for the parameters (including aliases) to simplify checks
947 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
949 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
950 LOGGER.debug("paramSet has " + paramSet.size() + " entries");
952 for (HeatTemplateParam htp : paramSet) {
953 params.put(htp.getParamName(), htp);
956 String alias = htp.getParamAlias();
957 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
958 params.put(alias, htp);
962 // First, convert all inputs to their "template" type
963 for (String key : inputs.keySet()) {
964 if (params.containsKey(key)) {
965 Object value = convertInputValue(inputs.get(key), params.get(key));
967 goldenInputs.put(key, value);
970 LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType());
973 extraInputs.add(key);
977 if (!extraInputs.isEmpty()) {
978 LOGGER.debug("Ignoring extra inputs: " + extraInputs);
981 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
982 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
983 for (String key : volumeGroupOutputs.keySet()) {
984 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
985 goldenInputs.put(key, volumeGroupOutputs.get(key));
990 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
991 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
992 for (String key : baseModuleOutputs.keySet()) {
993 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
994 goldenInputs.put(key, baseModuleOutputs.get(key));
999 // TODO: The model should support a mechanism to pre-assign default parameter values
1000 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
1001 // an Environment file. There is not a general mechanism in the model to handle this.
1002 // For the general case, any such parameter/values can be added dynamically to the
1003 // inputs (only if not already specified).
1006 // Check that required parameters have been supplied from any of the sources
1007 String missingParams = null;
1008 boolean checkRequiredParameters = true;
1010 String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
1011 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1012 checkRequiredParameters = false;
1013 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1014 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
1016 } catch (Exception e) {
1017 // No problem - default is true
1018 LOGGER.debug ("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS, e);
1021 // Do the actual parameter checking.
1022 // Include looking at the ENV file as a valid definition of a parameter value.
1023 // TODO: This handling of ENV applies only to Heat. A general mechanism to
1024 // support pre-set parameter/values does not yet exist in the model.
1026 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1027 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
1028 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1029 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1030 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1031 LOGGER.debug ("Required parameter " + parm.getParamName ()
1032 + " appears to be in environment - do not count as missing");
1034 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1035 if (missingParams == null) {
1036 missingParams = parm.getParamName ();
1038 missingParams += "," + parm.getParamName ();
1044 if (missingParams != null) {
1045 if (checkRequiredParameters) {
1046 // Problem - missing one or more required parameters
1047 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1048 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "VDU", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1049 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1050 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1052 LOGGER.debug ("found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - will not block");
1055 LOGGER.debug ("No missing parameters found - ok to proceed");
1058 } // NOTE: END PARAMETER CHECKING
1061 // Here we go... ready to deploy the VF Module.
1062 long instantiateVduStartTime = System.currentTimeMillis ();
1063 if (backout == null) backout = true;
1066 // Construct the VDU Model structure to pass to the targeted VduPlugin
1067 VduModelInfo vduModel = null;
1068 if (! isVolumeRequest) {
1069 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1071 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1074 // Invoke the VduPlugin to instantiate the VF Module
1075 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1077 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "instantiateVdu", vfModuleName);
1079 catch (VduException me) {
1080 // Failed to instantiate the VDU.
1081 me.addContext ("CreateVFModule");
1082 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1083 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "instantiateVdu", vfModuleName);
1084 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "MsoException - instantiateVdu", me);
1085 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1086 // Convert to a generic VnfException
1087 throw new VnfException (me);
1089 catch (NullPointerException npe) {
1090 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1091 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error, "VDU", "instantiateVdu", vfModuleName);
1092 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "NullPointerException - instantiateVdu", npe);
1093 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
1094 LOGGER.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1095 throw new VnfException ("NullPointerException during instantiateVdu");
1097 catch (Exception e) {
1098 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + e;
1099 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error, "VDU", "instantiateVdu", vfModuleName);
1100 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error);
1101 LOGGER.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1102 throw new VnfException("Exception during instantiateVdu: " + e.getMessage());
1106 // Reach this point if create is successful.
1107 // Populate remaining rollback info and response parameters.
1108 vfRollback.setVnfCreated (true);
1109 vfRollback.setVnfId (vduInstance.getVduInstanceId());
1110 vnfId.value = vduInstance.getVduInstanceId();
1111 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
1113 rollback.value = vfRollback;
1115 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1116 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1121 public void deleteVfModule (String cloudSiteId,
1124 MsoRequest msoRequest,
1125 Holder <Map <String, String>> outputs) throws VnfException
1127 MsoLogger.setLogContext (msoRequest);
1128 MsoLogger.setServiceName ("DeleteVfModule");
1130 LOGGER.debug ("Deleting VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
1131 // Will capture execution time for metrics
1132 long startTime = System.currentTimeMillis ();
1134 // Capture the output parameters on a delete, so need to query first
1135 VduInstance vduInstance = null;
1136 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null);
1138 // Use the VduPlugin.
1139 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
1142 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleId);
1143 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vfModuleId);
1145 catch (VduException e) {
1146 // Failed to query the VDU due to a plugin exception.
1147 // Convert to a generic VnfException
1148 e.addContext ("QueryVFModule");
1149 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + e;
1150 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vfModuleId);
1151 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "QueryVFModule", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e);
1152 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1153 throw new VnfException (e);
1156 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1157 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1159 // Use the VduPlugin to delete the VDU.
1160 // The possible outcomes of deleteVdu are
1161 // - a vnfInstance object with status of DELETED (success)
1162 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1163 // - a vnfInstance object with status of FAILED (error)
1164 // Also, VduException could be thrown.
1165 long subStartTime = System.currentTimeMillis ();
1167 // TODO: Get an appropriate timeout value - require access to the model
1168 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1169 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from deleteVdu", "VDU", "DeleteVdu", vfModuleId);
1170 } catch (VduException me) {
1171 me.addContext ("DeleteVfModule");
1172 // Convert to a generic VnfException
1173 String error = "Delete VF: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1174 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteVdu", "DeleteVdu", vfModuleId);
1175 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu: " + me.getMessage());
1176 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1177 throw new VnfException (me);
1180 // On success, nothing is returned.
1181 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1185 // Update VF Module not yet implemented for generic VDU plug-in model.
1187 public void updateVfModule (String cloudSiteId,
1193 String volumeGroupHeatStackId,
1194 String baseVfHeatStackId,
1195 String vfModuleStackId,
1196 String modelCustomizationUuid,
1197 Map <String, String> inputs,
1198 MsoRequest msoRequest,
1199 Holder <Map <String, String>> outputs,
1200 Holder <VnfRollback> rollback) throws VnfException
1202 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1203 LOGGER.debug ("Update VF Module command attempted but not supported");
1204 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1208 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator"
1209 * defined for the target cloud. Should really be looking at the VNF Model (ochestration_mode)
1210 * but we don't currently have access to that in Query and Delete cases.
1212 private VduPlugin getVduPlugin (String cloudSiteId) {
1213 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
1214 if (cloudSiteOp.isPresent()) {
1215 CloudSite cloudSite = cloudSiteOp.get();
1216 String orchestrator = cloudSite.getOrchestrator();
1218 if (orchestrator.equalsIgnoreCase("CLOUDIFY")) {
1219 return cloudifyUtils;
1221 else if (orchestrator.equalsIgnoreCase("HEAT")) {
1226 // Default - return HEAT plugin, though will fail later