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 = "{} {} {} {} {} {} {} {} {}";
87 private static final String OPENSTACK = "OpenStack";
90 protected CloudConfig cloudConfig;
93 private VFModuleCustomizationRepository vfModuleCustomRepo;
96 private Environment environment;
99 protected MsoKeystoneUtils keystoneUtils;
102 protected MsoCloudifyUtils cloudifyUtils;
105 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
107 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
109 public MsoVnfCloudifyAdapterImpl() {
114 * Health Check web method. Does nothing but return to show the adapter is deployed.
117 public void healthCheck() {
118 logger.debug("Health check call in VNF Cloudify Adapter");
122 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
126 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
127 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
128 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
129 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
130 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
131 logger.debug("CreateVNF command attempted but not supported");
132 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
136 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
140 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
141 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
142 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
143 throws VnfException {
144 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
145 logger.debug("UpdateVNF command attempted but not supported");
146 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
150 * This is the "Query VNF" web service implementation.
152 * This really should be QueryVfModule, but nobody ever changed it.
154 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same as deployment name,
155 * since it assigned by the client when a deployment is created. Also, the input cloudSiteId is used only to
156 * identify which Cloudify instance to query, and the tenantId is ignored (since that really only applies for
159 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
160 * also be reflected back as its ID.
162 * @param cloudSiteId CLLI code of the cloud site in which to query
163 * @param cloudOwner cloud owner of the cloud site in which to query
164 * @param tenantId Openstack tenant identifier - ignored for Cloudify
165 * @param vnfName VNF Name (should match a deployment ID)
166 * @param msoRequest Request tracking information for logs
167 * @param vnfExists Flag reporting the result of the query
168 * @param vnfId Holder for output VNF ID
169 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
172 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
173 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
174 Holder<Map<String, String>> outputs) throws VnfException {
175 logger.debug("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
177 // Will capture execution time for metrics
178 long startTime = System.currentTimeMillis();
179 long subStartTime = System.currentTimeMillis();
181 DeploymentInfo deployment = null;
184 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
185 } catch (MsoCloudifyManagerNotFound e) {
186 // This site does not have a Cloudify Manager.
187 // This isn't an error, just means we won't find the VNF here.
189 } catch (MsoException me) {
190 // Failed to query the Deployment due to a cloudify exception.
191 // Convert to a generic VnfException
192 me.addContext("QueryVNF");
193 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
195 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
196 CLOUDIFY, "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryDeployment", me);
198 throw new VnfException(me);
201 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
202 vnfExists.value = Boolean.TRUE;
203 status.value = deploymentStatusToVnfStatus(deployment);
204 vnfId.value = deployment.getId();
205 outputs.value = copyStringOutputs(deployment.getOutputs());
207 logger.debug("VNF {} found in Cloudify, ID = {}", vnfName, vnfId.value);
209 vnfExists.value = Boolean.FALSE;
210 status.value = VnfStatus.NOTFOUND;
212 outputs.value = new HashMap<String, String>(); // Return as an empty map
214 logger.debug("VNF {} not found", vnfName);
221 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
225 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
226 throws VnfException {
228 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
229 logger.debug("DeleteVNF command attempted but not supported");
230 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
234 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
235 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
236 * to undo the creation.
238 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
241 public void rollbackVnf(VnfRollback rollback) throws VnfException {
242 long startTime = System.currentTimeMillis();
243 // rollback may be null (e.g. if stack already existed when Create was called)
244 if (rollback == null) {
245 logger.info("{} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), OPENSTACK, "rollbackVnf");
249 // Don't rollback if nothing was done originally
250 if (!rollback.getVnfCreated()) {
254 // Get the elements of the VnfRollback object for easier access
255 String cloudSiteId = rollback.getCloudSiteId();
256 String cloudOwner = rollback.getCloudOwner();
257 String tenantId = rollback.getTenantId();
258 String vfModuleId = rollback.getVfModuleStackId();
260 logger.debug("Rolling Back VF Module {} in {}", vfModuleId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
262 DeploymentInfo deployment = null;
264 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
265 // The possible outcomes of deleteStack are a StackInfo object with status
266 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
268 long subStartTime = System.currentTimeMillis();
270 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
271 // Go directly to Keystone until APIs could be updated to supply the name.
272 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
273 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
275 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
277 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
278 logger.debug("Rolled back deployment: {}", deployment.getId());
279 } catch (MsoException me) {
280 // Failed to rollback the VNF due to a cloudify exception.
281 // Convert to a generic VnfException
282 me.addContext("RollbackVNF");
283 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
284 + tenantId + ": " + me;
285 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
286 tenantId, CLOUDIFY, "DeleteDeployment", ErrorCode.DataError.getValue(),
287 "Exception - DeleteDeployment", me);
289 throw new VnfException(me);
295 private VnfStatus deploymentStatusToVnfStatus(DeploymentInfo deployment) {
296 // Determine the status based on last action & status
297 // DeploymentInfo object should be enhanced to report a better status internally.
298 DeploymentStatus status = deployment.getStatus();
299 String lastAction = deployment.getLastAction();
301 if (status == null || lastAction == null) {
302 return VnfStatus.UNKNOWN;
303 } else if (status == DeploymentStatus.NOTFOUND) {
304 return VnfStatus.NOTFOUND;
305 } else if (status == DeploymentStatus.INSTALLED) {
306 return VnfStatus.ACTIVE;
307 } else if (status == DeploymentStatus.CREATED) {
308 // Should have an INACTIVE status for this case. Shouldn't really happen, but
309 // Install was never run, or Uninstall was done but deployment didn't get deleted.
310 return VnfStatus.UNKNOWN;
311 } else if (status == DeploymentStatus.FAILED) {
312 return VnfStatus.FAILED;
315 return VnfStatus.UNKNOWN;
318 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
319 Map<String, String> stringOutputs = new HashMap<String, String>();
320 for (String key : stackOutputs.keySet()) {
321 if (stackOutputs.get(key) instanceof String) {
322 stringOutputs.put(key, (String) stackOutputs.get(key));
323 } else if (stackOutputs.get(key) instanceof Integer) {
325 String str = "" + stackOutputs.get(key);
326 stringOutputs.put(key, str);
327 } catch (Exception e) {
328 logger.debug("Unable to add " + key + " to outputs");
330 } else if (stackOutputs.get(key) instanceof JsonNode) {
332 String str = this.convertNode((JsonNode) stackOutputs.get(key));
333 stringOutputs.put(key, str);
334 } catch (Exception e) {
335 logger.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
337 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
339 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
340 stringOutputs.put(key, str);
341 } catch (Exception e) {
342 logger.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
346 String str = stackOutputs.get(key).toString();
347 stringOutputs.put(key, str);
348 } catch (Exception e) {
349 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
353 return stringOutputs;
357 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
359 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
360 if (inputs == null) {
362 } else if (inputs.size() < 1) {
363 sb.append("\tEMPTY");
365 for (String str : inputs.keySet()) {
368 outputString = inputs.get(str).toString();
369 } catch (Exception e) {
370 outputString = "Unable to call toString() on the value for " + str;
372 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
375 logger.debug(sb.toString());
379 private void sendMapToDebug(Map<String, Object> inputs) {
381 StringBuilder sb = new StringBuilder("inputs:");
382 if (inputs == null) {
384 } else if (inputs.size() < 1) {
385 sb.append("\tEMPTY");
387 for (String str : inputs.keySet()) {
388 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
391 logger.debug(sb.toString());
395 private String convertNode(final JsonNode node) {
397 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
398 final String json = JSON_MAPPER.writeValueAsString(obj);
400 } catch (JsonParseException jpe) {
401 logger.debug("Error converting json to string " + jpe.getMessage());
402 } catch (Exception e) {
403 logger.debug("Error converting json to string " + e.getMessage());
405 return "[Error converting json to string]";
408 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
409 if (objectMap == null) {
412 Map<String, String> stringMap = new HashMap<String, String>();
413 for (String key : objectMap.keySet()) {
414 if (!stringMap.containsKey(key)) {
415 Object obj = objectMap.get(key);
416 if (obj instanceof String) {
417 stringMap.put(key, (String) objectMap.get(key));
418 } else if (obj instanceof JsonNode) {
419 // This is a bit of mess - but I think it's the least impacting
420 // let's convert it BACK to a string - then it will get converted back later
422 String str = this.convertNode((JsonNode) obj);
423 stringMap.put(key, str);
424 } catch (Exception e) {
425 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key);
426 // okay in this instance - only string values (fqdn) are expected to be needed
428 } else if (obj instanceof java.util.LinkedHashMap) {
429 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
431 String str = JSON_MAPPER.writeValueAsString(obj);
432 stringMap.put(key, str);
433 } catch (Exception e) {
434 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key);
436 } else if (obj instanceof Integer) {
438 String str = "" + obj;
439 stringMap.put(key, str);
440 } catch (Exception e) {
441 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key);
445 String str = obj.toString();
446 stringMap.put(key, str);
447 } catch (Exception e) {
449 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")");
459 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
460 * type in the specified cloud and tenant. The tenant must exist before this service is called.
462 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
463 * value of the 'failIfExists' parameter.
465 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
466 * error will be returned. Within the catalog, each VF Module references (among other things) a cloud template which
467 * is used to deploy the required artifacts (VMs, networks, etc.) to the cloud. In this adapter implementation, that
468 * artifact is expected to be a Cloudify blueprint.
470 * Depending on the blueprint, a variable set of input parameters will be defined, some of which are required. The
471 * caller is responsible to pass the necessary input data for the module or an error will be thrown.
473 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
474 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
475 * VF module is successfully created but the orchestration fails on a subsequent step.
477 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
478 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
479 * @param tenantId Openstack tenant identifier
480 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
481 * modelCustomizationUuid
482 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
483 * also captured by modelCustomizationUuid
484 * @param genericVnfId Generic VNF ID
485 * @param vfModuleName Name to be assigned to the new VF Module
486 * @param vfModuleId Id of the new VF Module
487 * @param requestType Indicates if this is a Volume Group or Module request
488 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
489 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
490 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
491 * @param inputs Map of key=value inputs for VNF stack creation
492 * @param failIfExists Flag whether already existing VNF should be considered
493 * @param backout Flag whether to suppress automatic backout (for testing)
494 * @param msoRequest Request tracking information for logs
495 * @param vnfId Holder for output VNF Cloudify Deployment ID
496 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
497 * @param rollback Holder for returning VnfRollback object
500 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
501 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
502 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
503 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
504 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
505 // Will capture execution time for metrics
506 long startTime = System.currentTimeMillis();
508 // Require a model customization ID. Every VF Module definition must have one.
509 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
510 logger.debug("Missing required input: modelCustomizationUuid");
511 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
512 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
513 "VF Module ModelCustomizationUuid", CLOUDIFY, ErrorCode.DataError.getValue(),
514 "Create VF Module: Missing required input: modelCustomizationUuid");
516 throw new VnfException(error, MsoExceptionCategory.USERDATA);
519 // Clean up some inputs to make comparisons easier
520 if (requestType == null)
523 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
524 volumeGroupId = null;
526 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
527 baseVfModuleId = null;
529 if (inputs == null) {
530 // Create an empty set of inputs
531 inputs = new HashMap<>();
532 logger.debug("inputs == null - setting to empty");
534 this.sendMapToDebug(inputs);
537 // Check if this is for a "Volume" module
538 boolean isVolumeRequest = false;
539 if (requestType.startsWith("VOLUME")) {
540 isVolumeRequest = true;
543 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
546 // Build a default rollback object (no actions performed)
547 VnfRollback vfRollback = new VnfRollback();
548 vfRollback.setCloudSiteId(cloudSiteId);
549 vfRollback.setCloudOwner(cloudOwner);
550 vfRollback.setTenantId(tenantId);
551 vfRollback.setMsoRequest(msoRequest);
552 vfRollback.setRequestType(requestType);
553 vfRollback.setIsBase(false); // Until we know better
554 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
555 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
556 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
557 vfRollback.setMode("CFY");
559 rollback.value = vfRollback; // Default rollback - no updates performed
561 // Get the VNF/VF Module definition from the Catalog DB first.
562 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
565 VnfResource vnfResource = null;
566 VfModuleCustomization vfmc = null;
569 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
572 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
573 + modelCustomizationUuid;
575 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
576 "VF Module " + "ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb",
577 ErrorCode.DataError.getValue(), error);
578 throw new VnfException(error, MsoExceptionCategory.USERDATA);
580 logger.debug("Found vfModuleCust entry " + vfmc.toString());
583 // Get the vfModule and vnfResource records
584 vf = vfmc.getVfModule();
585 vnfResource = vfmc.getVfModule().getVnfResources();
586 } catch (Exception e) {
588 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
589 throw new VnfException("Exception during create VF " + e.getMessage());
592 // Perform a version check against cloudSite
593 // Obtain the cloud site information where we will create the VF Module
594 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
595 if (!cloudSiteOp.isPresent()) {
596 throw new VnfException(new MsoCloudSiteNotFound(cloudSiteId));
598 CloudSite cloudSite = cloudSiteOp.get();
599 MavenLikeVersioning aicV = new MavenLikeVersioning();
600 aicV.setVersion(cloudSite.getCloudVersion());
602 String vnfMin = vnfResource.getAicVersionMin();
603 String vnfMax = vnfResource.getAicVersionMax();
605 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
606 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
608 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
609 + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax
610 + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
611 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK,
612 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
614 throw new VnfException(error, MsoExceptionCategory.USERDATA);
619 DeploymentInfo cloudifyDeployment = null;
621 // First, look up to see if the VF already exists.
623 long subStartTime1 = System.currentTimeMillis();
625 cloudifyDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vfModuleName);
626 } catch (MsoException me) {
627 // Failed to query the Deployment due to a cloudify exception.
628 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
629 + tenantId + ": " + me;
630 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudSiteId,
631 tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
632 "Exception - queryDeployment", me);
635 // Convert to a generic VnfException
636 me.addContext("CreateVFModule");
637 throw new VnfException(me);
640 // More precise handling/messaging if the Module already exists
641 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus() == DeploymentStatus.NOTFOUND)) {
642 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
643 DeploymentStatus status = cloudifyDeployment.getStatus();
644 logger.debug("Found Existing Deployment, status=" + status);
646 if (status == DeploymentStatus.INSTALLED) {
648 if (failIfExists != null && failIfExists) {
649 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
650 + cloudSiteId + "/" + tenantId;
651 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
652 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
653 "Deployment " + vfModuleName + " already exists");
655 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
656 cloudifyDeployment.getId());
658 // Found existing deployment and client has not requested "failIfExists".
659 // Populate the outputs from the existing deployment.
661 vnfId.value = cloudifyDeployment.getId();
662 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
666 // Check through various detailed error cases
667 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
668 // fail - it's in progress - return meaningful error
669 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
670 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
671 + "; please wait for it to complete, or fix manually.";
672 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
673 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
674 "Deployment " + vfModuleName + " already exists");
676 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
677 } else if (status == DeploymentStatus.FAILED) {
678 // fail - it exists and is in a FAILED state
679 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
680 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
681 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
682 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
683 "Deployment " + vfModuleName + " already " + "exists and is in FAILED state");
685 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
686 } else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
687 // fail - it exists and is in a UNKNOWN state
688 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
689 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
690 + "; requires manual intervention.";
691 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
692 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
693 "Deployment " + vfModuleName + " already " + "exists and is in " + status.toString()
696 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
698 // Unexpected, since all known status values have been tested for
699 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
700 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
701 + "; requires manual intervention.";
702 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
703 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
704 "Deployment " + vfModuleName + " already " + "exists and is in an unknown state");
706 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
711 // Collect outputs from Base Modules and Volume Modules
712 Map<String, Object> baseModuleOutputs = null;
713 Map<String, Object> volumeGroupOutputs = null;
715 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
716 if (volumeGroupId != null) {
717 long subStartTime2 = System.currentTimeMillis();
718 DeploymentInfo volumeDeployment = null;
720 volumeDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, volumeGroupId);
721 } catch (MsoException me) {
722 // Failed to query the Volume GroupDeployment due to a cloudify exception.
723 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
724 + cloudSiteId + "/" + tenantId + ": " + me;
725 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner, cloudSiteId,
726 tenantId, CLOUDIFY, "queryDeployment(volume)", ErrorCode.DataError.getValue(),
727 "Exception - queryDeployment(volume)", me);
729 // Convert to a generic VnfException
730 me.addContext("CreateVFModule(QueryVolume)");
731 throw new VnfException(me);
734 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
735 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
736 + cloudSiteId + "/" + tenantId + " USER ERROR";
737 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudSiteId, tenantId,
738 error, CLOUDIFY, "queryDeployment(volume)", 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(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudOwner,
775 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)", ErrorCode.DataError.getValue(),
776 "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(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudSiteId,
787 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 + ", modelCustomizationUuid=" + modelCustomizationUuid + ", vfModuleUuid=" + vf.getModelUUID()
822 + ", reqType=" + requestType;
823 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
824 vfModuleType, OPENSTACK, ErrorCode.DataError.getValue(), error);
825 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
827 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
830 if (heatEnvironment == null) {
831 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + ", modelCustomizationUuid="
832 + modelCustomizationUuid + ", vfModuleUuid=" + vf.getModelUUID() + ", reqType=" + requestType;
833 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
834 OPENSTACK, ErrorCode.DataError.getValue(), error);
835 // Alarm on this error, configuration must be fixed
836 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
838 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
843 // All variables converted to their native object types
844 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
845 List<String> extraInputs = new ArrayList<String>();
847 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
848 // This whole section needs to be rewritten.
849 Boolean skipInputChecks = false;
851 if (skipInputChecks) {
852 goldenInputs = new HashMap<String, Object>();
853 for (String key : inputs.keySet()) {
854 goldenInputs.put(key, inputs.get(key));
857 // Build maps for the parameters (including aliases) to simplify checks
858 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
860 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
861 logger.debug("paramSet has {} entries", paramSet.size());
863 for (HeatTemplateParam htp : paramSet) {
864 params.put(htp.getParamName(), htp);
867 String alias = htp.getParamAlias();
868 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
869 params.put(alias, htp);
873 // First, convert all inputs to their "template" type
874 for (String key : inputs.keySet()) {
875 if (params.containsKey(key)) {
876 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
878 goldenInputs.put(key, value);
880 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
881 + params.get(key).getParamType());
884 extraInputs.add(key);
888 if (!extraInputs.isEmpty()) {
889 logger.debug("Ignoring extra inputs: " + extraInputs);
892 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
893 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
894 for (String key : volumeGroupOutputs.keySet()) {
895 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
896 goldenInputs.put(key, volumeGroupOutputs.get(key));
901 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
902 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
903 for (String key : baseModuleOutputs.keySet()) {
904 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
905 goldenInputs.put(key, baseModuleOutputs.get(key));
910 // Last, add in values from the "environment" file.
911 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
913 // TODO: This may take a different form for Cloudify, but for now process it
914 // with Heat environment file syntax
915 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
916 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
918 if (mhee.getParameters() != null) {
919 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
920 // If this is a template input, copy to golden inputs
921 String envKey = envParam.getName();
922 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
923 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
925 goldenInputs.put(envKey, value);
927 logger.debug("Failed to convert environment parameter " + envKey + "='"
928 + envParam.getValue() + "' to " + params.get(envKey).getParamType());
934 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
937 // Check that required parameters have been supplied from any of the sources
938 String missingParams = null;
939 boolean checkRequiredParameters = true;
941 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
942 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
943 checkRequiredParameters = false;
944 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
945 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
947 } catch (Exception e) {
948 // No problem - default is true
949 logger.debug("An exception occured trying to get property {}",
950 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
954 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
955 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
956 logger.debug("adding to missing parameters list: {}", parm.getParamName());
957 if (missingParams == null) {
958 missingParams = parm.getParamName();
960 missingParams += "," + parm.getParamName();
965 if (missingParams != null) {
966 if (checkRequiredParameters) {
967 // Problem - missing one or more required parameters
968 String error = "Create VFModule: Missing Required inputs: " + missingParams;
969 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, CLOUDIFY,
970 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
972 throw new VnfException(error, MsoExceptionCategory.USERDATA);
974 logger.debug("found missing parameters [" + missingParams
975 + "] - but checkRequiredParameters is false -" + " will not block");
978 logger.debug("No missing parameters found - ok to proceed");
981 } // NOTE: END PARAMETER CHECKING
983 // Ready to deploy the VF Module.
984 // *First step - make sure the blueprint is loaded into Cloudify.
985 String blueprintName = heatTemplate.getTemplateName();
986 String blueprint = heatTemplate.getTemplateBody();
987 String blueprintId = blueprintName;
989 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
990 if (blueprintId.endsWith(".yaml"))
991 blueprintId = blueprintId.substring(0, blueprintId.lastIndexOf(".yaml"));
994 if (!cloudifyUtils.isBlueprintLoaded(cloudSiteId, blueprintId)) {
995 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
997 Map<String, byte[]> blueprintFiles = new HashMap<String, byte[]>();
999 blueprintFiles.put(blueprintName, blueprint.getBytes());
1001 // TODO: Implement nested blueprint logic based on Cloudify structures.
1002 // For now, just use the Heat structures.
1003 // The query returns a map of String->Object, where the map keys provide one layer of
1004 // indirection from the Heat template names. For this case, assume the map key matches
1005 // the nested blueprint name.
1006 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1007 if (nestedBlueprints != null) {
1008 for (HeatTemplate nestedBlueprint : nestedBlueprints) {
1009 blueprintFiles.put(nestedBlueprint.getTemplateName(),
1010 nestedBlueprint.getTemplateBody().getBytes());
1014 // TODO: Implement file artifact logic based on Cloudify structures.
1015 // For now, just use the Heat structures.
1016 List<HeatFiles> heatFiles = vf.getHeatFiles();
1017 if (heatFiles != null) {
1018 for (HeatFiles heatFile : heatFiles) {
1019 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1023 // Upload the blueprint package
1024 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1029 catch (MsoException me) {
1030 me.addContext("CreateVFModule");
1031 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1032 logger.error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1033 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1034 "MsoException - uploadBlueprint", me);
1035 logger.debug(error);
1036 throw new VnfException(me);
1039 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1040 // because we already checked for those.
1041 long createDeploymentStarttime = System.currentTimeMillis();
1043 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1044 // Go directly to Keystone until APIs could be updated to supply the name.
1045 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1046 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
1048 if (backout == null) {
1052 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment(cloudSiteId, tenantName, vfModuleName,
1053 blueprintId, goldenInputs, true, heatTemplate.getTimeoutMinutes(), backout.booleanValue());
1055 } catch (MsoException me) {
1056 me.addContext("CreateVFModule");
1057 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1058 + tenantId + ": " + me;
1059 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1060 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1061 "MsoException - createDeployment", me);
1062 logger.debug(error);
1063 throw new VnfException(me);
1064 } catch (NullPointerException npe) {
1065 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1066 + tenantId + ": " + npe;
1067 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1068 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1069 "NullPointerException - createDeployment", npe);
1070 logger.debug(error);
1071 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1072 // npe.addContext ("CreateVNF");
1073 throw new VnfException("NullPointerException during cloudify.createAndInstallDeployment");
1074 } catch (Exception e) {
1075 logger.debug("unhandled exception at cloudify.createAndInstallDeployment");
1076 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1078 } catch (Exception e) {
1079 logger.debug("unhandled exception in create VF");
1080 throw new VnfException("Exception during create VF " + e.getMessage());
1084 // Reach this point if create is successful.
1085 // Populate remaining rollback info and response parameters.
1086 vfRollback.setVnfCreated(true);
1087 vfRollback.setVnfId(cloudifyDeployment.getId());
1088 vnfId.value = cloudifyDeployment.getId();
1089 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
1091 rollback.value = vfRollback;
1093 logger.debug("VF Module successfully created", vfModuleName);
1097 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1098 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1099 logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1100 // Will capture execution time for metrics
1101 long startTime = System.currentTimeMillis();
1103 // 1702 capture the output parameters on a delete
1104 // so we'll need to query first
1105 DeploymentInfo deployment = null;
1107 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1108 } catch (MsoException me) {
1109 // Failed to query the deployment. Convert to a generic VnfException
1110 me.addContext("DeleteVFModule");
1111 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1112 + "/" + tenantId + ": " + me;
1113 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1114 CLOUDIFY, "QueryDeployment", ErrorCode.DataError.getValue(), "Exception - QueryDeployment", me);
1115 logger.debug(error);
1116 throw new VnfException(me);
1118 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1120 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1122 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1123 // The possible outcomes of deleteStack are a StackInfo object with status
1124 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1126 long subStartTime = System.currentTimeMillis();
1128 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1129 } catch (MsoException me) {
1130 me.addContext("DeleteVfModule");
1131 // Convert to a generic VnfException
1133 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1134 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1135 "DeleteDeployment", "DeleteDeployment", ErrorCode.DataError.getValue(),
1136 "Exception - DeleteDeployment: " + me.getMessage());
1137 logger.debug(error);
1138 throw new VnfException(me);
1141 // On success, nothing is returned.
1145 // TODO: Should Update be supported for Cloudify? What would this look like?
1147 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1148 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1149 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1150 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1151 throws VnfException {
1152 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1153 logger.debug("Update VF Module command attempted but not supported");
1154 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);