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.openecomp.mso.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.openecomp.mso.adapters.vdu.CloudInfo;
52 import org.openecomp.mso.adapters.vdu.VduException;
53 import org.openecomp.mso.adapters.vdu.VduInstance;
54 import org.openecomp.mso.adapters.vdu.VduModelInfo;
55 import org.openecomp.mso.adapters.vdu.VduPlugin;
56 import org.openecomp.mso.adapters.vdu.VduStateType;
57 import org.openecomp.mso.adapters.vdu.VduStatus;
58 import org.openecomp.mso.adapters.vdu.mapper.VfModuleCustomizationToVduMapper;
59 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
60 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
61 import org.openecomp.mso.cloud.CloudConfigFactory;
62 import org.openecomp.mso.cloud.CloudSite;
63 import org.openecomp.mso.cloudify.utils.MsoCloudifyUtils;
64 import org.openecomp.mso.aria.AriaVduPlugin;
65 import org.openecomp.mso.db.catalog.CatalogDatabase;
66 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
67 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
68 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
69 import org.openecomp.mso.db.catalog.beans.VfModule;
70 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
71 import org.openecomp.mso.db.catalog.beans.VnfResource;
72 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
73 import org.openecomp.mso.entity.MsoRequest;
74 import org.openecomp.mso.logger.MessageEnum;
75 import org.openecomp.mso.logger.MsoAlarmLogger;
76 import org.openecomp.mso.logger.MsoLogger;
77 import org.openecomp.mso.openstack.beans.VnfRollback;
78 import org.openecomp.mso.openstack.beans.VnfStatus;
79 import org.openecomp.mso.openstack.exceptions.MsoCloudSiteNotFound;
80 import org.openecomp.mso.openstack.exceptions.MsoException;
81 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
82 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
83 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
84 import org.openecomp.mso.properties.MsoPropertiesFactory;
86 import com.fasterxml.jackson.core.JsonParseException;
87 import com.fasterxml.jackson.databind.JsonNode;
88 import com.fasterxml.jackson.databind.ObjectMapper;
90 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
91 public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter {
93 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
94 protected MsoHeatUtils heatUtils;
95 protected VfModuleCustomizationToVduMapper vduMapper;
96 protected MsoCloudifyUtils cloudifyUtils;
97 protected AriaVduPlugin ariaVduPlugin;
99 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
101 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
102 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
103 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
104 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
105 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
106 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
109 * Health Check web method. Does nothing but return to show the adapter is deployed.
112 public void healthCheck () {
113 LOGGER.debug ("Health check call in VNF Plugin Adapter");
117 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
118 * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
120 public MsoVnfPluginAdapterImpl() {
125 * This constructor MUST be used if this class is called with the new operator.
126 * @param msoPropFactory
128 public MsoVnfPluginAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
129 this.msoPropertiesFactory = msoPropFactory;
130 this.cloudConfigFactory = cloudConfigFact;
131 heatUtils = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
132 vduMapper = new VfModuleCustomizationToVduMapper();
133 cloudifyUtils = new MsoCloudifyUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
134 ariaVduPlugin = new AriaVduPlugin("localhost", 5000);
138 * This is the "Create VNF" web service implementation.
139 * This function is now unsupported and will return an error.
143 public void createVnf (String cloudSiteId,
149 String volumeGroupHeatStackId,
150 Map <String, String> inputs,
151 Boolean failIfExists,
153 MsoRequest msoRequest,
154 Holder <String> vnfId,
155 Holder <Map <String, String>> outputs,
156 Holder <VnfRollback> rollback)
159 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
160 LOGGER.debug ("CreateVNF command attempted but not supported");
161 throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
165 * This is the "Update VNF" web service implementation.
166 * This function is now unsupported and will return an error.
170 public void updateVnf (String cloudSiteId,
176 String volumeGroupHeatStackId,
177 Map <String, String> inputs,
178 MsoRequest msoRequest,
179 Holder <Map <String, String>> outputs,
180 Holder <VnfRollback> rollback)
183 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
184 LOGGER.debug ("UpdateVNF command attempted but not supported");
185 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
189 * This is the "Query VNF" web service implementation.
191 * This really should be QueryVfModule, but nobody ever changed it.
193 * The method returns an indicator that the VNF exists, along with its status and outputs.
194 * The input "vnfName" will also be reflected back as its ID.
196 * @param cloudSiteId CLLI code of the cloud site in which to query
197 * @param tenantId Openstack tenant identifier
198 * @param vnfNameOrId VNF Name or ID to query
199 * @param msoRequest Request tracking information for logs
200 * @param vnfExists Flag reporting the result of the query
201 * @param vnfId Holder for output VNF ID
202 * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc)
205 public void queryVnf (String cloudSiteId,
208 MsoRequest msoRequest,
209 Holder <Boolean> vnfExists,
210 Holder <String> vnfId,
211 Holder <VnfStatus> status,
212 Holder <Map <String, String>> outputs)
215 MsoLogger.setLogContext (msoRequest);
216 MsoLogger.setServiceName ("QueryVnf");
217 LOGGER.debug ("Querying VNF " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId);
219 // Will capture execution time for metrics
220 long startTime = System.currentTimeMillis ();
221 long subStartTime = System.currentTimeMillis ();
223 VduInstance vduInstance = null;
224 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null);
226 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
229 vduInstance = vduPlugin.queryVdu(cloudInfo, vnfNameOrId);
230 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vnfNameOrId);
232 catch (VduException e) {
233 // Failed to query the VDU due to a plugin exception.
234 e.addContext ("QueryVNF");
235 String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId + ": " + e;
236 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vnfNameOrId);
237 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfNameOrId, cloudSiteId, tenantId, "VDU", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e);
238 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
239 throw new VnfException (e);
242 if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) {
243 vnfExists.value = Boolean.TRUE;
244 status.value = vduStatusToVnfStatus(vduInstance);
245 vnfId.value = vduInstance.getVduInstanceId();
246 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
248 LOGGER.debug ("VNF " + vnfNameOrId + " found, ID = " + vnfId.value);
251 vnfExists.value = Boolean.FALSE;
252 status.value = VnfStatus.NOTFOUND;
254 outputs.value = new HashMap <String, String> (); // Return as an empty map
256 LOGGER.debug ("VNF " + vnfNameOrId + " not found");
258 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
264 * This is the "Delete VNF" web service implementation.
265 * This function is now unsupported and will return an error.
269 public void deleteVnf (String cloudSiteId,
272 MsoRequest msoRequest) throws VnfException {
273 MsoLogger.setLogContext (msoRequest);
274 MsoLogger.setServiceName ("DeleteVnf");
276 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
277 LOGGER.debug ("DeleteVNF command attempted but not supported");
278 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
282 * This web service endpoint will rollback a previous Create VNF operation.
283 * A rollback object is returned to the client in a successful creation
284 * response. The client can pass that object as-is back to the rollbackVnf
285 * operation to undo the creation.
287 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
288 * but APIs were apparently never updated.
291 public void rollbackVnf (VnfRollback rollback) throws VnfException {
292 long startTime = System.currentTimeMillis ();
293 MsoLogger.setServiceName ("RollbackVnf");
294 // rollback may be null (e.g. if stack already existed when Create was called)
295 if (rollback == null) {
296 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
297 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
301 // Don't rollback if nothing was done originally
302 if (!rollback.getVnfCreated()) {
303 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back");
307 // Get the elements of the VnfRollback object for easier access
308 String cloudSiteId = rollback.getCloudSiteId ();
309 String tenantId = rollback.getTenantId ();
310 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null);
312 String vfModuleId = rollback.getVfModuleStackId ();
314 MsoLogger.setLogContext (rollback.getMsoRequest());
316 LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
318 VduInstance vduInstance = null;
320 // Use the VduPlugin to delete the VF Module.
321 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
323 long subStartTime = System.currentTimeMillis ();
325 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
326 vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
328 LOGGER.debug("Rolled back VDU instantiation: " + vduInstance.getVduInstanceId());
329 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VDU Plugin", "VDU", "DeleteVdu", null);
331 catch (VduException ve) {
332 // Failed to rollback the VF Module due to a plugin exception.
333 // Convert to a generic VnfException
334 ve.addContext ("RollbackVFModule");
335 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + ve;
336 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "DeleteVdu", null);
337 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu", ve);
338 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
339 throw new VnfException (ve);
341 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module");
346 private VnfStatus vduStatusToVnfStatus (VduInstance vdu) {
347 // Determine the status based on last action & status
348 // DeploymentInfo object should be enhanced to report a better status internally.
349 VduStatus vduStatus = vdu.getStatus();
350 VduStateType status = vduStatus.getState();
352 if (status == null) {
353 return VnfStatus.UNKNOWN;
355 else if (status == VduStateType.NOTFOUND) {
356 return VnfStatus.NOTFOUND;
358 else if (status == VduStateType.INSTANTIATED) {
359 return VnfStatus.ACTIVE;
361 else if (status == VduStateType.FAILED) {
362 return VnfStatus.FAILED;
365 return VnfStatus.UNKNOWN;
369 * Normalize an input value to an Object, based on the target parameter type.
370 * If the type is not recognized, it will just be returned unchanged (as a string).
372 private Object convertInputValue (String inputValue, HeatTemplateParam templateParam)
374 String type = templateParam.getParamType();
375 LOGGER.debug("Parameter: " + templateParam.getParamName() + " is of type " + type);
377 if (type.equalsIgnoreCase("number")) {
379 return Integer.valueOf(inputValue);
381 catch (Exception e) {
382 LOGGER.debug("Unable to convert " + inputValue + " to an integer!" , e);
385 } else if (type.equalsIgnoreCase("json")) {
387 JsonNode jsonNode = new ObjectMapper().readTree(inputValue);
390 catch (Exception e) {
391 LOGGER.debug("Unable to convert " + inputValue + " to a JsonNode!", e);
394 } else if (type.equalsIgnoreCase("boolean")) {
395 return new Boolean(inputValue);
398 // Nothing else matched. Return the original string
402 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
403 Map <String, String> stringOutputs = new HashMap <> ();
404 for (String key : stackOutputs.keySet ()) {
405 if (stackOutputs.get (key) instanceof String) {
406 stringOutputs.put (key, (String) stackOutputs.get (key));
407 } else if (stackOutputs.get(key) instanceof Integer) {
409 String str = "" + stackOutputs.get(key);
410 stringOutputs.put(key, str);
411 } catch (Exception e) {
412 LOGGER.debug("Unable to add " + key + " to outputs", e);
414 } else if (stackOutputs.get(key) instanceof JsonNode) {
416 String str = this.convertNode((JsonNode) stackOutputs.get(key));
417 stringOutputs.put(key, str);
418 } catch (Exception e) {
419 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode", e);
421 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
423 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
424 stringOutputs.put(key, str);
425 } catch (Exception e) {
426 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap", e);
430 String str = stackOutputs.get(key).toString();
431 stringOutputs.put(key, str);
432 } catch (Exception e) {
433 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(), e);
437 return stringOutputs;
441 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
443 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
444 if (inputs == null) {
447 else if (inputs.size() < 1) {
448 sb.append("\tEMPTY");
450 for (String str : inputs.keySet()) {
453 outputString = inputs.get(str).toString();
454 } catch (Exception e) {
455 outputString = "Unable to call toString() on the value for " + str;
457 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
460 LOGGER.debug(sb.toString());
464 private void sendMapToDebug(Map<String, String> inputs) {
466 StringBuilder sb = new StringBuilder("inputs:");
467 if (inputs == null) {
470 else if (inputs.size() < 1) {
471 sb.append("\tEMPTY");
473 for (String str : inputs.keySet()) {
474 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
477 LOGGER.debug(sb.toString());
481 private String convertNode(final JsonNode node) {
483 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
484 final String json = JSON_MAPPER.writeValueAsString(obj);
486 } catch (JsonParseException jpe) {
487 LOGGER.debug("Error converting json to string " + jpe.getMessage());
488 } catch (Exception e) {
489 LOGGER.debug("Error converting json to string " + e.getMessage());
491 return "[Error converting json to string]";
494 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
495 if (objectMap == null) {
498 Map<String, String> stringMap = new HashMap<>();
499 for (String key : objectMap.keySet()) {
500 if (!stringMap.containsKey(key)) {
501 Object obj = objectMap.get(key);
502 if (obj instanceof String) {
503 stringMap.put(key, (String) objectMap.get(key));
504 } else if (obj instanceof JsonNode ){
505 // This is a bit of mess - but I think it's the least impacting
506 // let's convert it BACK to a string - then it will get converted back later
508 String str = this.convertNode((JsonNode) obj);
509 stringMap.put(key, str);
510 } catch (Exception e) {
511 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key, e);
512 //okay in this instance - only string values (fqdn) are expected to be needed
514 } else if (obj instanceof java.util.LinkedHashMap) {
515 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
517 String str = JSON_MAPPER.writeValueAsString(obj);
518 stringMap.put(key, str);
519 } catch (Exception e) {
520 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key, e);
522 } else if (obj instanceof Integer) {
524 String str = "" + obj;
525 stringMap.put(key, str);
526 } catch (Exception e) {
527 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key, e);
531 String str = obj.toString();
532 stringMap.put(key, str);
533 } catch (Exception e) {
534 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")", e);
544 * This is the "Create VF Module" web service implementation.
545 * It will instantiate a new VF Module of the requested type in the specified cloud
546 * and tenant. The tenant must exist before this service is called.
548 * If a VF Module with the same name already exists, this can be considered a
549 * success or failure, depending on the value of the 'failIfExists' parameter.
551 * All VF Modules are defined in the MSO catalog. The caller must request one of
552 * the pre-defined module types or an error will be returned. Within the catalog,
553 * each VF Module references (among other things) a collection of artifacts that
554 * are used to deploy the required cloud resources (VMs, networks, etc.).
556 * Depending on the module templates, a variable set of input parameters will
557 * be defined, some of which are required. The caller is responsible to
558 * pass the necessary input data for the module or an error will be thrown.
560 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
561 * object. This last object can be passed as-is to the rollbackVnf operation to
562 * undo everything that was created for the Module. This is useful if a VF module
563 * is successfully created but the orchestration fails on a subsequent step.
565 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
566 * @param tenantId Openstack tenant identifier
567 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
568 * Deprecated - should use modelCustomizationUuid
569 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
570 * Deprecated - VF Module versions also captured by modelCustomizationUuid
571 * @param vfModuleName Name to be assigned to the new VF Module
572 * @param requestType Indicates if this is a Volume Group or Module request
573 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
574 * to attach to a VF Module
575 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
576 * this is an Add-on module
577 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
578 * the use of vfModuleType.
579 * @param inputs Map of key=value inputs for VNF stack creation
580 * @param failIfExists Flag whether already existing VNF should be considered
581 * @param backout Flag whether to suppress automatic backout (for testing)
582 * @param msoRequest Request tracking information for logs
583 * @param vnfId Holder for output VF Module instance ID in the cloud
584 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
585 * @param rollback Holder for returning VnfRollback object
587 public void createVfModule(String cloudSiteId,
593 String volumeGroupId,
594 String baseVfModuleId,
595 String modelCustomizationUuid,
596 Map <String, String> inputs,
597 Boolean failIfExists,
599 MsoRequest msoRequest,
600 Holder <String> vnfId,
601 Holder <Map <String, String>> outputs,
602 Holder <VnfRollback> rollback)
605 // Will capture execution time for metrics
606 long startTime = System.currentTimeMillis ();
608 MsoLogger.setLogContext (msoRequest);
609 MsoLogger.setServiceName ("CreateVfModule");
611 // Require a model customization ID. Every VF Module definition must have one.
612 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
613 LOGGER.debug("Missing required input: modelCustomizationUuid");
614 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
615 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
616 "VF Module ModelCustomizationUuid", "null", "VDU", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid");
617 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
618 throw new VnfException(error, MsoExceptionCategory.USERDATA);
621 // Clean up some inputs to make comparisons easier
622 if (requestType == null)
625 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
626 volumeGroupId = null;
628 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
629 baseVfModuleId = null;
631 if (inputs == null) {
632 // Create an empty set of inputs
633 inputs = new HashMap<>();
634 LOGGER.debug("inputs == null - setting to empty");
636 this.sendMapToDebug(inputs);
639 // Check if this is for a "Volume" module
640 boolean isVolumeRequest = false;
641 if (requestType.startsWith("VOLUME")) {
642 isVolumeRequest = true;
645 LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId);
647 // Build a default rollback object (no actions performed)
648 VnfRollback vfRollback = new VnfRollback();
649 vfRollback.setCloudSiteId(cloudSiteId);
650 vfRollback.setTenantId(tenantId);
651 vfRollback.setMsoRequest(msoRequest);
652 vfRollback.setRequestType(requestType);
653 vfRollback.setIsBase(false); // Until we know better
654 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
655 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
656 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
657 vfRollback.setMode("CFY");
659 rollback.value = vfRollback; // Default rollback - no updates performed
661 // Get the VNF/VF Module definition from the Catalog DB first.
662 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
664 CatalogDatabase db = CatalogDatabase.getInstance();
665 VfModule vfModule = null;
666 VnfResource vnfResource = null;
667 VfModuleCustomization vfModuleCust = null;
670 vfModuleCust = db.getVfModuleCustomizationByModelCustomizationId(modelCustomizationUuid);
672 if (vfModuleCust == null) {
673 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid;
675 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
676 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error);
677 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
678 throw new VnfException(error, MsoExceptionCategory.USERDATA);
680 LOGGER.debug("Found vfModuleCust entry " + vfModuleCust.toString());
683 // Get the vfModule and vnfResource records
684 vfModule = vfModuleCust.getVfModule();
685 vnfResource = db.getVnfResourceByModelUuid(vfModule.getVnfResourceModelUUId());
687 catch (Exception e) {
689 LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage());
690 throw new VnfException("Exception during create VF " + e.getMessage());
693 // Perform a version check against cloudSite
694 // Obtain the cloud site information where we will create the VF Module
695 Optional<CloudSite> cloudSite = cloudConfigFactory.getCloudConfig().getCloudSite (cloudSiteId);
696 if (!cloudSite.isPresent()) {
697 throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId));
699 MavenLikeVersioning aicV = new MavenLikeVersioning();
700 aicV.setVersion(cloudSite.get().getAic_version());
702 String vnfMin = vnfResource.getAicVersionMin();
703 String vnfMax = vnfResource.getAicVersionMax();
705 if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) ||
706 (vnfMax != null && aicV.isMoreRecentThan(vnfMax)))
709 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSite.get().getId() + " with AIC_Version:" + cloudSite.get().getAic_version();
710 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
712 throw new VnfException(error, MsoExceptionCategory.USERDATA);
717 VduInstance vduInstance = null;
718 CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null);
720 // Use the VduPlugin.
721 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
723 // First, look up to see if the VF already exists.
725 long subStartTime1 = System.currentTimeMillis ();
727 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName);
728 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "QueryVDU", vfModuleName);
730 catch (VduException me) {
731 // Failed to query the VDU due to a plugin exception.
732 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
733 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "Exception - queryVdu", me);
734 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu", vfModuleName);
735 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
737 // Convert to a generic VnfException
738 me.addContext ("CreateVFModule");
739 throw new VnfException (me);
742 // More precise handling/messaging if the Module already exists
743 if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) {
744 VduStateType status = vduInstance.getStatus().getState();
745 LOGGER.debug ("Found Existing VDU, status=" + status);
747 if (status == VduStateType.INSTANTIATED) {
748 if (failIfExists != null && failIfExists) {
750 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
751 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists");
752 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
753 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
755 // Found existing deployment and client has not requested "failIfExists".
756 // Populate the outputs from the existing deployment.
758 vnfId.value = vduInstance.getVduInstanceId();
759 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
760 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)");
764 // Check through various detailed error cases
765 else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING || status == VduStateType.UPDATING) {
766 // fail - it's in progress - return meaningful error
767 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.";
768 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists");
769 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
770 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
772 else if (status == VduStateType.FAILED) {
773 // fail - it exists and is in a FAILED state
774 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
775 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");
776 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
777 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
779 else if (status == VduStateType.UNKNOWN) {
780 // fail - it exists and is in a UNKNOWN state
781 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
782 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");
783 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
784 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
787 // Unexpected, since all known status values have been tested for
788 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
789 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");
790 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
791 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId());
796 // Collect outputs from Base Modules and Volume Modules
797 Map<String, Object> baseModuleOutputs = null;
798 Map<String, Object> volumeGroupOutputs = null;
800 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
801 if (volumeGroupId != null) {
802 long subStartTime2 = System.currentTimeMillis ();
803 VduInstance volumeVdu = null;
805 volumeVdu = vduPlugin.queryVdu (cloudInfo, volumeGroupId);
806 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu", volumeGroupId);
808 catch (VduException me) {
809 // Failed to query the Volume Group VDU due to a plugin exception.
810 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
811 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(volume)", me);
812 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(volume)", volumeGroupId);
813 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
815 // Convert to a generic VnfException
816 me.addContext ("CreateVFModule(QueryVolume)");
817 throw new VnfException (me);
820 if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) {
821 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
822 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");
823 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
825 throw new VnfException (error, MsoExceptionCategory.USERDATA);
827 LOGGER.debug("Found nested volume group");
828 volumeGroupOutputs = volumeVdu.getOutputs();
829 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
833 // If this is an Add-On Module, query the Base Module outputs
834 // Note: This will be performed whether or not the current request is for an
835 // Add-On Volume Group or Add-On VF Module
837 if (vfModule.isBase()) {
838 LOGGER.debug("This is a BASE Module request");
839 vfRollback.setIsBase(true);
841 LOGGER.debug("This is an Add-On Module request");
843 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
844 // Add-on Volume requests may or may not specify a base.
845 if (!isVolumeRequest && baseVfModuleId == null) {
846 LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided");
849 if (baseVfModuleId != null) {
850 long subStartTime2 = System.currentTimeMillis ();
851 VduInstance baseVdu = null;
853 baseVdu = vduPlugin.queryVdu (cloudInfo, baseVfModuleId);
854 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu(Base)", baseVfModuleId);
856 catch (MsoException me) {
857 // Failed to query the Base VF Module due to a Vdu Plugin exception.
858 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
859 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(Base)", me);
860 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(Base)", baseVfModuleId);
861 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
863 // Convert to a generic VnfException
864 me.addContext ("CreateVFModule(QueryBase)");
865 throw new VnfException (me);
868 if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) {
869 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
870 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module DOES NOT EXIST");
871 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
873 throw new VnfException (error, MsoExceptionCategory.USERDATA);
875 LOGGER.debug("Found base module");
876 baseModuleOutputs = baseVdu.getOutputs();
877 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
882 // NOTE: For this section, heatTemplate is used for all template artifacts.
883 // In final implementation (post-POC), the template object would either be generic or there would
884 // be a separate DB Table/Object for different sub-orchestrators.
886 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
888 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
889 String heatTemplateArtifactUuid = null;
890 String heatEnvironmentArtifactUuid = null;
892 if (isVolumeRequest) {
893 heatTemplateArtifactUuid = vfModule.getVolHeatTemplateArtifactUUId();
894 heatEnvironmentArtifactUuid = vfModuleCust.getVolEnvironmentArtifactUuid();
896 heatTemplateArtifactUuid = vfModule.getHeatTemplateArtifactUUId();
897 heatEnvironmentArtifactUuid = vfModuleCust.getHeatEnvironmentArtifactUuid();
900 if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) {
901 String error = "Create: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType;
902 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "Cloudify", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
903 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
904 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
905 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
908 HeatTemplate heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
910 if (heatTemplate == null) {
911 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
912 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
914 String.valueOf(heatTemplateArtifactUuid), "Cloudify", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
915 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
916 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
917 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
919 LOGGER.debug("Got HEAT Template record from DB");
921 // Next get the Environment record. This is optional.
922 HeatEnvironment heatEnvironment = null;
923 if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals(""))
925 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
926 if (heatEnvironment == null) {
927 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
928 + ", Environment ID="
929 + heatEnvironmentArtifactUuid;
930 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "Cloudify", "getEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
931 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
932 // Alarm on this error, configuration must be fixed
933 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
935 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
937 LOGGER.debug ("Got Heat Environment from DB");
939 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
943 // Create the combined set of parameters from the incoming request, base-module outputs,
944 // volume-module outputs. Also, convert all variables to their native object types.
946 HashMap<String, Object> goldenInputs = new HashMap<>();
947 List<String> extraInputs = new ArrayList<>();
949 Boolean skipInputChecks = false;
951 if (skipInputChecks) {
952 goldenInputs = new HashMap<String,Object>();
953 for (String key : inputs.keySet()) {
954 goldenInputs.put(key, inputs.get(key));
958 // Build maps for the parameters (including aliases) to simplify checks
959 HashMap<String, HeatTemplateParam> params = new HashMap<>();
961 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
962 LOGGER.debug("paramSet has " + paramSet.size() + " entries");
964 for (HeatTemplateParam htp : paramSet) {
965 params.put(htp.getParamName(), htp);
968 String alias = htp.getParamAlias();
969 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
970 params.put(alias, htp);
974 // First, convert all inputs to their "template" type
975 for (String key : inputs.keySet()) {
976 if (params.containsKey(key)) {
977 Object value = convertInputValue(inputs.get(key), params.get(key));
979 goldenInputs.put(key, value);
982 LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType());
985 extraInputs.add(key);
989 if (!extraInputs.isEmpty()) {
990 LOGGER.debug("Ignoring extra inputs: " + extraInputs);
993 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
994 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
995 for (String key : volumeGroupOutputs.keySet()) {
996 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
997 goldenInputs.put(key, volumeGroupOutputs.get(key));
1002 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
1003 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
1004 for (String key : baseModuleOutputs.keySet()) {
1005 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
1006 goldenInputs.put(key, baseModuleOutputs.get(key));
1011 // TODO: The model should support a mechanism to pre-assign default parameter values
1012 // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by
1013 // an Environment file. There is not a general mechanism in the model to handle this.
1014 // For the general case, any such parameter/values can be added dynamically to the
1015 // inputs (only if not already specified).
1018 // Check that required parameters have been supplied from any of the sources
1019 String missingParams = null;
1020 boolean checkRequiredParameters = true;
1022 String propertyString = this.msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1023 .getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS,null);
1024 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1025 checkRequiredParameters = false;
1026 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1027 + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS);
1029 } catch (Exception e) {
1030 // No problem - default is true
1031 LOGGER.debug ("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS, e);
1034 // Do the actual parameter checking.
1035 // Include looking at the ENV file as a valid definition of a parameter value.
1036 // TODO: This handling of ENV applies only to Heat. A general mechanism to
1037 // support pre-set parameter/values does not yet exist in the model.
1039 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1040 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
1041 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1042 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1043 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1044 LOGGER.debug ("Required parameter " + parm.getParamName ()
1045 + " appears to be in environment - do not count as missing");
1047 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1048 if (missingParams == null) {
1049 missingParams = parm.getParamName ();
1051 missingParams += "," + parm.getParamName ();
1057 if (missingParams != null) {
1058 if (checkRequiredParameters) {
1059 // Problem - missing one or more required parameters
1060 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1061 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "VDU", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1062 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1063 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1065 LOGGER.debug ("found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - will not block");
1068 LOGGER.debug ("No missing parameters found - ok to proceed");
1071 } // NOTE: END PARAMETER CHECKING
1073 // Here we go... ready to deploy the VF Module.
1074 long instantiateVduStartTime = System.currentTimeMillis ();
1075 if (backout == null) backout = true;
1078 // Construct the VDU Model structure to pass to the targeted VduPlugin
1079 VduModelInfo vduModel = null;
1080 if (! isVolumeRequest) {
1081 vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust);
1083 vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust);
1086 // Invoke the VduPlugin to instantiate the VF Module
1087 vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout);
1089 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "instantiateVdu", vfModuleName);
1091 catch (VduException me) {
1092 // Failed to instantiate the VDU.
1093 me.addContext ("CreateVFModule");
1094 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1095 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "instantiateVdu", vfModuleName);
1096 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "MsoException - instantiateVdu", me);
1097 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1098 // Convert to a generic VnfException
1099 throw new VnfException (me);
1101 catch (NullPointerException npe) {
1102 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1103 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error, "VDU", "instantiateVdu", vfModuleName);
1104 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "NullPointerException - instantiateVdu", npe);
1105 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
1106 LOGGER.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe);
1107 throw new VnfException ("NullPointerException during instantiateVdu");
1109 catch (Exception e) {
1110 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + e;
1111 LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error, "VDU", "instantiateVdu", vfModuleName);
1112 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error);
1113 LOGGER.debug("Unhandled exception at vduPlugin.instantiateVdu", e);
1118 // Reach this point if create is successful.
1119 // Populate remaining rollback info and response parameters.
1120 vfRollback.setVnfCreated (true);
1121 vfRollback.setVnfId (vduInstance.getVduInstanceId());
1122 vnfId.value = vduInstance.getVduInstanceId();
1123 outputs.value = copyStringOutputs (vduInstance.getOutputs ());
1125 rollback.value = vfRollback;
1127 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1128 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1132 public void deleteVfModule (String cloudSiteId,
1135 MsoRequest msoRequest,
1136 Holder <Map <String, String>> outputs) throws VnfException
1138 MsoLogger.setLogContext (msoRequest);
1139 MsoLogger.setServiceName ("DeleteVfModule");
1141 LOGGER.debug ("Deleting VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
1142 // Will capture execution time for metrics
1143 long startTime = System.currentTimeMillis ();
1145 // Capture the output parameters on a delete, so need to query first
1146 VduInstance vduInstance = null;
1147 CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null);
1149 // Use the VduPlugin.
1150 VduPlugin vduPlugin = getVduPlugin(cloudSiteId);
1153 vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleId);
1154 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vfModuleId);
1156 catch (VduException e) {
1157 // Failed to query the VDU due to a plugin exception.
1158 // Convert to a generic VnfException
1159 e.addContext ("QueryVFModule");
1160 String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + e;
1161 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vfModuleId);
1162 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "QueryVFModule", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e);
1163 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1164 throw new VnfException (e);
1167 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1168 outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs());
1170 // Use the VduPlugin to delete the VDU.
1171 // The possible outcomes of deleteVdu are
1172 // - a vnfInstance object with status of DELETED (success)
1173 // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success)
1174 // - a vnfInstance object with status of FAILED (error)
1175 // Also, VduException could be thrown.
1176 long subStartTime = System.currentTimeMillis ();
1178 // TODO: Get an appropriate timeout value - require access to the model
1179 vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5);
1180 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from deleteVdu", "VDU", "DeleteVdu", vfModuleId);
1181 } catch (VduException me) {
1182 me.addContext ("DeleteVfModule");
1183 // Convert to a generic VnfException
1184 String error = "Delete VF: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1185 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteVdu", "DeleteVdu", vfModuleId);
1186 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu: " + me.getMessage());
1187 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1188 throw new VnfException (me);
1191 // On success, nothing is returned.
1192 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1196 // Update VF Module not yet implemented for generic VDU plug-in model.
1198 public void updateVfModule (String cloudSiteId,
1204 String volumeGroupHeatStackId,
1205 String baseVfHeatStackId,
1206 String vfModuleStackId,
1207 String modelCustomizationUuid,
1208 Map <String, String> inputs,
1209 MsoRequest msoRequest,
1210 Holder <Map <String, String>> outputs,
1211 Holder <VnfRollback> rollback) throws VnfException
1213 // This operation is not currently supported for VduPlugin-orchestrated VF Modules.
1214 LOGGER.debug ("Update VF Module command attempted but not supported");
1215 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);
1219 * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator"
1220 * defined for the target cloud. Should really be looking at the VNF Model (ochestration_mode)
1221 * but we don't currently have access to that in Query and Delete cases.
1223 private VduPlugin getVduPlugin (String cloudSiteId) {
1224 Optional<CloudSite> cloudSite = cloudConfigFactory.getCloudConfig().getCloudSite(cloudSiteId);
1225 if (cloudSite.isPresent()) {
1226 String orchestrator = cloudSite.get().getOrchestrator();
1228 if (orchestrator.equalsIgnoreCase("CLOUDIFY")) {
1229 return cloudifyUtils;
1231 else if (orchestrator.equalsIgnoreCase("ARIA")) {
1232 return ariaVduPlugin;
1234 else if (orchestrator.equalsIgnoreCase("HEAT")) {
1239 // Default - return HEAT plugin, though will fail later