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();
88 protected CloudConfig cloudConfig;
91 private VFModuleCustomizationRepository vfModuleCustomRepo;
94 private Environment environment;
97 protected MsoKeystoneUtils keystoneUtils;
100 protected MsoCloudifyUtils cloudifyUtils;
103 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
105 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
107 public MsoVnfCloudifyAdapterImpl() {
112 * Health Check web method. Does nothing but return to show the adapter is deployed.
115 public void healthCheck() {
116 logger.debug("Health check call in VNF Cloudify Adapter");
120 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
124 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
125 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
126 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
127 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
128 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
129 logger.debug("CreateVNF command attempted but not supported");
130 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
134 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
138 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
139 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
140 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
141 throws VnfException {
142 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
143 logger.debug("UpdateVNF command attempted but not supported");
144 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
148 * This is the "Query VNF" web service implementation.
150 * This really should be QueryVfModule, but nobody ever changed it.
152 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same as deployment name,
153 * since it assigned by the client when a deployment is created. Also, the input cloudSiteId is used only to
154 * identify which Cloudify instance to query, and the tenantId is ignored (since that really only applies for
157 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
158 * also be reflected back as its ID.
160 * @param cloudSiteId CLLI code of the cloud site in which to query
161 * @param cloudOwner cloud owner of the cloud site in which to query
162 * @param tenantId Openstack tenant identifier - ignored for Cloudify
163 * @param vnfName VNF Name (should match a deployment ID)
164 * @param msoRequest Request tracking information for logs
165 * @param vnfExists Flag reporting the result of the query
166 * @param vnfId Holder for output VNF ID
167 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
170 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
171 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
172 Holder<Map<String, String>> outputs) throws VnfException {
173 logger.debug("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
175 // Will capture execution time for metrics
176 long startTime = System.currentTimeMillis();
177 long subStartTime = System.currentTimeMillis();
179 DeploymentInfo deployment = null;
182 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
183 } catch (MsoCloudifyManagerNotFound e) {
184 // This site does not have a Cloudify Manager.
185 // This isn't an error, just means we won't find the VNF here.
187 } catch (MsoException me) {
188 // Failed to query the Deployment due to a cloudify exception.
189 // Convert to a generic VnfException
190 me.addContext("QueryVNF");
191 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
193 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
194 cloudSiteId, tenantId, CLOUDIFY, "QueryVNF", ErrorCode.DataError.getValue(),
195 "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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
285 cloudSiteId, 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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(),
651 vfModuleName, cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment",
652 ErrorCode.DataError.getValue(), "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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
672 cloudOwner, 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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
681 cloudOwner, 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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
691 cloudOwner, 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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
702 cloudOwner, 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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
725 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(volume)",
726 ErrorCode.DataError.getValue(), "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("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
737 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(volume)",
738 ErrorCode.BusinessProcesssError.getValue(),
739 "Create VFModule: Attached Volume Group DOES NOT EXIST");
741 throw new VnfException(error, MsoExceptionCategory.USERDATA);
743 logger.debug("Found nested volume group");
744 volumeGroupOutputs = volumeDeployment.getOutputs();
745 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
749 // If this is an Add-On Module, query the Base Module outputs
750 // Note: This will be performed whether or not the current request is for an
751 // Add-On Volume Group or Add-On VF Module
753 if (vf.getIsBase()) {
754 logger.debug("This is a BASE Module request");
755 vfRollback.setIsBase(true);
757 logger.debug("This is an Add-On Module request");
759 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
760 // Add-on Volume requests may or may not specify a base.
761 if (!isVolumeRequest && baseVfModuleId == null) {
762 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
765 if (baseVfModuleId != null) {
766 long subStartTime2 = System.currentTimeMillis();
767 DeploymentInfo baseDeployment = null;
769 baseDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, baseVfModuleId);
770 } catch (MsoException me) {
771 // Failed to query the Volume GroupDeployment due to a cloudify exception.
772 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
773 + cloudSiteId + "/" + tenantId + ": " + me;
774 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
775 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)",
776 ErrorCode.DataError.getValue(), "Exception - queryDeployment(Base)", me);
778 // Convert to a generic VnfException
779 me.addContext("CreateVFModule(QueryBase)");
780 throw new VnfException(me);
783 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
784 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in "
785 + cloudSiteId + "/" + tenantId + " USER ERROR";
786 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
787 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(Base)",
788 ErrorCode.BusinessProcesssError.getValue(),
789 "Create VFModule: Base " + "Module DOES NOT EXIST");
791 throw new VnfException(error, MsoExceptionCategory.USERDATA);
793 logger.debug("Found base module");
794 baseModuleOutputs = baseDeployment.getOutputs();
795 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
801 // Ready to deploy the new VNF
803 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
804 // In final implementation (post-POC), the template object would either be generic or there would
805 // be a separate DB Table/Object for Blueprints.
808 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
809 HeatTemplate heatTemplate = null;
810 HeatEnvironment heatEnvironment = null;
811 if (isVolumeRequest) {
812 heatTemplate = vf.getVolumeHeatTemplate();
813 heatEnvironment = vfmc.getVolumeHeatEnv();
815 heatTemplate = vf.getModuleHeatTemplate();
816 heatEnvironment = vfmc.getHeatEnvironment();
819 if (heatTemplate == null) {
820 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
821 + ", reqType=" + requestType;
822 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
823 vfModuleType, "OpenStack", ErrorCode.DataError.getValue(), error);
824 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
826 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
829 if (heatEnvironment == null) {
830 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
831 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
832 "OpenStack", ErrorCode.DataError.getValue(), error);
833 // Alarm on this error, configuration must be fixed
834 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
836 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
841 // All variables converted to their native object types
842 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
843 List<String> extraInputs = new ArrayList<String>();
845 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
846 // This whole section needs to be rewritten.
847 Boolean skipInputChecks = false;
849 if (skipInputChecks) {
850 goldenInputs = new HashMap<String, Object>();
851 for (String key : inputs.keySet()) {
852 goldenInputs.put(key, inputs.get(key));
855 // Build maps for the parameters (including aliases) to simplify checks
856 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
858 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
859 logger.debug("paramSet has {} entries", paramSet.size());
861 for (HeatTemplateParam htp : paramSet) {
862 params.put(htp.getParamName(), htp);
865 String alias = htp.getParamAlias();
866 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
867 params.put(alias, htp);
871 // First, convert all inputs to their "template" type
872 for (String key : inputs.keySet()) {
873 if (params.containsKey(key)) {
874 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
876 goldenInputs.put(key, value);
878 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
879 + params.get(key).getParamType());
882 extraInputs.add(key);
886 if (!extraInputs.isEmpty()) {
887 logger.debug("Ignoring extra inputs: " + extraInputs);
890 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
891 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
892 for (String key : volumeGroupOutputs.keySet()) {
893 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
894 goldenInputs.put(key, volumeGroupOutputs.get(key));
899 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
900 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
901 for (String key : baseModuleOutputs.keySet()) {
902 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
903 goldenInputs.put(key, baseModuleOutputs.get(key));
908 // Last, add in values from the "environment" file.
909 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
911 // TODO: This may take a different form for Cloudify, but for now process it
912 // with Heat environment file syntax
913 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
914 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
916 if (mhee.getParameters() != null) {
917 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
918 // If this is a template input, copy to golden inputs
919 String envKey = envParam.getName();
920 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
921 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
923 goldenInputs.put(envKey, value);
925 logger.debug("Failed to convert environment parameter " + envKey + "='"
926 + envParam.getValue() + "' to " + params.get(envKey).getParamType());
932 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
935 // Check that required parameters have been supplied from any of the sources
936 String missingParams = null;
937 boolean checkRequiredParameters = true;
939 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
940 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
941 checkRequiredParameters = false;
942 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
943 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
945 } catch (Exception e) {
946 // No problem - default is true
947 logger.debug("An exception occured trying to get property {}",
948 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
952 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
953 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
954 logger.debug("adding to missing parameters list: {}", parm.getParamName());
955 if (missingParams == null) {
956 missingParams = parm.getParamName();
958 missingParams += "," + parm.getParamName();
963 if (missingParams != null) {
964 if (checkRequiredParameters) {
965 // Problem - missing one or more required parameters
966 String error = "Create VFModule: Missing Required inputs: " + missingParams;
967 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, CLOUDIFY,
968 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
970 throw new VnfException(error, MsoExceptionCategory.USERDATA);
972 logger.debug("found missing parameters [" + missingParams
973 + "] - but checkRequiredParameters is false -" + " will not block");
976 logger.debug("No missing parameters found - ok to proceed");
979 } // NOTE: END PARAMETER CHECKING
981 // Ready to deploy the VF Module.
982 // *First step - make sure the blueprint is loaded into Cloudify.
983 String blueprintName = heatTemplate.getTemplateName();
984 String blueprint = heatTemplate.getTemplateBody();
985 String blueprintId = blueprintName;
987 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
988 if (blueprintId.endsWith(".yaml"))
989 blueprintId = blueprintId.substring(0, blueprintId.lastIndexOf(".yaml"));
992 if (!cloudifyUtils.isBlueprintLoaded(cloudSiteId, blueprintId)) {
993 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
995 Map<String, byte[]> blueprintFiles = new HashMap<String, byte[]>();
997 blueprintFiles.put(blueprintName, blueprint.getBytes());
999 // TODO: Implement nested blueprint logic based on Cloudify structures.
1000 // For now, just use the Heat structures.
1001 // The query returns a map of String->Object, where the map keys provide one layer of
1002 // indirection from the Heat template names. For this case, assume the map key matches
1003 // the nested blueprint name.
1004 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1005 if (nestedBlueprints != null) {
1006 for (HeatTemplate nestedBlueprint : nestedBlueprints) {
1007 blueprintFiles.put(nestedBlueprint.getTemplateName(),
1008 nestedBlueprint.getTemplateBody().getBytes());
1012 // TODO: Implement file artifact logic based on Cloudify structures.
1013 // For now, just use the Heat structures.
1014 List<HeatFiles> heatFiles = vf.getHeatFiles();
1015 if (heatFiles != null) {
1016 for (HeatFiles heatFile : heatFiles) {
1017 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1021 // Upload the blueprint package
1022 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1027 catch (MsoException me) {
1028 me.addContext("CreateVFModule");
1029 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1030 logger.error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1031 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1032 "MsoException - uploadBlueprint", me);
1033 logger.debug(error);
1034 throw new VnfException(me);
1037 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1038 // because we already checked for those.
1039 long createDeploymentStarttime = System.currentTimeMillis();
1041 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1042 // Go directly to Keystone until APIs could be updated to supply the name.
1043 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1044 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
1046 if (backout == null) {
1050 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment(cloudSiteId, tenantName, vfModuleName,
1051 blueprintId, goldenInputs, true, heatTemplate.getTimeoutMinutes(), backout.booleanValue());
1053 } catch (MsoException me) {
1054 me.addContext("CreateVFModule");
1055 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1056 + tenantId + ": " + me;
1057 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1058 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1059 "MsoException - createDeployment", me);
1060 logger.debug(error);
1061 throw new VnfException(me);
1062 } catch (NullPointerException npe) {
1063 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1064 + tenantId + ": " + npe;
1065 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1066 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1067 "NullPointerException - createDeployment", npe);
1068 logger.debug(error);
1069 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1070 // npe.addContext ("CreateVNF");
1071 throw new VnfException("NullPointerException during cloudify.createAndInstallDeployment");
1072 } catch (Exception e) {
1073 logger.debug("unhandled exception at cloudify.createAndInstallDeployment");
1074 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1076 } catch (Exception e) {
1077 logger.debug("unhandled exception in create VF");
1078 throw new VnfException("Exception during create VF " + e.getMessage());
1082 // Reach this point if create is successful.
1083 // Populate remaining rollback info and response parameters.
1084 vfRollback.setVnfCreated(true);
1085 vfRollback.setVnfId(cloudifyDeployment.getId());
1086 vnfId.value = cloudifyDeployment.getId();
1087 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
1089 rollback.value = vfRollback;
1091 logger.debug("VF Module successfully created", vfModuleName);
1095 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1096 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1097 logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1098 // Will capture execution time for metrics
1099 long startTime = System.currentTimeMillis();
1101 // 1702 capture the output parameters on a delete
1102 // so we'll need to query first
1103 DeploymentInfo deployment = null;
1105 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1106 } catch (MsoException me) {
1107 // Failed to query the deployment. Convert to a generic VnfException
1108 me.addContext("DeleteVFModule");
1109 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1110 + "/" + tenantId + ": " + me;
1111 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1112 cloudSiteId, tenantId, CLOUDIFY, "QueryDeployment", ErrorCode.DataError.getValue(),
1113 "Exception - QueryDeployment", me);
1114 logger.debug(error);
1115 throw new VnfException(me);
1117 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1119 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1121 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1122 // The possible outcomes of deleteStack are a StackInfo object with status
1123 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1125 long subStartTime = System.currentTimeMillis();
1127 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1128 } catch (MsoException me) {
1129 me.addContext("DeleteVfModule");
1130 // Convert to a generic VnfException
1132 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1133 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner,
1134 cloudSiteId, tenantId, "DeleteDeployment", "DeleteDeployment", ErrorCode.DataError.getValue(),
1135 "Exception - DeleteDeployment: " + me.getMessage());
1136 logger.debug(error);
1137 throw new VnfException(me);
1140 // On success, nothing is returned.
1144 // TODO: Should Update be supported for Cloudify? What would this look like?
1146 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1147 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1148 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1149 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1150 throws VnfException {
1151 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1152 logger.debug("Update VF Module command attempted but not supported");
1153 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);