2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (C) 2018 IBM.
8 * Modifications Copyright (c) 2019 Samsung
9 * ================================================================================
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 * ============LICENSE_END=========================================================
24 package org.onap.so.adapters.vnf;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.List;
31 import java.util.Optional;
34 import javax.jws.WebService;
35 import javax.xml.ws.Holder;
37 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
38 import org.onap.so.adapters.vnf.exceptions.VnfException;
39 import org.onap.so.cloud.CloudConfig;
40 import org.onap.so.db.catalog.beans.CloudSite;
41 import org.onap.so.cloudify.beans.DeploymentInfo;
42 import org.onap.so.cloudify.beans.DeploymentStatus;
43 import org.onap.so.cloudify.exceptions.MsoCloudifyManagerNotFound;
44 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
45 import org.onap.so.db.catalog.beans.HeatEnvironment;
46 import org.onap.so.db.catalog.beans.HeatFiles;
47 import org.onap.so.db.catalog.beans.HeatTemplate;
48 import org.onap.so.db.catalog.beans.HeatTemplateParam;
49 import org.onap.so.db.catalog.beans.VfModule;
50 import org.onap.so.db.catalog.beans.VfModuleCustomization;
51 import org.onap.so.db.catalog.beans.VnfResource;
52 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
53 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
54 import org.onap.so.entity.MsoRequest;
55 import org.onap.so.logger.MessageEnum;
57 import org.onap.so.logger.MsoLogger;
58 import org.onap.so.openstack.beans.MsoTenant;
59 import org.onap.so.openstack.beans.VnfRollback;
60 import org.onap.so.openstack.beans.VnfStatus;
61 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
62 import org.onap.so.openstack.exceptions.MsoException;
63 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
64 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
65 import org.onap.so.openstack.utils.MsoHeatEnvironmentParameter;
66 import org.onap.so.openstack.utils.MsoKeystoneUtils;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69 import org.springframework.beans.factory.annotation.Autowired;
70 import org.springframework.core.env.Environment;
71 import org.springframework.stereotype.Component;
73 import com.fasterxml.jackson.core.JsonParseException;
74 import com.fasterxml.jackson.databind.JsonNode;
75 import com.fasterxml.jackson.databind.ObjectMapper;
76 import org.springframework.transaction.annotation.Transactional;
80 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf")
81 public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter {
83 private static Logger logger = LoggerFactory.getLogger(MsoVnfCloudifyAdapterImpl.class);
85 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
86 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
87 private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN.";
88 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
89 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq";
90 private static final String CLOUDIFY_RESPONSE_SUCCESS="Successfully received response from Cloudify";
91 private static final String CLOUDIFY="Cloudify";
93 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
96 protected CloudConfig cloudConfig;
99 private VFModuleCustomizationRepository vfModuleCustomRepo;
102 private Environment environment;
105 protected MsoKeystoneUtils keystoneUtils;
108 protected MsoCloudifyUtils cloudifyUtils;
110 * Health Check web method. Does nothing but return to show the adapter is deployed.
113 public void healthCheck () {
114 logger.debug("Health check call in VNF Cloudify Adapter");
118 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
119 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
121 public MsoVnfCloudifyAdapterImpl() {
126 * This is the "Create VNF" web service implementation.
127 * This function is now unsupported and will return an error.
131 public void createVnf (String cloudSiteId,
137 String volumeGroupHeatStackId,
138 Map <String, Object> inputs,
139 Boolean failIfExists,
141 Boolean enableBridge,
142 MsoRequest msoRequest,
143 Holder <String> vnfId,
144 Holder <Map <String, String>> outputs,
145 Holder <VnfRollback> rollback)
148 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
149 logger.debug("CreateVNF command attempted but not supported");
150 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
154 * This is the "Update VNF" web service implementation.
155 * This function is now unsupported and will return an error.
159 public void updateVnf (String cloudSiteId,
165 String volumeGroupHeatStackId,
166 Map <String, Object> inputs,
167 MsoRequest msoRequest,
168 Holder <Map <String, String>> outputs,
169 Holder <VnfRollback> rollback)
172 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
173 logger.debug("UpdateVNF command attempted but not supported");
174 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
178 * This is the "Query VNF" web service implementation.
180 * This really should be QueryVfModule, but nobody ever changed it.
182 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same
183 * as deployment name, since it assigned by the client when a deployment is created.
184 * Also, the input cloudSiteId is used only to identify which Cloudify instance to query,
185 * and the tenantId is ignored (since that really only applies for Openstack/Heat).
187 * The method returns an indicator that the VNF exists, along with its status and outputs.
188 * The input "vnfName" will also be reflected back as its ID.
190 * @param cloudSiteId CLLI code of the cloud site in which to query
191 * @param tenantId Openstack tenant identifier - ignored for Cloudify
192 * @param vnfName VNF Name (should match a deployment ID)
193 * @param msoRequest Request tracking information for logs
194 * @param vnfExists Flag reporting the result of the query
195 * @param vnfId Holder for output VNF ID
196 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
199 public void queryVnf (String cloudSiteId,
202 MsoRequest msoRequest,
203 Holder <Boolean> vnfExists,
204 Holder <String> vnfId,
205 Holder <VnfStatus> status,
206 Holder <Map <String, String>> outputs)
209 MsoLogger.setLogContext (msoRequest);
210 logger.debug ("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
212 // Will capture execution time for metrics
213 long startTime = System.currentTimeMillis ();
214 long subStartTime = System.currentTimeMillis ();
216 DeploymentInfo deployment = null;
219 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
221 catch (MsoCloudifyManagerNotFound e) {
222 // This site does not have a Cloudify Manager.
223 // This isn't an error, just means we won't find the VNF here.
226 catch (MsoException me) {
227 // Failed to query the Deployment due to a cloudify exception.
228 // Convert to a generic VnfException
229 me.addContext("QueryVNF");
230 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
232 .error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudSiteId, tenantId,
233 CLOUDIFY, "QueryVNF", MsoLogger.ErrorCode.DataError.getValue(), "Exception - queryDeployment", me);
235 throw new VnfException(me);
238 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
239 vnfExists.value = Boolean.TRUE;
240 status.value = deploymentStatusToVnfStatus(deployment);
241 vnfId.value = deployment.getId();
242 outputs.value = copyStringOutputs(deployment.getOutputs());
244 logger.debug("VNF {} found in Cloudify, ID = {}", vnfName, vnfId.value);
246 vnfExists.value = Boolean.FALSE;
247 status.value = VnfStatus.NOTFOUND;
249 outputs.value = new HashMap<String, String>(); // Return as an empty map
251 logger.debug("VNF {} not found", vnfName);
258 * This is the "Delete VNF" web service implementation.
259 * This function is now unsupported and will return an error.
263 public void deleteVnf (String cloudSiteId,
266 MsoRequest msoRequest) throws VnfException {
267 MsoLogger.setLogContext (msoRequest);
269 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
270 logger.debug("DeleteVNF command attempted but not supported");
271 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
275 * This web service endpoint will rollback a previous Create VNF operation.
276 * A rollback object is returned to the client in a successful creation
277 * response. The client can pass that object as-is back to the rollbackVnf
278 * operation to undo the creation.
280 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
281 * but APIs were apparently never updated.
284 public void rollbackVnf (VnfRollback rollback) throws VnfException {
285 long startTime = System.currentTimeMillis ();
286 // rollback may be null (e.g. if stack already existed when Create was called)
287 if (rollback == null) {
288 logger.info ("{} {} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf", MsoLogger
293 // Don't rollback if nothing was done originally
294 if (!rollback.getVnfCreated()) {
298 // Get the elements of the VnfRollback object for easier access
299 String cloudSiteId = rollback.getCloudSiteId ();
300 String tenantId = rollback.getTenantId ();
301 String vfModuleId = rollback.getVfModuleStackId ();
303 MsoLogger.setLogContext (rollback.getMsoRequest());
305 logger.debug("Rolling Back VF Module {} in {}", vfModuleId, cloudSiteId + "/" + tenantId);
307 DeploymentInfo deployment = null;
309 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
310 // The possible outcomes of deleteStack are a StackInfo object with status
311 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
313 long subStartTime = System.currentTimeMillis ();
315 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
316 // Go directly to Keystone until APIs could be updated to supply the name.
317 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
318 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
320 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
321 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
322 logger.debug("Rolled back deployment: {}", deployment.getId());
323 } catch (MsoException me) {
324 // Failed to rollback the VNF due to a cloudify exception.
325 // Convert to a generic VnfException
326 me.addContext ("RollbackVNF");
327 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
328 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudSiteId,
329 tenantId, CLOUDIFY, "DeleteDeployment", MsoLogger.ErrorCode.DataError.getValue(),
330 "Exception - DeleteDeployment", me);
332 throw new VnfException (me);
338 private VnfStatus deploymentStatusToVnfStatus (DeploymentInfo deployment) {
339 // Determine the status based on last action & status
340 // DeploymentInfo object should be enhanced to report a better status internally.
341 DeploymentStatus status = deployment.getStatus();
342 String lastAction = deployment.getLastAction();
344 if (status == null || lastAction == null) {
345 return VnfStatus.UNKNOWN;
347 else if (status == DeploymentStatus.NOTFOUND) {
348 return VnfStatus.NOTFOUND;
350 else if (status == DeploymentStatus.INSTALLED) {
351 return VnfStatus.ACTIVE;
353 else if (status == DeploymentStatus.CREATED) {
354 // Should have an INACTIVE status for this case. Shouldn't really happen, but
355 // Install was never run, or Uninstall was done but deployment didn't get deleted.
356 return VnfStatus.UNKNOWN;
358 else if (status == DeploymentStatus.FAILED) {
359 return VnfStatus.FAILED;
362 return VnfStatus.UNKNOWN;
365 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
366 Map <String, String> stringOutputs = new HashMap <String, String> ();
367 for (String key : stackOutputs.keySet ()) {
368 if (stackOutputs.get (key) instanceof String) {
369 stringOutputs.put (key, (String) stackOutputs.get (key));
370 } else if (stackOutputs.get(key) instanceof Integer) {
372 String str = "" + stackOutputs.get(key);
373 stringOutputs.put(key, str);
374 } catch (Exception e) {
375 logger.debug("Unable to add " + key + " to outputs");
377 } else if (stackOutputs.get(key) instanceof JsonNode) {
379 String str = this.convertNode((JsonNode) stackOutputs.get(key));
380 stringOutputs.put(key, str);
381 } catch (Exception e) {
382 logger.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
384 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
386 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
387 stringOutputs.put(key, str);
388 } catch (Exception e) {
389 logger.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
393 String str = stackOutputs.get(key).toString();
394 stringOutputs.put(key, str);
395 } catch (Exception e) {
396 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
400 return stringOutputs;
404 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
406 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
407 if (inputs == null) {
410 else if (inputs.size() < 1) {
411 sb.append("\tEMPTY");
413 for (String str : inputs.keySet()) {
416 outputString = inputs.get(str).toString();
417 } catch (Exception e) {
418 outputString = "Unable to call toString() on the value for " + str;
420 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
423 logger.debug(sb.toString());
427 private void sendMapToDebug(Map<String, Object> inputs) {
429 StringBuilder sb = new StringBuilder("inputs:");
430 if (inputs == null) {
433 else if (inputs.size() < 1) {
434 sb.append("\tEMPTY");
436 for (String str : inputs.keySet()) {
437 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
440 logger.debug(sb.toString());
444 private String convertNode(final JsonNode node) {
446 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
447 final String json = JSON_MAPPER.writeValueAsString(obj);
449 } catch (JsonParseException jpe) {
450 logger.debug("Error converting json to string " + jpe.getMessage());
451 } catch (Exception e) {
452 logger.debug("Error converting json to string " + e.getMessage());
454 return "[Error converting json to string]";
457 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
458 if (objectMap == null) {
461 Map<String, String> stringMap = new HashMap<String, String>();
462 for (String key : objectMap.keySet()) {
463 if (!stringMap.containsKey(key)) {
464 Object obj = objectMap.get(key);
465 if (obj instanceof String) {
466 stringMap.put(key, (String) objectMap.get(key));
467 } else if (obj instanceof JsonNode ){
468 // This is a bit of mess - but I think it's the least impacting
469 // let's convert it BACK to a string - then it will get converted back later
471 String str = this.convertNode((JsonNode) obj);
472 stringMap.put(key, str);
473 } catch (Exception e) {
474 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key);
475 //okay in this instance - only string values (fqdn) are expected to be needed
477 } else if (obj instanceof java.util.LinkedHashMap) {
478 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
480 String str = JSON_MAPPER.writeValueAsString(obj);
481 stringMap.put(key, str);
482 } catch (Exception e) {
483 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key);
485 } else if (obj instanceof Integer) {
487 String str = "" + obj;
488 stringMap.put(key, str);
489 } catch (Exception e) {
490 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key);
494 String str = obj.toString();
495 stringMap.put(key, str);
496 } catch (Exception e) {
497 logger.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")");
507 * This is the "Create VF Module" web service implementation.
508 * It will instantiate a new VF Module of the requested type in the specified cloud
509 * and tenant. The tenant must exist before this service is called.
511 * If a VF Module with the same name already exists, this can be considered a
512 * success or failure, depending on the value of the 'failIfExists' parameter.
514 * All VF Modules are defined in the MSO catalog. The caller must request
515 * one of the pre-defined module types or an error will be returned. Within the
516 * catalog, each VF Module references (among other things) a cloud template
517 * which is used to deploy the required artifacts (VMs, networks, etc.)
518 * to the cloud. In this adapter implementation, that artifact is expected
519 * to be a Cloudify blueprint.
521 * Depending on the blueprint, a variable set of input parameters will
522 * be defined, some of which are required. The caller is responsible to
523 * pass the necessary input data for the module or an error will be thrown.
525 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
526 * object. This last object can be passed as-is to the rollbackVnf operation to
527 * undo everything that was created for the Module. This is useful if a VF module
528 * is successfully created but the orchestration fails on a subsequent step.
530 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
531 * @param tenantId Openstack tenant identifier
532 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
533 * Deprecated - should use modelCustomizationUuid
534 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
535 * Deprecated - VF Module versions also captured by modelCustomizationUuid
536 * @param genericVnfId Generic VNF ID
537 * @param vfModuleName Name to be assigned to the new VF Module
538 * @param vfModuleId Id of the new VF Module
539 * @param requestType Indicates if this is a Volume Group or Module request
540 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
541 * to attach to a VF Module
542 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
543 * this is an Add-on module
544 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
545 * the use of vfModuleType.
546 * @param inputs Map of key=value inputs for VNF stack creation
547 * @param failIfExists Flag whether already existing VNF should be considered
548 * @param backout Flag whether to suppress automatic backout (for testing)
549 * @param msoRequest Request tracking information for logs
550 * @param vnfId Holder for output VNF Cloudify Deployment ID
551 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
552 * @param rollback Holder for returning VnfRollback object
555 public void createVfModule(String cloudSiteId,
563 String volumeGroupId,
564 String baseVfModuleId,
565 String modelCustomizationUuid,
566 Map <String, Object> inputs,
567 Boolean failIfExists,
569 Boolean enableBridge,
570 MsoRequest msoRequest,
571 Holder <String> vnfId,
572 Holder <Map <String, String>> outputs,
573 Holder <VnfRollback> rollback)
576 // Will capture execution time for metrics
577 long startTime = System.currentTimeMillis ();
579 MsoLogger.setLogContext (msoRequest);
581 // Require a model customization ID. Every VF Module definition must have one.
582 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
583 logger.debug("Missing required input: modelCustomizationUuid");
584 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
585 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
586 "VF Module ModelCustomizationUuid", CLOUDIFY, MsoLogger.ErrorCode.DataError.getValue(),
587 "Create VF Module: Missing required input: modelCustomizationUuid");
589 throw new VnfException(error, MsoExceptionCategory.USERDATA);
592 // Clean up some inputs to make comparisons easier
593 if (requestType == null)
596 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
597 volumeGroupId = null;
599 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
600 baseVfModuleId = null;
602 if (inputs == null) {
603 // Create an empty set of inputs
604 inputs = new HashMap<>();
605 logger.debug("inputs == null - setting to empty");
607 this.sendMapToDebug(inputs);
610 // Check if this is for a "Volume" module
611 boolean isVolumeRequest = false;
612 if (requestType.startsWith("VOLUME")) {
613 isVolumeRequest = true;
616 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " +
619 // Build a default rollback object (no actions performed)
620 VnfRollback vfRollback = new VnfRollback();
621 vfRollback.setCloudSiteId(cloudSiteId);
622 vfRollback.setTenantId(tenantId);
623 vfRollback.setMsoRequest(msoRequest);
624 vfRollback.setRequestType(requestType);
625 vfRollback.setIsBase(false); // Until we know better
626 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
627 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
628 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
629 vfRollback.setMode("CFY");
631 rollback.value = vfRollback; // Default rollback - no updates performed
633 // Get the VNF/VF Module definition from the Catalog DB first.
634 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
637 VnfResource vnfResource = null;
638 VfModuleCustomization vfmc = null;
641 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
644 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
645 + modelCustomizationUuid;
647 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VF Module "
648 + "ModelCustomizationUuid",
649 modelCustomizationUuid, "CatalogDb", MsoLogger.ErrorCode.DataError.getValue(), error);
650 throw new VnfException(error, MsoExceptionCategory.USERDATA);
652 logger.debug("Found vfModuleCust entry " + vfmc.toString());
655 // Get the vfModule and vnfResource records
656 vf = vfmc.getVfModule();
657 vnfResource = vfmc.getVfModule().getVnfResources();
659 catch (Exception e) {
661 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
662 throw new VnfException("Exception during create VF " + e.getMessage());
665 // Perform a version check against cloudSite
666 // Obtain the cloud site information where we will create the VF Module
667 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId);
668 if (!cloudSiteOp.isPresent()) {
669 throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId));
671 CloudSite cloudSite = cloudSiteOp.get();
672 MavenLikeVersioning aicV = new MavenLikeVersioning();
673 aicV.setVersion(cloudSite.getCloudVersion());
675 String vnfMin = vnfResource.getAicVersionMin();
676 String vnfMax = vnfResource.getAicVersionMax();
678 if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) ||
679 (vnfMax != null && aicV.isMoreRecentThan(vnfMax)))
682 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
683 + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId
684 + " with AIC_Version:" + cloudSite.getCloudVersion();
685 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
686 MsoLogger.ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
688 throw new VnfException(error, MsoExceptionCategory.USERDATA);
693 DeploymentInfo cloudifyDeployment = null;
695 // First, look up to see if the VF already exists.
697 long subStartTime1 = System.currentTimeMillis ();
699 cloudifyDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, vfModuleName);
701 catch (MsoException me) {
702 // Failed to query the Deployment due to a cloudify exception.
703 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
704 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudSiteId,
705 tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError.getValue(),
706 "Exception - queryDeployment", me);
709 // Convert to a generic VnfException
710 me.addContext ("CreateVFModule");
711 throw new VnfException (me);
714 // More precise handling/messaging if the Module already exists
715 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus () == DeploymentStatus.NOTFOUND)) {
716 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
717 DeploymentStatus status = cloudifyDeployment.getStatus();
718 logger.debug ("Found Existing Deployment, status=" + status);
720 if (status == DeploymentStatus.INSTALLED) {
722 if (failIfExists != null && failIfExists) {
723 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
724 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
725 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError.getValue(),
726 "Deployment " + vfModuleName + " already exists");
728 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
730 // Found existing deployment and client has not requested "failIfExists".
731 // Populate the outputs from the existing deployment.
733 vnfId.value = cloudifyDeployment.getId();
734 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
738 // Check through various detailed error cases
739 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
740 // fail - it's in progress - return meaningful error
741 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.";
742 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
743 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError.getValue(),
744 "Deployment " + vfModuleName + " already exists");
746 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
748 else if (status == DeploymentStatus.FAILED) {
749 // fail - it exists and is in a FAILED state
750 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
751 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
752 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError.getValue(),
753 "Deployment " + vfModuleName + " already " + "exists and is in FAILED state");
755 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
757 else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
758 // fail - it exists and is in a UNKNOWN state
759 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
760 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
761 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError.getValue(),
762 "Deployment " + vfModuleName + " already " + "exists and is in " + status.toString() + " state");
764 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
767 // Unexpected, since all known status values have been tested for
769 "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status
770 .toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
771 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
772 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError.getValue(),
773 "Deployment " + vfModuleName + " already " + "exists and is in an unknown state");
775 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
780 // Collect outputs from Base Modules and Volume Modules
781 Map<String, Object> baseModuleOutputs = null;
782 Map<String, Object> volumeGroupOutputs = null;
784 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
785 if (volumeGroupId != null) {
786 long subStartTime2 = System.currentTimeMillis ();
787 DeploymentInfo volumeDeployment = null;
789 volumeDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, volumeGroupId);
791 catch (MsoException me) {
792 // Failed to query the Volume GroupDeployment due to a cloudify exception.
793 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
794 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
795 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(volume)",
796 MsoLogger.ErrorCode.DataError.getValue(), "Exception - queryDeployment(volume)", me);
798 // Convert to a generic VnfException
799 me.addContext ("CreateVFModule(QueryVolume)");
800 throw new VnfException (me);
803 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
805 "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/"
806 + tenantId + " USER ERROR";
807 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
808 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(volume)",
809 MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
810 "Create VFModule: Attached Volume Group DOES NOT EXIST");
812 throw new VnfException(error, MsoExceptionCategory.USERDATA);
814 logger.debug("Found nested volume group");
815 volumeGroupOutputs = volumeDeployment.getOutputs();
816 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
820 // If this is an Add-On Module, query the Base Module outputs
821 // Note: This will be performed whether or not the current request is for an
822 // Add-On Volume Group or Add-On VF Module
824 if (vf.getIsBase()) {
825 logger.debug("This is a BASE Module request");
826 vfRollback.setIsBase(true);
828 logger.debug("This is an Add-On Module request");
830 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
831 // Add-on Volume requests may or may not specify a base.
832 if (!isVolumeRequest && baseVfModuleId == null) {
833 logger.debug ("WARNING: Add-on Module request - no Base Module ID provided");
836 if (baseVfModuleId != null) {
837 long subStartTime2 = System.currentTimeMillis ();
838 DeploymentInfo baseDeployment = null;
840 baseDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, baseVfModuleId);
842 catch (MsoException me) {
843 // Failed to query the Volume GroupDeployment due to a cloudify exception.
845 "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": "
847 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
848 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)",
849 MsoLogger.ErrorCode.DataError.getValue(), "Exception - queryDeployment(Base)", me);
851 // Convert to a generic VnfException
852 me.addContext("CreateVFModule(QueryBase)");
853 throw new VnfException (me);
856 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
858 "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/"
859 + tenantId + " USER ERROR";
860 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
861 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(Base)",
862 MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
863 "Create VFModule: Base " + "Module DOES NOT EXIST");
865 throw new VnfException(error, MsoExceptionCategory.USERDATA);
867 logger.debug("Found base module");
868 baseModuleOutputs = baseDeployment.getOutputs();
869 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
875 // Ready to deploy the new VNF
877 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
878 // In final implementation (post-POC), the template object would either be generic or there would
879 // be a separate DB Table/Object for Blueprints.
882 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
883 HeatTemplate heatTemplate = null;
884 HeatEnvironment heatEnvironment = null;
885 if (isVolumeRequest) {
886 heatTemplate = vf.getVolumeHeatTemplate();
887 heatEnvironment = vfmc.getVolumeHeatEnv();
889 heatTemplate = vf.getModuleHeatTemplate();
890 heatEnvironment = vfmc.getHeatEnvironment();
893 if (heatTemplate == null) {
894 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType="
896 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID", vfModuleType,
897 "OpenStack", MsoLogger.ErrorCode.DataError.getValue(), error);
898 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
900 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
903 if (heatEnvironment == null) {
904 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
905 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
906 "OpenStack", MsoLogger.ErrorCode.DataError.getValue(), error);
907 // Alarm on this error, configuration must be fixed
908 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
910 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
915 // All variables converted to their native object types
916 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
917 List<String> extraInputs = new ArrayList<String>();
919 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
920 // This whole section needs to be rewritten.
921 Boolean skipInputChecks = false;
923 if (skipInputChecks) {
924 goldenInputs = new HashMap<String,Object>();
925 for (String key : inputs.keySet()) {
926 goldenInputs.put(key, inputs.get(key));
930 // Build maps for the parameters (including aliases) to simplify checks
931 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
933 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
934 logger.debug("paramSet has {} entries", paramSet.size());
936 for (HeatTemplateParam htp : paramSet) {
937 params.put(htp.getParamName(), htp);
940 String alias = htp.getParamAlias();
941 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
942 params.put(alias, htp);
946 // First, convert all inputs to their "template" type
947 for (String key : inputs.keySet()) {
948 if (params.containsKey(key)) {
949 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
951 goldenInputs.put(key, value);
954 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key)
958 extraInputs.add(key);
962 if (!extraInputs.isEmpty()) {
963 logger.debug("Ignoring extra inputs: " + extraInputs);
966 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
967 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
968 for (String key : volumeGroupOutputs.keySet()) {
969 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
970 goldenInputs.put(key, volumeGroupOutputs.get(key));
975 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
976 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
977 for (String key : baseModuleOutputs.keySet()) {
978 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
979 goldenInputs.put(key, baseModuleOutputs.get(key));
984 // Last, add in values from the "environment" file.
985 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
987 // TODO: This may take a different form for Cloudify, but for now process it
988 // with Heat environment file syntax
989 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
990 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
992 if (mhee.getParameters() != null) {
993 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
994 // If this is a template input, copy to golden inputs
995 String envKey = envParam.getName();
996 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
997 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
999 goldenInputs.put(envKey, value);
1002 logger.debug("Failed to convert environment parameter " + envKey + "='" + envParam.getValue() + "' to " +
1003 params.get(envKey).getParamType());
1009 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
1012 // Check that required parameters have been supplied from any of the sources
1013 String missingParams = null;
1014 boolean checkRequiredParameters = true;
1016 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
1017 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1018 checkRequiredParameters = false;
1019 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
1020 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
1022 } catch (Exception e) {
1023 // No problem - default is true
1024 logger.debug("An exception occured trying to get property {}",
1025 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
1029 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1030 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1031 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1032 if (missingParams == null) {
1033 missingParams = parm.getParamName();
1035 missingParams += "," + parm.getParamName();
1040 if (missingParams != null) {
1041 if (checkRequiredParameters) {
1042 // Problem - missing one or more required parameters
1043 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1044 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, CLOUDIFY,
1045 MsoLogger.ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1046 logger.debug(error);
1047 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1050 "found missing parameters [" + missingParams + "] - but checkRequiredParameters is false -"
1051 + " will not block");
1054 logger.debug("No missing parameters found - ok to proceed");
1057 } // NOTE: END PARAMETER CHECKING
1059 // Ready to deploy the VF Module.
1060 // *First step - make sure the blueprint is loaded into Cloudify.
1061 String blueprintName = heatTemplate.getTemplateName();
1062 String blueprint = heatTemplate.getTemplateBody();
1063 String blueprintId = blueprintName;
1065 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
1066 if (blueprintId.endsWith(".yaml"))
1067 blueprintId = blueprintId.substring(0,blueprintId.lastIndexOf(".yaml"));
1070 if (! cloudifyUtils.isBlueprintLoaded (cloudSiteId, blueprintId)) {
1071 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
1073 Map<String,byte[]> blueprintFiles = new HashMap<String,byte[]>();
1075 blueprintFiles.put(blueprintName, blueprint.getBytes());
1077 // TODO: Implement nested blueprint logic based on Cloudify structures.
1078 // For now, just use the Heat structures.
1079 // The query returns a map of String->Object, where the map keys provide one layer of
1080 // indirection from the Heat template names. For this case, assume the map key matches
1081 // the nested blueprint name.
1082 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1083 if (nestedBlueprints != null) {
1084 for (HeatTemplate nestedBlueprint: nestedBlueprints) {
1085 blueprintFiles.put(nestedBlueprint.getTemplateName(), nestedBlueprint.getTemplateBody().getBytes());
1089 // TODO: Implement file artifact logic based on Cloudify structures.
1090 // For now, just use the Heat structures.
1091 List<HeatFiles> heatFiles = vf.getHeatFiles();
1092 if (heatFiles != null) {
1093 for (HeatFiles heatFile: heatFiles) {
1094 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1098 // Upload the blueprint package
1099 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1104 catch (MsoException me) {
1105 me.addContext("CreateVFModule");
1106 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1107 logger.error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudSiteId,
1108 tenantId, CLOUDIFY, MsoLogger.ErrorCode.DataError.getValue(), "MsoException - uploadBlueprint", me);
1109 logger.debug(error);
1110 throw new VnfException(me);
1113 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1114 // because we already checked for those.
1115 long createDeploymentStarttime = System.currentTimeMillis ();
1117 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1118 // Go directly to Keystone until APIs could be updated to supply the name.
1119 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1120 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
1122 if (backout == null) {
1126 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment (cloudSiteId,
1132 heatTemplate.getTimeoutMinutes (),
1133 backout.booleanValue());
1135 } catch (MsoException me) {
1136 me.addContext ("CreateVFModule");
1137 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1139 .error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudSiteId,
1140 tenantId, CLOUDIFY, MsoLogger.ErrorCode.DataError.getValue(), "MsoException - createDeployment",
1142 logger.debug(error);
1143 throw new VnfException (me);
1144 } catch (NullPointerException npe) {
1145 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1147 .error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudSiteId,
1148 tenantId, CLOUDIFY, MsoLogger.ErrorCode.DataError.getValue(),
1149 "NullPointerException - createDeployment", npe);
1150 logger.debug(error);
1151 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1152 //npe.addContext ("CreateVNF");
1153 throw new VnfException ("NullPointerException during cloudify.createAndInstallDeployment");
1154 } catch (Exception e) {
1155 logger.debug("unhandled exception at cloudify.createAndInstallDeployment");
1156 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1158 } catch (Exception e) {
1159 logger.debug("unhandled exception in create VF");
1160 throw new VnfException("Exception during create VF " + e.getMessage());
1164 // Reach this point if create is successful.
1165 // Populate remaining rollback info and response parameters.
1166 vfRollback.setVnfCreated (true);
1167 vfRollback.setVnfId (cloudifyDeployment.getId());
1168 vnfId.value = cloudifyDeployment.getId();
1169 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
1171 rollback.value = vfRollback;
1173 logger.debug("VF Module successfully created", vfModuleName);
1177 public void deleteVfModule (String cloudSiteId,
1180 MsoRequest msoRequest,
1181 Holder <Map <String, String>> outputs) throws VnfException {
1182 MsoLogger.setLogContext (msoRequest);
1183 logger.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1184 // Will capture execution time for metrics
1185 long startTime = System.currentTimeMillis ();
1187 // 1702 capture the output parameters on a delete
1188 // so we'll need to query first
1189 DeploymentInfo deployment = null;
1191 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1192 } catch (MsoException me) {
1193 // Failed to query the deployment. Convert to a generic VnfException
1194 me.addContext ("DeleteVFModule");
1195 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1196 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudSiteId,
1197 tenantId, CLOUDIFY, "QueryDeployment", MsoLogger.ErrorCode.DataError.getValue(),
1198 "Exception - QueryDeployment", me);
1199 logger.debug(error);
1200 throw new VnfException (me);
1202 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1203 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1205 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1206 // The possible outcomes of deleteStack are a StackInfo object with status
1207 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1209 long subStartTime = System.currentTimeMillis ();
1211 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1212 } catch (MsoException me) {
1213 me.addContext("DeleteVfModule");
1214 // Convert to a generic VnfException
1215 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1216 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudSiteId,
1217 tenantId, "DeleteDeployment", "DeleteDeployment", MsoLogger.ErrorCode.DataError.getValue(),
1218 "Exception - DeleteDeployment: " + me.getMessage());
1219 logger.debug(error);
1220 throw new VnfException(me);
1223 // On success, nothing is returned.
1227 // TODO: Should Update be supported for Cloudify? What would this look like?
1229 public void updateVfModule (String cloudSiteId,
1235 String volumeGroupHeatStackId,
1236 String baseVfHeatStackId,
1237 String vfModuleStackId,
1238 String modelCustomizationUuid,
1239 Map <String, Object> inputs,
1240 MsoRequest msoRequest,
1241 Holder <Map <String, String>> outputs,
1242 Holder <VnfRollback> rollback) throws VnfException
1244 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1245 logger.debug("Update VF Module command attempted but not supported");
1246 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);