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.ErrorCode;
56 import org.onap.so.logger.MessageEnum;
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,
138 String volumeGroupHeatStackId,
139 Map <String, Object> inputs,
140 Boolean failIfExists,
142 Boolean enableBridge,
143 MsoRequest msoRequest,
144 Holder <String> vnfId,
145 Holder <Map <String, String>> outputs,
146 Holder <VnfRollback> rollback)
149 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
150 logger.debug("CreateVNF command attempted but not supported");
151 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
155 * This is the "Update VNF" web service implementation.
156 * This function is now unsupported and will return an error.
160 public void updateVnf (String cloudSiteId,
167 String volumeGroupHeatStackId,
168 Map <String, Object> inputs,
169 MsoRequest msoRequest,
170 Holder <Map <String, String>> outputs,
171 Holder <VnfRollback> rollback)
174 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
175 logger.debug("UpdateVNF command attempted but not supported");
176 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
180 * This is the "Query VNF" web service implementation.
182 * This really should be QueryVfModule, but nobody ever changed it.
184 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same
185 * as deployment name, since it assigned by the client when a deployment is created.
186 * Also, the input cloudSiteId is used only to identify which Cloudify instance to query,
187 * and the tenantId is ignored (since that really only applies for Openstack/Heat).
189 * The method returns an indicator that the VNF exists, along with its status and outputs.
190 * The input "vnfName" will also be reflected back as its ID.
192 * @param cloudSiteId CLLI code of the cloud site in which to query
193 * @param cloudOwner cloud owner of the cloud site in which to query
194 * @param tenantId Openstack tenant identifier - ignored for Cloudify
195 * @param vnfName VNF Name (should match a deployment ID)
196 * @param msoRequest Request tracking information for logs
197 * @param vnfExists Flag reporting the result of the query
198 * @param vnfId Holder for output VNF ID
199 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
202 public void queryVnf (String cloudSiteId,
206 MsoRequest msoRequest,
207 Holder <Boolean> vnfExists,
208 Holder <String> vnfId,
209 Holder <VnfStatus> status,
210 Holder <Map <String, String>> outputs)
213 logger.debug ("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
215 // Will capture execution time for metrics
216 long startTime = System.currentTimeMillis ();
217 long subStartTime = System.currentTimeMillis ();
219 DeploymentInfo deployment = null;
222 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
224 catch (MsoCloudifyManagerNotFound e) {
225 // This site does not have a Cloudify Manager.
226 // This isn't an error, just means we won't find the VNF here.
229 catch (MsoException me) {
230 // Failed to query the Deployment due to a cloudify exception.
231 // Convert to a generic VnfException
232 me.addContext("QueryVNF");
233 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
235 .error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
236 CLOUDIFY, "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryDeployment", me);
238 throw new VnfException(me);
241 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
242 vnfExists.value = Boolean.TRUE;
243 status.value = deploymentStatusToVnfStatus(deployment);
244 vnfId.value = deployment.getId();
245 outputs.value = copyStringOutputs(deployment.getOutputs());
247 logger.debug("VNF {} found in Cloudify, ID = {}", vnfName, vnfId.value);
249 vnfExists.value = Boolean.FALSE;
250 status.value = VnfStatus.NOTFOUND;
252 outputs.value = new HashMap<String, String>(); // Return as an empty map
254 logger.debug("VNF {} not found", vnfName);
261 * This is the "Delete VNF" web service implementation.
262 * This function is now unsupported and will return an error.
266 public void deleteVnf (String cloudSiteId,
270 MsoRequest msoRequest) throws VnfException {
272 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
273 logger.debug("DeleteVNF command attempted but not supported");
274 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
278 * This web service endpoint will rollback a previous Create VNF operation.
279 * A rollback object is returned to the client in a successful creation
280 * response. The client can pass that object as-is back to the rollbackVnf
281 * operation to undo the creation.
283 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
284 * but APIs were apparently never updated.
287 public void rollbackVnf (VnfRollback rollback) throws VnfException {
288 long startTime = System.currentTimeMillis ();
289 // rollback may be null (e.g. if stack already existed when Create was called)
290 if (rollback == null) {
291 logger.info ("{} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
295 // Don't rollback if nothing was done originally
296 if (!rollback.getVnfCreated()) {
300 // Get the elements of the VnfRollback object for easier access
301 String cloudSiteId = rollback.getCloudSiteId ();
302 String cloudOwner = rollback.getCloudOwner();
303 String tenantId = rollback.getTenantId ();
304 String vfModuleId = rollback.getVfModuleStackId ();
306 logger.debug("Rolling Back VF Module {} in {}", vfModuleId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
308 DeploymentInfo deployment = null;
310 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
311 // The possible outcomes of deleteStack are a StackInfo object with status
312 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
314 long subStartTime = System.currentTimeMillis ();
316 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
317 // Go directly to Keystone until APIs could be updated to supply the name.
318 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
319 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
321 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
322 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
323 logger.debug("Rolled back deployment: {}", deployment.getId());
324 } catch (MsoException me) {
325 // Failed to rollback the VNF due to a cloudify exception.
326 // Convert to a generic VnfException
327 me.addContext ("RollbackVNF");
328 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
329 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
330 tenantId, CLOUDIFY, "DeleteDeployment", ErrorCode.DataError.getValue(),
331 "Exception - DeleteDeployment", me);
333 throw new VnfException (me);
339 private VnfStatus deploymentStatusToVnfStatus (DeploymentInfo deployment) {
340 // Determine the status based on last action & status
341 // DeploymentInfo object should be enhanced to report a better status internally.
342 DeploymentStatus status = deployment.getStatus();
343 String lastAction = deployment.getLastAction();
345 if (status == null || lastAction == null) {
346 return VnfStatus.UNKNOWN;
348 else if (status == DeploymentStatus.NOTFOUND) {
349 return VnfStatus.NOTFOUND;
351 else if (status == DeploymentStatus.INSTALLED) {
352 return VnfStatus.ACTIVE;
354 else if (status == DeploymentStatus.CREATED) {
355 // Should have an INACTIVE status for this case. Shouldn't really happen, but
356 // Install was never run, or Uninstall was done but deployment didn't get deleted.
357 return VnfStatus.UNKNOWN;
359 else if (status == DeploymentStatus.FAILED) {
360 return VnfStatus.FAILED;
363 return VnfStatus.UNKNOWN;
366 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
367 Map <String, String> stringOutputs = new HashMap <String, String> ();
368 for (String key : stackOutputs.keySet ()) {
369 if (stackOutputs.get (key) instanceof String) {
370 stringOutputs.put (key, (String) stackOutputs.get (key));
371 } else if (stackOutputs.get(key) instanceof Integer) {
373 String str = "" + stackOutputs.get(key);
374 stringOutputs.put(key, str);
375 } catch (Exception e) {
376 logger.debug("Unable to add " + key + " to outputs");
378 } else if (stackOutputs.get(key) instanceof JsonNode) {
380 String str = this.convertNode((JsonNode) stackOutputs.get(key));
381 stringOutputs.put(key, str);
382 } catch (Exception e) {
383 logger.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
385 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
387 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
388 stringOutputs.put(key, str);
389 } catch (Exception e) {
390 logger.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
394 String str = stackOutputs.get(key).toString();
395 stringOutputs.put(key, str);
396 } catch (Exception e) {
397 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
401 return stringOutputs;
405 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
407 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
408 if (inputs == null) {
411 else if (inputs.size() < 1) {
412 sb.append("\tEMPTY");
414 for (String str : inputs.keySet()) {
417 outputString = inputs.get(str).toString();
418 } catch (Exception e) {
419 outputString = "Unable to call toString() on the value for " + str;
421 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
424 logger.debug(sb.toString());
428 private void sendMapToDebug(Map<String, Object> inputs) {
430 StringBuilder sb = new StringBuilder("inputs:");
431 if (inputs == null) {
434 else if (inputs.size() < 1) {
435 sb.append("\tEMPTY");
437 for (String str : inputs.keySet()) {
438 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
441 logger.debug(sb.toString());
445 private String convertNode(final JsonNode node) {
447 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
448 final String json = JSON_MAPPER.writeValueAsString(obj);
450 } catch (JsonParseException jpe) {
451 logger.debug("Error converting json to string " + jpe.getMessage());
452 } catch (Exception e) {
453 logger.debug("Error converting json to string " + e.getMessage());
455 return "[Error converting json to string]";
458 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
459 if (objectMap == null) {
462 Map<String, String> stringMap = new HashMap<String, String>();
463 for (String key : objectMap.keySet()) {
464 if (!stringMap.containsKey(key)) {
465 Object obj = objectMap.get(key);
466 if (obj instanceof String) {
467 stringMap.put(key, (String) objectMap.get(key));
468 } else if (obj instanceof JsonNode ){
469 // This is a bit of mess - but I think it's the least impacting
470 // let's convert it BACK to a string - then it will get converted back later
472 String str = this.convertNode((JsonNode) obj);
473 stringMap.put(key, str);
474 } catch (Exception e) {
475 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key);
476 //okay in this instance - only string values (fqdn) are expected to be needed
478 } else if (obj instanceof java.util.LinkedHashMap) {
479 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
481 String str = JSON_MAPPER.writeValueAsString(obj);
482 stringMap.put(key, str);
483 } catch (Exception e) {
484 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key);
486 } else if (obj instanceof Integer) {
488 String str = "" + obj;
489 stringMap.put(key, str);
490 } catch (Exception e) {
491 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key);
495 String str = obj.toString();
496 stringMap.put(key, str);
497 } catch (Exception e) {
498 logger.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")");
508 * This is the "Create VF Module" web service implementation.
509 * It will instantiate a new VF Module of the requested type in the specified cloud
510 * and tenant. The tenant must exist before this service is called.
512 * If a VF Module with the same name already exists, this can be considered a
513 * success or failure, depending on the value of the 'failIfExists' parameter.
515 * All VF Modules are defined in the MSO catalog. The caller must request
516 * one of the pre-defined module types or an error will be returned. Within the
517 * catalog, each VF Module references (among other things) a cloud template
518 * which is used to deploy the required artifacts (VMs, networks, etc.)
519 * to the cloud. In this adapter implementation, that artifact is expected
520 * to be a Cloudify blueprint.
522 * Depending on the blueprint, a variable set of input parameters will
523 * be defined, some of which are required. The caller is responsible to
524 * pass the necessary input data for the module or an error will be thrown.
526 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
527 * object. This last object can be passed as-is to the rollbackVnf operation to
528 * undo everything that was created for the Module. This is useful if a VF module
529 * is successfully created but the orchestration fails on a subsequent step.
531 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
532 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
533 * @param tenantId Openstack tenant identifier
534 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
535 * Deprecated - should use modelCustomizationUuid
536 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
537 * Deprecated - VF Module versions also captured by modelCustomizationUuid
538 * @param genericVnfId Generic VNF ID
539 * @param vfModuleName Name to be assigned to the new VF Module
540 * @param vfModuleId Id of the new VF Module
541 * @param requestType Indicates if this is a Volume Group or Module request
542 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
543 * to attach to a VF Module
544 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
545 * this is an Add-on module
546 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
547 * the use of vfModuleType.
548 * @param inputs Map of key=value inputs for VNF stack creation
549 * @param failIfExists Flag whether already existing VNF should be considered
550 * @param backout Flag whether to suppress automatic backout (for testing)
551 * @param msoRequest Request tracking information for logs
552 * @param vnfId Holder for output VNF Cloudify Deployment ID
553 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
554 * @param rollback Holder for returning VnfRollback object
557 public void createVfModule(String cloudSiteId,
566 String volumeGroupId,
567 String baseVfModuleId,
568 String modelCustomizationUuid,
569 Map <String, Object> inputs,
570 Boolean failIfExists,
572 Boolean enableBridge,
573 MsoRequest msoRequest,
574 Holder <String> vnfId,
575 Holder <Map <String, String>> outputs,
576 Holder <VnfRollback> rollback)
579 // Will capture execution time for metrics
580 long startTime = System.currentTimeMillis ();
582 // Require a model customization ID. Every VF Module definition must have one.
583 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
584 logger.debug("Missing required input: modelCustomizationUuid");
585 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
586 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
587 "VF Module ModelCustomizationUuid", CLOUDIFY, ErrorCode.DataError.getValue(),
588 "Create VF Module: Missing required input: modelCustomizationUuid");
590 throw new VnfException(error, MsoExceptionCategory.USERDATA);
593 // Clean up some inputs to make comparisons easier
594 if (requestType == null)
597 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
598 volumeGroupId = null;
600 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
601 baseVfModuleId = null;
603 if (inputs == null) {
604 // Create an empty set of inputs
605 inputs = new HashMap<>();
606 logger.debug("inputs == null - setting to empty");
608 this.sendMapToDebug(inputs);
611 // Check if this is for a "Volume" module
612 boolean isVolumeRequest = false;
613 if (requestType.startsWith("VOLUME")) {
614 isVolumeRequest = true;
617 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " +
620 // Build a default rollback object (no actions performed)
621 VnfRollback vfRollback = new VnfRollback();
622 vfRollback.setCloudSiteId(cloudSiteId);
623 vfRollback.setCloudOwner(cloudOwner);
624 vfRollback.setTenantId(tenantId);
625 vfRollback.setMsoRequest(msoRequest);
626 vfRollback.setRequestType(requestType);
627 vfRollback.setIsBase(false); // Until we know better
628 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
629 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
630 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
631 vfRollback.setMode("CFY");
633 rollback.value = vfRollback; // Default rollback - no updates performed
635 // Get the VNF/VF Module definition from the Catalog DB first.
636 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
639 VnfResource vnfResource = null;
640 VfModuleCustomization vfmc = null;
643 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
646 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
647 + modelCustomizationUuid;
649 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VF Module "
650 + "ModelCustomizationUuid",
651 modelCustomizationUuid, "CatalogDb", ErrorCode.DataError.getValue(), error);
652 throw new VnfException(error, MsoExceptionCategory.USERDATA);
654 logger.debug("Found vfModuleCust entry " + vfmc.toString());
657 // Get the vfModule and vnfResource records
658 vf = vfmc.getVfModule();
659 vnfResource = vfmc.getVfModule().getVnfResources();
661 catch (Exception e) {
663 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
664 throw new VnfException("Exception during create VF " + e.getMessage());
667 // Perform a version check against cloudSite
668 // Obtain the cloud site information where we will create the VF Module
669 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId);
670 if (!cloudSiteOp.isPresent()) {
671 throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId));
673 CloudSite cloudSite = cloudSiteOp.get();
674 MavenLikeVersioning aicV = new MavenLikeVersioning();
675 aicV.setVersion(cloudSite.getCloudVersion());
677 String vnfMin = vnfResource.getAicVersionMin();
678 String vnfMax = vnfResource.getAicVersionMax();
680 if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) ||
681 (vnfMax != null && aicV.isMoreRecentThan(vnfMax)))
684 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
685 + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId
686 + " with AIC_Version:" + cloudSite.getCloudVersion();
687 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
688 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
690 throw new VnfException(error, MsoExceptionCategory.USERDATA);
695 DeploymentInfo cloudifyDeployment = null;
697 // First, look up to see if the VF already exists.
699 long subStartTime1 = System.currentTimeMillis ();
701 cloudifyDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, vfModuleName);
703 catch (MsoException me) {
704 // Failed to query the Deployment due to a cloudify exception.
705 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
706 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudSiteId,
707 tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
708 "Exception - queryDeployment", me);
711 // Convert to a generic VnfException
712 me.addContext ("CreateVFModule");
713 throw new VnfException (me);
716 // More precise handling/messaging if the Module already exists
717 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus () == DeploymentStatus.NOTFOUND)) {
718 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
719 DeploymentStatus status = cloudifyDeployment.getStatus();
720 logger.debug ("Found Existing Deployment, status=" + status);
722 if (status == DeploymentStatus.INSTALLED) {
724 if (failIfExists != null && failIfExists) {
725 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId;
726 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
727 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
728 "Deployment " + vfModuleName + " already exists");
730 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
732 // Found existing deployment and client has not requested "failIfExists".
733 // Populate the outputs from the existing deployment.
735 vnfId.value = cloudifyDeployment.getId();
736 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
740 // Check through various detailed error cases
741 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
742 // fail - it's in progress - return meaningful error
743 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
744 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
745 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
746 "Deployment " + vfModuleName + " already exists");
748 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
750 else if (status == DeploymentStatus.FAILED) {
751 // fail - it exists and is in a FAILED state
752 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
753 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
754 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
755 "Deployment " + vfModuleName + " already " + "exists and is in FAILED state");
757 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
759 else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
760 // fail - it exists and is in a UNKNOWN state
761 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
762 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
763 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
764 "Deployment " + vfModuleName + " already " + "exists and is in " + status.toString() + " state");
766 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
769 // Unexpected, since all known status values have been tested for
771 "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status
772 .toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
773 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
774 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
775 "Deployment " + vfModuleName + " already " + "exists and is in an unknown state");
777 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
782 // Collect outputs from Base Modules and Volume Modules
783 Map<String, Object> baseModuleOutputs = null;
784 Map<String, Object> volumeGroupOutputs = null;
786 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
787 if (volumeGroupId != null) {
788 long subStartTime2 = System.currentTimeMillis ();
789 DeploymentInfo volumeDeployment = null;
791 volumeDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, volumeGroupId);
793 catch (MsoException me) {
794 // Failed to query the Volume GroupDeployment due to a cloudify exception.
795 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
796 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
797 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(volume)",
798 ErrorCode.DataError.getValue(), "Exception - queryDeployment(volume)", me);
800 // Convert to a generic VnfException
801 me.addContext ("CreateVFModule(QueryVolume)");
802 throw new VnfException (me);
805 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
807 "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/"
808 + tenantId + " USER ERROR";
809 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
810 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(volume)",
811 ErrorCode.BusinessProcesssError.getValue(),
812 "Create VFModule: Attached Volume Group DOES NOT EXIST");
814 throw new VnfException(error, MsoExceptionCategory.USERDATA);
816 logger.debug("Found nested volume group");
817 volumeGroupOutputs = volumeDeployment.getOutputs();
818 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
822 // If this is an Add-On Module, query the Base Module outputs
823 // Note: This will be performed whether or not the current request is for an
824 // Add-On Volume Group or Add-On VF Module
826 if (vf.getIsBase()) {
827 logger.debug("This is a BASE Module request");
828 vfRollback.setIsBase(true);
830 logger.debug("This is an Add-On Module request");
832 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
833 // Add-on Volume requests may or may not specify a base.
834 if (!isVolumeRequest && baseVfModuleId == null) {
835 logger.debug ("WARNING: Add-on Module request - no Base Module ID provided");
838 if (baseVfModuleId != null) {
839 long subStartTime2 = System.currentTimeMillis ();
840 DeploymentInfo baseDeployment = null;
842 baseDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, baseVfModuleId);
844 catch (MsoException me) {
845 // Failed to query the Volume GroupDeployment due to a cloudify exception.
847 "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": "
849 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
850 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)",
851 ErrorCode.DataError.getValue(), "Exception - queryDeployment(Base)", me);
853 // Convert to a generic VnfException
854 me.addContext("CreateVFModule(QueryBase)");
855 throw new VnfException (me);
858 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
860 "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/"
861 + tenantId + " USER ERROR";
862 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
863 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(Base)",
864 ErrorCode.BusinessProcesssError.getValue(),
865 "Create VFModule: Base " + "Module DOES NOT EXIST");
867 throw new VnfException(error, MsoExceptionCategory.USERDATA);
869 logger.debug("Found base module");
870 baseModuleOutputs = baseDeployment.getOutputs();
871 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
877 // Ready to deploy the new VNF
879 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
880 // In final implementation (post-POC), the template object would either be generic or there would
881 // be a separate DB Table/Object for Blueprints.
884 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
885 HeatTemplate heatTemplate = null;
886 HeatEnvironment heatEnvironment = null;
887 if (isVolumeRequest) {
888 heatTemplate = vf.getVolumeHeatTemplate();
889 heatEnvironment = vfmc.getVolumeHeatEnv();
891 heatTemplate = vf.getModuleHeatTemplate();
892 heatEnvironment = vfmc.getHeatEnvironment();
895 if (heatTemplate == null) {
896 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType="
898 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID", vfModuleType,
899 "OpenStack", ErrorCode.DataError.getValue(), error);
900 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
902 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
905 if (heatEnvironment == null) {
906 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
907 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
908 "OpenStack", ErrorCode.DataError.getValue(), error);
909 // Alarm on this error, configuration must be fixed
910 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
912 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
917 // All variables converted to their native object types
918 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
919 List<String> extraInputs = new ArrayList<String>();
921 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
922 // This whole section needs to be rewritten.
923 Boolean skipInputChecks = false;
925 if (skipInputChecks) {
926 goldenInputs = new HashMap<String,Object>();
927 for (String key : inputs.keySet()) {
928 goldenInputs.put(key, inputs.get(key));
932 // Build maps for the parameters (including aliases) to simplify checks
933 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
935 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
936 logger.debug("paramSet has {} entries", paramSet.size());
938 for (HeatTemplateParam htp : paramSet) {
939 params.put(htp.getParamName(), htp);
942 String alias = htp.getParamAlias();
943 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
944 params.put(alias, htp);
948 // First, convert all inputs to their "template" type
949 for (String key : inputs.keySet()) {
950 if (params.containsKey(key)) {
951 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
953 goldenInputs.put(key, value);
956 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key)
960 extraInputs.add(key);
964 if (!extraInputs.isEmpty()) {
965 logger.debug("Ignoring extra inputs: " + extraInputs);
968 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
969 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
970 for (String key : volumeGroupOutputs.keySet()) {
971 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
972 goldenInputs.put(key, volumeGroupOutputs.get(key));
977 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
978 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
979 for (String key : baseModuleOutputs.keySet()) {
980 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
981 goldenInputs.put(key, baseModuleOutputs.get(key));
986 // Last, add in values from the "environment" file.
987 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
989 // TODO: This may take a different form for Cloudify, but for now process it
990 // with Heat environment file syntax
991 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
992 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
994 if (mhee.getParameters() != null) {
995 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
996 // If this is a template input, copy to golden inputs
997 String envKey = envParam.getName();
998 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
999 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
1000 if (value != null) {
1001 goldenInputs.put(envKey, value);
1004 logger.debug("Failed to convert environment parameter " + envKey + "='" + envParam.getValue() + "' to " +
1005 params.get(envKey).getParamType());
1011 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
1014 // Check that required parameters have been supplied from any of the sources
1015 String missingParams = null;
1016 boolean checkRequiredParameters = true;
1018 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
1019 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1020 checkRequiredParameters = false;
1021 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
1022 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
1024 } catch (Exception e) {
1025 // No problem - default is true
1026 logger.debug("An exception occured trying to get property {}",
1027 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
1031 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1032 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1033 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1034 if (missingParams == null) {
1035 missingParams = parm.getParamName();
1037 missingParams += "," + parm.getParamName();
1042 if (missingParams != null) {
1043 if (checkRequiredParameters) {
1044 // Problem - missing one or more required parameters
1045 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1046 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, CLOUDIFY,
1047 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1048 logger.debug(error);
1049 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1052 "found missing parameters [" + missingParams + "] - but checkRequiredParameters is false -"
1053 + " will not block");
1056 logger.debug("No missing parameters found - ok to proceed");
1059 } // NOTE: END PARAMETER CHECKING
1061 // Ready to deploy the VF Module.
1062 // *First step - make sure the blueprint is loaded into Cloudify.
1063 String blueprintName = heatTemplate.getTemplateName();
1064 String blueprint = heatTemplate.getTemplateBody();
1065 String blueprintId = blueprintName;
1067 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
1068 if (blueprintId.endsWith(".yaml"))
1069 blueprintId = blueprintId.substring(0,blueprintId.lastIndexOf(".yaml"));
1072 if (! cloudifyUtils.isBlueprintLoaded (cloudSiteId, blueprintId)) {
1073 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
1075 Map<String,byte[]> blueprintFiles = new HashMap<String,byte[]>();
1077 blueprintFiles.put(blueprintName, blueprint.getBytes());
1079 // TODO: Implement nested blueprint logic based on Cloudify structures.
1080 // For now, just use the Heat structures.
1081 // The query returns a map of String->Object, where the map keys provide one layer of
1082 // indirection from the Heat template names. For this case, assume the map key matches
1083 // the nested blueprint name.
1084 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1085 if (nestedBlueprints != null) {
1086 for (HeatTemplate nestedBlueprint: nestedBlueprints) {
1087 blueprintFiles.put(nestedBlueprint.getTemplateName(), nestedBlueprint.getTemplateBody().getBytes());
1091 // TODO: Implement file artifact logic based on Cloudify structures.
1092 // For now, just use the Heat structures.
1093 List<HeatFiles> heatFiles = vf.getHeatFiles();
1094 if (heatFiles != null) {
1095 for (HeatFiles heatFile: heatFiles) {
1096 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1100 // Upload the blueprint package
1101 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1106 catch (MsoException me) {
1107 me.addContext("CreateVFModule");
1108 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1109 logger.error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudSiteId,
1110 tenantId, CLOUDIFY, ErrorCode.DataError.getValue(), "MsoException - uploadBlueprint", me);
1111 logger.debug(error);
1112 throw new VnfException(me);
1115 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1116 // because we already checked for those.
1117 long createDeploymentStarttime = System.currentTimeMillis ();
1119 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1120 // Go directly to Keystone until APIs could be updated to supply the name.
1121 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1122 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
1124 if (backout == null) {
1128 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment (cloudSiteId,
1134 heatTemplate.getTimeoutMinutes (),
1135 backout.booleanValue());
1137 } catch (MsoException me) {
1138 me.addContext ("CreateVFModule");
1139 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1141 .error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner, cloudSiteId,
1142 tenantId, CLOUDIFY, ErrorCode.DataError.getValue(), "MsoException - createDeployment",
1144 logger.debug(error);
1145 throw new VnfException (me);
1146 } catch (NullPointerException npe) {
1147 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + npe;
1149 .error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner, cloudSiteId,
1150 tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1151 "NullPointerException - createDeployment", npe);
1152 logger.debug(error);
1153 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1154 //npe.addContext ("CreateVNF");
1155 throw new VnfException ("NullPointerException during cloudify.createAndInstallDeployment");
1156 } catch (Exception e) {
1157 logger.debug("unhandled exception at cloudify.createAndInstallDeployment");
1158 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1160 } catch (Exception e) {
1161 logger.debug("unhandled exception in create VF");
1162 throw new VnfException("Exception during create VF " + e.getMessage());
1166 // Reach this point if create is successful.
1167 // Populate remaining rollback info and response parameters.
1168 vfRollback.setVnfCreated (true);
1169 vfRollback.setVnfId (cloudifyDeployment.getId());
1170 vnfId.value = cloudifyDeployment.getId();
1171 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
1173 rollback.value = vfRollback;
1175 logger.debug("VF Module successfully created", vfModuleName);
1179 public void deleteVfModule (String cloudSiteId,
1183 MsoRequest msoRequest,
1184 Holder <Map <String, String>> outputs) throws VnfException {
1185 logger.debug ("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1186 // Will capture execution time for metrics
1187 long startTime = System.currentTimeMillis ();
1189 // 1702 capture the output parameters on a delete
1190 // so we'll need to query first
1191 DeploymentInfo deployment = null;
1193 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1194 } catch (MsoException me) {
1195 // Failed to query the deployment. Convert to a generic VnfException
1196 me.addContext ("DeleteVFModule");
1197 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1198 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1199 tenantId, CLOUDIFY, "QueryDeployment", ErrorCode.DataError.getValue(),
1200 "Exception - QueryDeployment", me);
1201 logger.debug(error);
1202 throw new VnfException (me);
1204 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1205 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1207 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1208 // The possible outcomes of deleteStack are a StackInfo object with status
1209 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1211 long subStartTime = System.currentTimeMillis ();
1213 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1214 } catch (MsoException me) {
1215 me.addContext("DeleteVfModule");
1216 // Convert to a generic VnfException
1217 String error = "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1218 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1219 tenantId, "DeleteDeployment", "DeleteDeployment", ErrorCode.DataError.getValue(),
1220 "Exception - DeleteDeployment: " + me.getMessage());
1221 logger.debug(error);
1222 throw new VnfException(me);
1225 // On success, nothing is returned.
1229 // TODO: Should Update be supported for Cloudify? What would this look like?
1231 public void updateVfModule (String cloudSiteId,
1238 String volumeGroupHeatStackId,
1239 String baseVfHeatStackId,
1240 String vfModuleStackId,
1241 String modelCustomizationUuid,
1242 Map <String, Object> inputs,
1243 MsoRequest msoRequest,
1244 Holder <Map <String, String>> outputs,
1245 Holder <VnfRollback> rollback) throws VnfException
1247 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1248 logger.debug("Update VF Module command attempted but not supported");
1249 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);