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;
33 import javax.jws.WebService;
34 import javax.xml.ws.Holder;
35 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
36 import org.onap.so.adapters.vnf.exceptions.VnfException;
37 import org.onap.so.cloud.CloudConfig;
38 import org.onap.so.db.catalog.beans.CloudSite;
39 import org.onap.so.cloudify.beans.DeploymentInfo;
40 import org.onap.so.cloudify.beans.DeploymentStatus;
41 import org.onap.so.cloudify.exceptions.MsoCloudifyManagerNotFound;
42 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
43 import org.onap.so.db.catalog.beans.HeatEnvironment;
44 import org.onap.so.db.catalog.beans.HeatFiles;
45 import org.onap.so.db.catalog.beans.HeatTemplate;
46 import org.onap.so.db.catalog.beans.HeatTemplateParam;
47 import org.onap.so.db.catalog.beans.VfModule;
48 import org.onap.so.db.catalog.beans.VfModuleCustomization;
49 import org.onap.so.db.catalog.beans.VnfResource;
50 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
51 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
52 import org.onap.so.entity.MsoRequest;
53 import org.onap.so.logger.ErrorCode;
54 import org.onap.so.logger.MessageEnum;
55 import org.onap.so.openstack.beans.MsoTenant;
56 import org.onap.so.openstack.beans.VnfRollback;
57 import org.onap.so.openstack.beans.VnfStatus;
58 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
59 import org.onap.so.openstack.exceptions.MsoException;
60 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
61 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
62 import org.onap.so.openstack.utils.MsoHeatEnvironmentParameter;
63 import org.onap.so.openstack.utils.MsoKeystoneUtils;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66 import org.springframework.beans.factory.annotation.Autowired;
67 import org.springframework.core.env.Environment;
68 import org.springframework.stereotype.Component;
69 import com.fasterxml.jackson.core.JsonParseException;
70 import com.fasterxml.jackson.databind.JsonNode;
71 import com.fasterxml.jackson.databind.ObjectMapper;
72 import org.springframework.transaction.annotation.Transactional;
76 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
77 targetNamespace = "http://org.onap.so/vnf")
78 public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter {
80 private static Logger logger = LoggerFactory.getLogger(MsoVnfCloudifyAdapterImpl.class);
82 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
83 private static final String CLOUDIFY = "Cloudify";
85 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
86 private static final String BRACKETS = "{} {} {} {} {} {} {} {} {}";
89 protected CloudConfig cloudConfig;
92 private VFModuleCustomizationRepository vfModuleCustomRepo;
95 private Environment environment;
98 protected MsoKeystoneUtils keystoneUtils;
101 protected MsoCloudifyUtils cloudifyUtils;
104 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
106 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
108 public MsoVnfCloudifyAdapterImpl() {
113 * Health Check web method. Does nothing but return to show the adapter is deployed.
116 public void healthCheck() {
117 logger.debug("Health check call in VNF Cloudify Adapter");
121 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
125 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
126 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
127 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
128 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
129 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
130 logger.debug("CreateVNF command attempted but not supported");
131 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
135 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
139 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
140 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
141 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
142 throws VnfException {
143 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
144 logger.debug("UpdateVNF command attempted but not supported");
145 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
149 * This is the "Query VNF" web service implementation.
151 * This really should be QueryVfModule, but nobody ever changed it.
153 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same as deployment name,
154 * since it assigned by the client when a deployment is created. Also, the input cloudSiteId is used only to
155 * identify which Cloudify instance to query, and the tenantId is ignored (since that really only applies for
158 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
159 * also be reflected back as its ID.
161 * @param cloudSiteId CLLI code of the cloud site in which to query
162 * @param cloudOwner cloud owner of the cloud site in which to query
163 * @param tenantId Openstack tenant identifier - ignored for Cloudify
164 * @param vnfName VNF Name (should match a deployment ID)
165 * @param msoRequest Request tracking information for logs
166 * @param vnfExists Flag reporting the result of the query
167 * @param vnfId Holder for output VNF ID
168 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
171 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
172 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
173 Holder<Map<String, String>> outputs) throws VnfException {
174 logger.debug("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
176 // Will capture execution time for metrics
177 long startTime = System.currentTimeMillis();
178 long subStartTime = System.currentTimeMillis();
180 DeploymentInfo deployment = null;
183 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
184 } catch (MsoCloudifyManagerNotFound e) {
185 // This site does not have a Cloudify Manager.
186 // This isn't an error, just means we won't find the VNF here.
188 } catch (MsoException me) {
189 // Failed to query the Deployment due to a cloudify exception.
190 // Convert to a generic VnfException
191 me.addContext("QueryVNF");
192 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
194 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
195 CLOUDIFY, "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryDeployment", me);
197 throw new VnfException(me);
200 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
201 vnfExists.value = Boolean.TRUE;
202 status.value = deploymentStatusToVnfStatus(deployment);
203 vnfId.value = deployment.getId();
204 outputs.value = copyStringOutputs(deployment.getOutputs());
206 logger.debug("VNF {} found in Cloudify, ID = {}", vnfName, vnfId.value);
208 vnfExists.value = Boolean.FALSE;
209 status.value = VnfStatus.NOTFOUND;
211 outputs.value = new HashMap<String, String>(); // Return as an empty map
213 logger.debug("VNF {} not found", vnfName);
220 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
224 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
225 throws VnfException {
227 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
228 logger.debug("DeleteVNF command attempted but not supported");
229 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
233 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
234 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
235 * to undo the creation.
237 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
240 public void rollbackVnf(VnfRollback rollback) throws VnfException {
241 long startTime = System.currentTimeMillis();
242 // rollback may be null (e.g. if stack already existed when Create was called)
243 if (rollback == null) {
244 logger.info("{} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
248 // Don't rollback if nothing was done originally
249 if (!rollback.getVnfCreated()) {
253 // Get the elements of the VnfRollback object for easier access
254 String cloudSiteId = rollback.getCloudSiteId();
255 String cloudOwner = rollback.getCloudOwner();
256 String tenantId = rollback.getTenantId();
257 String vfModuleId = rollback.getVfModuleStackId();
259 logger.debug("Rolling Back VF Module {} in {}", vfModuleId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
261 DeploymentInfo deployment = null;
263 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
264 // The possible outcomes of deleteStack are a StackInfo object with status
265 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
267 long subStartTime = System.currentTimeMillis();
269 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
270 // Go directly to Keystone until APIs could be updated to supply the name.
271 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
272 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
274 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
276 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
277 logger.debug("Rolled back deployment: {}", deployment.getId());
278 } catch (MsoException me) {
279 // Failed to rollback the VNF due to a cloudify exception.
280 // Convert to a generic VnfException
281 me.addContext("RollbackVNF");
282 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
283 + tenantId + ": " + me;
284 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
285 tenantId, CLOUDIFY, "DeleteDeployment", ErrorCode.DataError.getValue(),
286 "Exception - DeleteDeployment", me);
288 throw new VnfException(me);
294 private VnfStatus deploymentStatusToVnfStatus(DeploymentInfo deployment) {
295 // Determine the status based on last action & status
296 // DeploymentInfo object should be enhanced to report a better status internally.
297 DeploymentStatus status = deployment.getStatus();
298 String lastAction = deployment.getLastAction();
300 if (status == null || lastAction == null) {
301 return VnfStatus.UNKNOWN;
302 } else if (status == DeploymentStatus.NOTFOUND) {
303 return VnfStatus.NOTFOUND;
304 } else if (status == DeploymentStatus.INSTALLED) {
305 return VnfStatus.ACTIVE;
306 } else if (status == DeploymentStatus.CREATED) {
307 // Should have an INACTIVE status for this case. Shouldn't really happen, but
308 // Install was never run, or Uninstall was done but deployment didn't get deleted.
309 return VnfStatus.UNKNOWN;
310 } else if (status == DeploymentStatus.FAILED) {
311 return VnfStatus.FAILED;
314 return VnfStatus.UNKNOWN;
317 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
318 Map<String, String> stringOutputs = new HashMap<String, String>();
319 for (String key : stackOutputs.keySet()) {
320 if (stackOutputs.get(key) instanceof String) {
321 stringOutputs.put(key, (String) stackOutputs.get(key));
322 } else if (stackOutputs.get(key) instanceof Integer) {
324 String str = "" + stackOutputs.get(key);
325 stringOutputs.put(key, str);
326 } catch (Exception e) {
327 logger.debug("Unable to add " + key + " to outputs");
329 } else if (stackOutputs.get(key) instanceof JsonNode) {
331 String str = this.convertNode((JsonNode) stackOutputs.get(key));
332 stringOutputs.put(key, str);
333 } catch (Exception e) {
334 logger.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
336 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
338 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
339 stringOutputs.put(key, str);
340 } catch (Exception e) {
341 logger.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
345 String str = stackOutputs.get(key).toString();
346 stringOutputs.put(key, str);
347 } catch (Exception e) {
348 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
352 return stringOutputs;
356 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
358 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
359 if (inputs == null) {
361 } else if (inputs.size() < 1) {
362 sb.append("\tEMPTY");
364 for (String str : inputs.keySet()) {
367 outputString = inputs.get(str).toString();
368 } catch (Exception e) {
369 outputString = "Unable to call toString() on the value for " + str;
371 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
374 logger.debug(sb.toString());
378 private void sendMapToDebug(Map<String, Object> inputs) {
380 StringBuilder sb = new StringBuilder("inputs:");
381 if (inputs == null) {
383 } else if (inputs.size() < 1) {
384 sb.append("\tEMPTY");
386 for (String str : inputs.keySet()) {
387 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
390 logger.debug(sb.toString());
394 private String convertNode(final JsonNode node) {
396 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
397 final String json = JSON_MAPPER.writeValueAsString(obj);
399 } catch (JsonParseException jpe) {
400 logger.debug("Error converting json to string " + jpe.getMessage());
401 } catch (Exception e) {
402 logger.debug("Error converting json to string " + e.getMessage());
404 return "[Error converting json to string]";
407 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
408 if (objectMap == null) {
411 Map<String, String> stringMap = new HashMap<String, String>();
412 for (String key : objectMap.keySet()) {
413 if (!stringMap.containsKey(key)) {
414 Object obj = objectMap.get(key);
415 if (obj instanceof String) {
416 stringMap.put(key, (String) objectMap.get(key));
417 } else if (obj instanceof JsonNode) {
418 // This is a bit of mess - but I think it's the least impacting
419 // let's convert it BACK to a string - then it will get converted back later
421 String str = this.convertNode((JsonNode) obj);
422 stringMap.put(key, str);
423 } catch (Exception e) {
424 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key);
425 // okay in this instance - only string values (fqdn) are expected to be needed
427 } else if (obj instanceof java.util.LinkedHashMap) {
428 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
430 String str = JSON_MAPPER.writeValueAsString(obj);
431 stringMap.put(key, str);
432 } catch (Exception e) {
433 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key);
435 } else if (obj instanceof Integer) {
437 String str = "" + obj;
438 stringMap.put(key, str);
439 } catch (Exception e) {
440 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key);
444 String str = obj.toString();
445 stringMap.put(key, str);
446 } catch (Exception e) {
448 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")");
458 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
459 * type in the specified cloud and tenant. The tenant must exist before this service is called.
461 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
462 * value of the 'failIfExists' parameter.
464 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
465 * error will be returned. Within the catalog, each VF Module references (among other things) a cloud template which
466 * is used to deploy the required artifacts (VMs, networks, etc.) to the cloud. In this adapter implementation, that
467 * artifact is expected to be a Cloudify blueprint.
469 * Depending on the blueprint, a variable set of input parameters will be defined, some of which are required. The
470 * caller is responsible to pass the necessary input data for the module or an error will be thrown.
472 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
473 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
474 * VF module is successfully created but the orchestration fails on a subsequent step.
476 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
477 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
478 * @param tenantId Openstack tenant identifier
479 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
480 * modelCustomizationUuid
481 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
482 * also captured by modelCustomizationUuid
483 * @param genericVnfId Generic VNF ID
484 * @param vfModuleName Name to be assigned to the new VF Module
485 * @param vfModuleId Id of the new VF Module
486 * @param requestType Indicates if this is a Volume Group or Module request
487 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
488 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
489 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
490 * @param inputs Map of key=value inputs for VNF stack creation
491 * @param failIfExists Flag whether already existing VNF should be considered
492 * @param backout Flag whether to suppress automatic backout (for testing)
493 * @param msoRequest Request tracking information for logs
494 * @param vnfId Holder for output VNF Cloudify Deployment ID
495 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
496 * @param rollback Holder for returning VnfRollback object
499 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
500 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
501 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
502 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
503 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
504 // Will capture execution time for metrics
505 long startTime = System.currentTimeMillis();
507 // Require a model customization ID. Every VF Module definition must have one.
508 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
509 logger.debug("Missing required input: modelCustomizationUuid");
510 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
511 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
512 "VF Module ModelCustomizationUuid", CLOUDIFY, ErrorCode.DataError.getValue(),
513 "Create VF Module: Missing required input: modelCustomizationUuid");
515 throw new VnfException(error, MsoExceptionCategory.USERDATA);
518 // Clean up some inputs to make comparisons easier
519 if (requestType == null)
522 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
523 volumeGroupId = null;
525 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
526 baseVfModuleId = null;
528 if (inputs == null) {
529 // Create an empty set of inputs
530 inputs = new HashMap<>();
531 logger.debug("inputs == null - setting to empty");
533 this.sendMapToDebug(inputs);
536 // Check if this is for a "Volume" module
537 boolean isVolumeRequest = false;
538 if (requestType.startsWith("VOLUME")) {
539 isVolumeRequest = true;
542 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
545 // Build a default rollback object (no actions performed)
546 VnfRollback vfRollback = new VnfRollback();
547 vfRollback.setCloudSiteId(cloudSiteId);
548 vfRollback.setCloudOwner(cloudOwner);
549 vfRollback.setTenantId(tenantId);
550 vfRollback.setMsoRequest(msoRequest);
551 vfRollback.setRequestType(requestType);
552 vfRollback.setIsBase(false); // Until we know better
553 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
554 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
555 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
556 vfRollback.setMode("CFY");
558 rollback.value = vfRollback; // Default rollback - no updates performed
560 // Get the VNF/VF Module definition from the Catalog DB first.
561 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
564 VnfResource vnfResource = null;
565 VfModuleCustomization vfmc = null;
568 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
571 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
572 + modelCustomizationUuid;
574 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
575 "VF Module " + "ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb",
576 ErrorCode.DataError.getValue(), error);
577 throw new VnfException(error, MsoExceptionCategory.USERDATA);
579 logger.debug("Found vfModuleCust entry " + vfmc.toString());
582 // Get the vfModule and vnfResource records
583 vf = vfmc.getVfModule();
584 vnfResource = vfmc.getVfModule().getVnfResources();
585 } catch (Exception e) {
587 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
588 throw new VnfException("Exception during create VF " + e.getMessage());
591 // Perform a version check against cloudSite
592 // Obtain the cloud site information where we will create the VF Module
593 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
594 if (!cloudSiteOp.isPresent()) {
595 throw new VnfException(new MsoCloudSiteNotFound(cloudSiteId));
597 CloudSite cloudSite = cloudSiteOp.get();
598 MavenLikeVersioning aicV = new MavenLikeVersioning();
599 aicV.setVersion(cloudSite.getCloudVersion());
601 String vnfMin = vnfResource.getAicVersionMin();
602 String vnfMax = vnfResource.getAicVersionMax();
604 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
605 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
607 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
608 + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax
609 + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
610 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
611 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
613 throw new VnfException(error, MsoExceptionCategory.USERDATA);
618 DeploymentInfo cloudifyDeployment = null;
620 // First, look up to see if the VF already exists.
622 long subStartTime1 = System.currentTimeMillis();
624 cloudifyDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vfModuleName);
625 } catch (MsoException me) {
626 // Failed to query the Deployment due to a cloudify exception.
627 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
628 + tenantId + ": " + me;
629 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudSiteId,
630 tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
631 "Exception - queryDeployment", me);
634 // Convert to a generic VnfException
635 me.addContext("CreateVFModule");
636 throw new VnfException(me);
639 // More precise handling/messaging if the Module already exists
640 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus() == DeploymentStatus.NOTFOUND)) {
641 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
642 DeploymentStatus status = cloudifyDeployment.getStatus();
643 logger.debug("Found Existing Deployment, status=" + status);
645 if (status == DeploymentStatus.INSTALLED) {
647 if (failIfExists != null && failIfExists) {
648 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
649 + cloudSiteId + "/" + tenantId;
650 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
651 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
652 "Deployment " + vfModuleName + " already exists");
654 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
655 cloudifyDeployment.getId());
657 // Found existing deployment and client has not requested "failIfExists".
658 // Populate the outputs from the existing deployment.
660 vnfId.value = cloudifyDeployment.getId();
661 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
665 // Check through various detailed error cases
666 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
667 // fail - it's in progress - return meaningful error
668 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
669 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
670 + "; please wait for it to complete, or fix manually.";
671 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
672 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
673 "Deployment " + vfModuleName + " already exists");
675 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
676 } else if (status == DeploymentStatus.FAILED) {
677 // fail - it exists and is in a FAILED state
678 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
679 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
680 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
681 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
682 "Deployment " + vfModuleName + " already " + "exists and is in FAILED state");
684 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
685 } else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
686 // fail - it exists and is in a UNKNOWN state
687 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
688 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
689 + "; requires manual intervention.";
690 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
691 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
692 "Deployment " + vfModuleName + " already " + "exists and is in " + status.toString()
695 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
697 // Unexpected, since all known status values have been tested for
698 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
699 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
700 + "; requires manual intervention.";
701 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
702 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
703 "Deployment " + vfModuleName + " already " + "exists and is in an unknown state");
705 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
710 // Collect outputs from Base Modules and Volume Modules
711 Map<String, Object> baseModuleOutputs = null;
712 Map<String, Object> volumeGroupOutputs = null;
714 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
715 if (volumeGroupId != null) {
716 long subStartTime2 = System.currentTimeMillis();
717 DeploymentInfo volumeDeployment = null;
719 volumeDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, volumeGroupId);
720 } catch (MsoException me) {
721 // Failed to query the Volume GroupDeployment due to a cloudify exception.
722 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
723 + cloudSiteId + "/" + tenantId + ": " + me;
724 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner, cloudSiteId,
725 tenantId, CLOUDIFY, "queryDeployment(volume)", ErrorCode.DataError.getValue(),
726 "Exception - queryDeployment(volume)", me);
728 // Convert to a generic VnfException
729 me.addContext("CreateVFModule(QueryVolume)");
730 throw new VnfException(me);
733 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
734 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
735 + cloudSiteId + "/" + tenantId + " USER ERROR";
736 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudSiteId, tenantId,
737 error, CLOUDIFY, "queryDeployment(volume)", ErrorCode.BusinessProcesssError.getValue(),
738 "Create VFModule: Attached Volume Group DOES NOT EXIST");
740 throw new VnfException(error, MsoExceptionCategory.USERDATA);
742 logger.debug("Found nested volume group");
743 volumeGroupOutputs = volumeDeployment.getOutputs();
744 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
748 // If this is an Add-On Module, query the Base Module outputs
749 // Note: This will be performed whether or not the current request is for an
750 // Add-On Volume Group or Add-On VF Module
752 if (vf.getIsBase()) {
753 logger.debug("This is a BASE Module request");
754 vfRollback.setIsBase(true);
756 logger.debug("This is an Add-On Module request");
758 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
759 // Add-on Volume requests may or may not specify a base.
760 if (!isVolumeRequest && baseVfModuleId == null) {
761 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
764 if (baseVfModuleId != null) {
765 long subStartTime2 = System.currentTimeMillis();
766 DeploymentInfo baseDeployment = null;
768 baseDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, baseVfModuleId);
769 } catch (MsoException me) {
770 // Failed to query the Volume GroupDeployment due to a cloudify exception.
771 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
772 + cloudSiteId + "/" + tenantId + ": " + me;
773 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudOwner,
774 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)", ErrorCode.DataError.getValue(),
775 "Exception - queryDeployment(Base)", me);
777 // Convert to a generic VnfException
778 me.addContext("CreateVFModule(QueryBase)");
779 throw new VnfException(me);
782 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
783 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in "
784 + cloudSiteId + "/" + tenantId + " USER ERROR";
785 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudSiteId,
786 tenantId, error, CLOUDIFY, "queryDeployment(Base)",
787 ErrorCode.BusinessProcesssError.getValue(),
788 "Create VFModule: Base " + "Module DOES NOT EXIST");
790 throw new VnfException(error, MsoExceptionCategory.USERDATA);
792 logger.debug("Found base module");
793 baseModuleOutputs = baseDeployment.getOutputs();
794 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
800 // Ready to deploy the new VNF
802 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
803 // In final implementation (post-POC), the template object would either be generic or there would
804 // be a separate DB Table/Object for Blueprints.
807 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
808 HeatTemplate heatTemplate = null;
809 HeatEnvironment heatEnvironment = null;
810 if (isVolumeRequest) {
811 heatTemplate = vf.getVolumeHeatTemplate();
812 heatEnvironment = vfmc.getVolumeHeatEnv();
814 heatTemplate = vf.getModuleHeatTemplate();
815 heatEnvironment = vfmc.getHeatEnvironment();
818 if (heatTemplate == null) {
819 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
820 + ", reqType=" + requestType;
821 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
822 vfModuleType, "OpenStack", ErrorCode.DataError.getValue(), error);
823 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
825 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
828 if (heatEnvironment == null) {
829 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
830 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
831 "OpenStack", ErrorCode.DataError.getValue(), error);
832 // Alarm on this error, configuration must be fixed
833 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
835 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
840 // All variables converted to their native object types
841 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
842 List<String> extraInputs = new ArrayList<String>();
844 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
845 // This whole section needs to be rewritten.
846 Boolean skipInputChecks = false;
848 if (skipInputChecks) {
849 goldenInputs = new HashMap<String, Object>();
850 for (String key : inputs.keySet()) {
851 goldenInputs.put(key, inputs.get(key));
854 // Build maps for the parameters (including aliases) to simplify checks
855 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
857 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
858 logger.debug("paramSet has {} entries", paramSet.size());
860 for (HeatTemplateParam htp : paramSet) {
861 params.put(htp.getParamName(), htp);
864 String alias = htp.getParamAlias();
865 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
866 params.put(alias, htp);
870 // First, convert all inputs to their "template" type
871 for (String key : inputs.keySet()) {
872 if (params.containsKey(key)) {
873 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
875 goldenInputs.put(key, value);
877 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
878 + params.get(key).getParamType());
881 extraInputs.add(key);
885 if (!extraInputs.isEmpty()) {
886 logger.debug("Ignoring extra inputs: " + extraInputs);
889 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
890 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
891 for (String key : volumeGroupOutputs.keySet()) {
892 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
893 goldenInputs.put(key, volumeGroupOutputs.get(key));
898 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
899 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
900 for (String key : baseModuleOutputs.keySet()) {
901 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
902 goldenInputs.put(key, baseModuleOutputs.get(key));
907 // Last, add in values from the "environment" file.
908 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
910 // TODO: This may take a different form for Cloudify, but for now process it
911 // with Heat environment file syntax
912 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
913 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
915 if (mhee.getParameters() != null) {
916 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
917 // If this is a template input, copy to golden inputs
918 String envKey = envParam.getName();
919 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
920 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
922 goldenInputs.put(envKey, value);
924 logger.debug("Failed to convert environment parameter " + envKey + "='"
925 + envParam.getValue() + "' to " + params.get(envKey).getParamType());
931 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
934 // Check that required parameters have been supplied from any of the sources
935 String missingParams = null;
936 boolean checkRequiredParameters = true;
938 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
939 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
940 checkRequiredParameters = false;
941 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
942 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
944 } catch (Exception e) {
945 // No problem - default is true
946 logger.debug("An exception occured trying to get property {}",
947 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
951 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
952 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
953 logger.debug("adding to missing parameters list: {}", parm.getParamName());
954 if (missingParams == null) {
955 missingParams = parm.getParamName();
957 missingParams += "," + parm.getParamName();
962 if (missingParams != null) {
963 if (checkRequiredParameters) {
964 // Problem - missing one or more required parameters
965 String error = "Create VFModule: Missing Required inputs: " + missingParams;
966 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, CLOUDIFY,
967 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
969 throw new VnfException(error, MsoExceptionCategory.USERDATA);
971 logger.debug("found missing parameters [" + missingParams
972 + "] - but checkRequiredParameters is false -" + " will not block");
975 logger.debug("No missing parameters found - ok to proceed");
978 } // NOTE: END PARAMETER CHECKING
980 // Ready to deploy the VF Module.
981 // *First step - make sure the blueprint is loaded into Cloudify.
982 String blueprintName = heatTemplate.getTemplateName();
983 String blueprint = heatTemplate.getTemplateBody();
984 String blueprintId = blueprintName;
986 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
987 if (blueprintId.endsWith(".yaml"))
988 blueprintId = blueprintId.substring(0, blueprintId.lastIndexOf(".yaml"));
991 if (!cloudifyUtils.isBlueprintLoaded(cloudSiteId, blueprintId)) {
992 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
994 Map<String, byte[]> blueprintFiles = new HashMap<String, byte[]>();
996 blueprintFiles.put(blueprintName, blueprint.getBytes());
998 // TODO: Implement nested blueprint logic based on Cloudify structures.
999 // For now, just use the Heat structures.
1000 // The query returns a map of String->Object, where the map keys provide one layer of
1001 // indirection from the Heat template names. For this case, assume the map key matches
1002 // the nested blueprint name.
1003 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1004 if (nestedBlueprints != null) {
1005 for (HeatTemplate nestedBlueprint : nestedBlueprints) {
1006 blueprintFiles.put(nestedBlueprint.getTemplateName(),
1007 nestedBlueprint.getTemplateBody().getBytes());
1011 // TODO: Implement file artifact logic based on Cloudify structures.
1012 // For now, just use the Heat structures.
1013 List<HeatFiles> heatFiles = vf.getHeatFiles();
1014 if (heatFiles != null) {
1015 for (HeatFiles heatFile : heatFiles) {
1016 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1020 // Upload the blueprint package
1021 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1026 catch (MsoException me) {
1027 me.addContext("CreateVFModule");
1028 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1029 logger.error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1030 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1031 "MsoException - uploadBlueprint", me);
1032 logger.debug(error);
1033 throw new VnfException(me);
1036 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1037 // because we already checked for those.
1038 long createDeploymentStarttime = System.currentTimeMillis();
1040 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1041 // Go directly to Keystone until APIs could be updated to supply the name.
1042 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1043 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
1045 if (backout == null) {
1049 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment(cloudSiteId, tenantName, vfModuleName,
1050 blueprintId, goldenInputs, true, heatTemplate.getTimeoutMinutes(), backout.booleanValue());
1052 } catch (MsoException me) {
1053 me.addContext("CreateVFModule");
1054 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1055 + tenantId + ": " + me;
1056 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1057 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1058 "MsoException - createDeployment", me);
1059 logger.debug(error);
1060 throw new VnfException(me);
1061 } catch (NullPointerException npe) {
1062 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1063 + tenantId + ": " + npe;
1064 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1065 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1066 "NullPointerException - createDeployment", npe);
1067 logger.debug(error);
1068 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1069 // npe.addContext ("CreateVNF");
1070 throw new VnfException("NullPointerException during cloudify.createAndInstallDeployment");
1071 } catch (Exception e) {
1072 logger.debug("unhandled exception at cloudify.createAndInstallDeployment");
1073 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1075 } catch (Exception e) {
1076 logger.debug("unhandled exception in create VF");
1077 throw new VnfException("Exception during create VF " + e.getMessage());
1081 // Reach this point if create is successful.
1082 // Populate remaining rollback info and response parameters.
1083 vfRollback.setVnfCreated(true);
1084 vfRollback.setVnfId(cloudifyDeployment.getId());
1085 vnfId.value = cloudifyDeployment.getId();
1086 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
1088 rollback.value = vfRollback;
1090 logger.debug("VF Module successfully created", vfModuleName);
1094 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1095 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1096 logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1097 // Will capture execution time for metrics
1098 long startTime = System.currentTimeMillis();
1100 // 1702 capture the output parameters on a delete
1101 // so we'll need to query first
1102 DeploymentInfo deployment = null;
1104 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1105 } catch (MsoException me) {
1106 // Failed to query the deployment. Convert to a generic VnfException
1107 me.addContext("DeleteVFModule");
1108 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1109 + "/" + tenantId + ": " + me;
1110 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1111 CLOUDIFY, "QueryDeployment", ErrorCode.DataError.getValue(), "Exception - QueryDeployment", me);
1112 logger.debug(error);
1113 throw new VnfException(me);
1115 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1117 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1119 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1120 // The possible outcomes of deleteStack are a StackInfo object with status
1121 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1123 long subStartTime = System.currentTimeMillis();
1125 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1126 } catch (MsoException me) {
1127 me.addContext("DeleteVfModule");
1128 // Convert to a generic VnfException
1130 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1131 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1132 "DeleteDeployment", "DeleteDeployment", ErrorCode.DataError.getValue(),
1133 "Exception - DeleteDeployment: " + me.getMessage());
1134 logger.debug(error);
1135 throw new VnfException(me);
1138 // On success, nothing is returned.
1142 // TODO: Should Update be supported for Cloudify? What would this look like?
1144 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1145 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1146 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1147 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1148 throws VnfException {
1149 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1150 logger.debug("Update VF Module command attempted but not supported");
1151 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);