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.logger.LoggingAnchor;
36 import com.woorea.openstack.heat.Heat;
37 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
38 import org.onap.so.adapters.vnf.exceptions.VnfException;
39 import org.onap.so.cloud.CloudConfig;
40 import org.onap.so.db.catalog.beans.CloudSite;
41 import org.onap.so.cloudify.beans.DeploymentInfo;
42 import org.onap.so.cloudify.beans.DeploymentStatus;
43 import org.onap.so.cloudify.exceptions.MsoCloudifyManagerNotFound;
44 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
45 import org.onap.so.db.catalog.beans.HeatEnvironment;
46 import org.onap.so.db.catalog.beans.HeatFiles;
47 import org.onap.so.db.catalog.beans.HeatTemplate;
48 import org.onap.so.db.catalog.beans.HeatTemplateParam;
49 import org.onap.so.db.catalog.beans.VfModule;
50 import org.onap.so.db.catalog.beans.VfModuleCustomization;
51 import org.onap.so.db.catalog.beans.VnfResource;
52 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
53 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
54 import org.onap.so.entity.MsoRequest;
55 import org.onap.so.logger.ErrorCode;
56 import org.onap.so.logger.MessageEnum;
57 import org.onap.so.openstack.beans.MsoTenant;
58 import org.onap.so.openstack.beans.VnfRollback;
59 import org.onap.so.openstack.beans.VnfStatus;
60 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
61 import org.onap.so.openstack.exceptions.MsoException;
62 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
63 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
64 import org.onap.so.openstack.utils.MsoHeatEnvironmentParameter;
65 import org.onap.so.openstack.utils.MsoKeystoneUtils;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68 import org.springframework.beans.factory.annotation.Autowired;
69 import org.springframework.core.env.Environment;
70 import org.springframework.stereotype.Component;
71 import com.fasterxml.jackson.core.JsonParseException;
72 import com.fasterxml.jackson.databind.JsonNode;
73 import com.fasterxml.jackson.databind.ObjectMapper;
74 import org.springframework.transaction.annotation.Transactional;
78 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
79 targetNamespace = "http://org.onap.so/vnf")
80 public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter {
82 private static Logger logger = LoggerFactory.getLogger(MsoVnfCloudifyAdapterImpl.class);
84 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
85 private static final String CLOUDIFY = "Cloudify";
87 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
88 private static final String BRACKETS = LoggingAnchor.NINE;
89 private static final String OPENSTACK = "OpenStack";
92 protected CloudConfig cloudConfig;
95 private VFModuleCustomizationRepository vfModuleCustomRepo;
98 private Environment environment;
101 protected MsoKeystoneUtils keystoneUtils;
104 protected MsoCloudifyUtils cloudifyUtils;
107 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
109 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
111 public MsoVnfCloudifyAdapterImpl() {
116 * Health Check web method. Does nothing but return to show the adapter is deployed.
119 public void healthCheck() {
120 logger.debug("Health check call in VNF Cloudify Adapter");
124 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
128 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
129 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
130 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
131 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
132 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
133 logger.debug("CreateVNF command attempted but not supported");
134 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
138 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
142 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
143 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
144 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
145 throws VnfException {
146 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
147 logger.debug("UpdateVNF command attempted but not supported");
148 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
152 * This is the "Query VNF" web service implementation.
154 * This really should be QueryVfModule, but nobody ever changed it.
156 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same as deployment name,
157 * since it assigned by the client when a deployment is created. Also, the input cloudSiteId is used only to
158 * identify which Cloudify instance to query, and the tenantId is ignored (since that really only applies for
161 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
162 * also be reflected back as its ID.
164 * @param cloudSiteId CLLI code of the cloud site in which to query
165 * @param cloudOwner cloud owner of the cloud site in which to query
166 * @param tenantId Openstack tenant identifier - ignored for Cloudify
167 * @param vnfName VNF Name (should match a deployment ID)
168 * @param msoRequest Request tracking information for logs
169 * @param vnfExists Flag reporting the result of the query
170 * @param vnfId Holder for output VNF ID
171 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
174 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
175 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
176 Holder<Map<String, String>> outputs) throws VnfException {
177 logger.debug("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
179 // Will capture execution time for metrics
180 long startTime = System.currentTimeMillis();
181 long subStartTime = System.currentTimeMillis();
183 DeploymentInfo deployment = null;
186 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
187 } catch (MsoCloudifyManagerNotFound e) {
188 // This site does not have a Cloudify Manager.
189 // This isn't an error, just means we won't find the VNF here.
191 } catch (MsoException me) {
192 // Failed to query the Deployment due to a cloudify exception.
193 // Convert to a generic VnfException
194 me.addContext("QueryVNF");
195 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
197 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
198 CLOUDIFY, "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryDeployment", me);
200 throw new VnfException(me);
203 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
204 vnfExists.value = Boolean.TRUE;
205 status.value = deploymentStatusToVnfStatus(deployment);
206 vnfId.value = deployment.getId();
207 outputs.value = copyStringOutputs(deployment.getOutputs());
209 logger.debug("VNF {} found in Cloudify, ID = {}", vnfName, vnfId.value);
211 vnfExists.value = Boolean.FALSE;
212 status.value = VnfStatus.NOTFOUND;
214 outputs.value = new HashMap<String, String>(); // Return as an empty map
216 logger.debug("VNF {} not found", vnfName);
223 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
227 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
228 throws VnfException {
230 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
231 logger.debug("DeleteVNF command attempted but not supported");
232 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
236 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
237 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
238 * to undo the creation.
240 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
243 public void rollbackVnf(VnfRollback rollback) throws VnfException {
244 long startTime = System.currentTimeMillis();
245 // rollback may be null (e.g. if stack already existed when Create was called)
246 if (rollback == null) {
247 logger.info(LoggingAnchor.THREE, MessageEnum.RA_ROLLBACK_NULL.toString(), OPENSTACK, "rollbackVnf");
251 // Don't rollback if nothing was done originally
252 if (!rollback.getVnfCreated()) {
256 // Get the elements of the VnfRollback object for easier access
257 String cloudSiteId = rollback.getCloudSiteId();
258 String cloudOwner = rollback.getCloudOwner();
259 String tenantId = rollback.getTenantId();
260 String vfModuleId = rollback.getVfModuleStackId();
262 logger.debug("Rolling Back VF Module {} in {}", vfModuleId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
264 DeploymentInfo deployment = null;
266 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
267 // The possible outcomes of deleteStack are a StackInfo object with status
268 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
270 long subStartTime = System.currentTimeMillis();
272 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
273 // Go directly to Keystone until APIs could be updated to supply the name.
274 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
275 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
277 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
279 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
280 logger.debug("Rolled back deployment: {}", deployment.getId());
281 } catch (MsoException me) {
282 // Failed to rollback the VNF due to a cloudify exception.
283 // Convert to a generic VnfException
284 me.addContext("RollbackVNF");
285 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
286 + tenantId + ": " + me;
287 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
288 tenantId, CLOUDIFY, "DeleteDeployment", ErrorCode.DataError.getValue(),
289 "Exception - DeleteDeployment", me);
291 throw new VnfException(me);
297 private VnfStatus deploymentStatusToVnfStatus(DeploymentInfo deployment) {
298 // Determine the status based on last action & status
299 // DeploymentInfo object should be enhanced to report a better status internally.
300 DeploymentStatus status = deployment.getStatus();
301 String lastAction = deployment.getLastAction();
303 if (status == null || lastAction == null) {
304 return VnfStatus.UNKNOWN;
305 } else if (status == DeploymentStatus.NOTFOUND) {
306 return VnfStatus.NOTFOUND;
307 } else if (status == DeploymentStatus.INSTALLED) {
308 return VnfStatus.ACTIVE;
309 } else if (status == DeploymentStatus.CREATED) {
310 // Should have an INACTIVE status for this case. Shouldn't really happen, but
311 // Install was never run, or Uninstall was done but deployment didn't get deleted.
312 return VnfStatus.UNKNOWN;
313 } else if (status == DeploymentStatus.FAILED) {
314 return VnfStatus.FAILED;
317 return VnfStatus.UNKNOWN;
320 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
321 Map<String, String> stringOutputs = new HashMap<String, String>();
322 for (String key : stackOutputs.keySet()) {
323 if (stackOutputs.get(key) instanceof String) {
324 stringOutputs.put(key, (String) stackOutputs.get(key));
325 } else if (stackOutputs.get(key) instanceof Integer) {
327 String str = "" + stackOutputs.get(key);
328 stringOutputs.put(key, str);
329 } catch (Exception e) {
330 logger.debug("Unable to add " + key + " to outputs");
332 } else if (stackOutputs.get(key) instanceof JsonNode) {
334 String str = this.convertNode((JsonNode) stackOutputs.get(key));
335 stringOutputs.put(key, str);
336 } catch (Exception e) {
337 logger.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
339 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
341 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
342 stringOutputs.put(key, str);
343 } catch (Exception e) {
344 logger.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
348 String str = stackOutputs.get(key).toString();
349 stringOutputs.put(key, str);
350 } catch (Exception e) {
351 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
355 return stringOutputs;
359 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
361 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
362 if (inputs == null) {
364 } else if (inputs.size() < 1) {
365 sb.append("\tEMPTY");
367 for (String str : inputs.keySet()) {
370 outputString = inputs.get(str).toString();
371 } catch (Exception e) {
372 outputString = "Unable to call toString() on the value for " + str;
374 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
377 logger.debug(sb.toString());
381 private void sendMapToDebug(Map<String, Object> inputs) {
383 StringBuilder sb = new StringBuilder("inputs:");
384 if (inputs == null) {
386 } else if (inputs.size() < 1) {
387 sb.append("\tEMPTY");
389 for (String str : inputs.keySet()) {
390 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
393 logger.debug(sb.toString());
397 private String convertNode(final JsonNode node) {
399 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
400 final String json = JSON_MAPPER.writeValueAsString(obj);
402 } catch (JsonParseException jpe) {
403 logger.debug("Error converting json to string " + jpe.getMessage());
404 } catch (Exception e) {
405 logger.debug("Error converting json to string " + e.getMessage());
407 return "[Error converting json to string]";
410 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
411 if (objectMap == null) {
414 Map<String, String> stringMap = new HashMap<String, String>();
415 for (String key : objectMap.keySet()) {
416 if (!stringMap.containsKey(key)) {
417 Object obj = objectMap.get(key);
418 if (obj instanceof String) {
419 stringMap.put(key, (String) objectMap.get(key));
420 } else if (obj instanceof JsonNode) {
421 // This is a bit of mess - but I think it's the least impacting
422 // let's convert it BACK to a string - then it will get converted back later
424 String str = this.convertNode((JsonNode) obj);
425 stringMap.put(key, str);
426 } catch (Exception e) {
427 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key);
428 // okay in this instance - only string values (fqdn) are expected to be needed
430 } else if (obj instanceof java.util.LinkedHashMap) {
431 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
433 String str = JSON_MAPPER.writeValueAsString(obj);
434 stringMap.put(key, str);
435 } catch (Exception e) {
436 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key);
438 } else if (obj instanceof Integer) {
440 String str = "" + obj;
441 stringMap.put(key, str);
442 } catch (Exception e) {
443 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key);
447 String str = obj.toString();
448 stringMap.put(key, str);
449 } catch (Exception e) {
451 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")");
461 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
462 * type in the specified cloud and tenant. The tenant must exist before this service is called.
464 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
465 * value of the 'failIfExists' parameter.
467 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
468 * error will be returned. Within the catalog, each VF Module references (among other things) a cloud template which
469 * is used to deploy the required artifacts (VMs, networks, etc.) to the cloud. In this adapter implementation, that
470 * artifact is expected to be a Cloudify blueprint.
472 * Depending on the blueprint, a variable set of input parameters will be defined, some of which are required. The
473 * caller is responsible to pass the necessary input data for the module or an error will be thrown.
475 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
476 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
477 * VF module is successfully created but the orchestration fails on a subsequent step.
479 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
480 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
481 * @param tenantId Openstack tenant identifier
482 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
483 * modelCustomizationUuid
484 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
485 * also captured by modelCustomizationUuid
486 * @param genericVnfId Generic VNF ID
487 * @param vfModuleName Name to be assigned to the new VF Module
488 * @param vfModuleId Id of the new VF Module
489 * @param requestType Indicates if this is a Volume Group or Module request
490 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
491 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
492 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
493 * @param inputs Map of key=value inputs for VNF stack creation
494 * @param failIfExists Flag whether already existing VNF should be considered
495 * @param backout Flag whether to suppress automatic backout (for testing)
496 * @param msoRequest Request tracking information for logs
497 * @param vnfId Holder for output VNF Cloudify Deployment ID
498 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
499 * @param rollback Holder for returning VnfRollback object
502 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
503 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
504 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
505 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
506 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
507 // Will capture execution time for metrics
508 long startTime = System.currentTimeMillis();
510 // Require a model customization ID. Every VF Module definition must have one.
511 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
512 logger.debug("Missing required input: modelCustomizationUuid");
513 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
514 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
515 "VF Module ModelCustomizationUuid", CLOUDIFY, ErrorCode.DataError.getValue(),
516 "Create VF Module: Missing required input: modelCustomizationUuid");
518 throw new VnfException(error, MsoExceptionCategory.USERDATA);
521 // Clean up some inputs to make comparisons easier
522 if (requestType == null)
525 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
526 volumeGroupId = null;
528 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
529 baseVfModuleId = null;
531 if (inputs == null) {
532 // Create an empty set of inputs
533 inputs = new HashMap<>();
534 logger.debug("inputs == null - setting to empty");
536 this.sendMapToDebug(inputs);
539 // Check if this is for a "Volume" module
540 boolean isVolumeRequest = false;
541 if (requestType.startsWith("VOLUME")) {
542 isVolumeRequest = true;
545 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
548 // Build a default rollback object (no actions performed)
549 VnfRollback vfRollback = new VnfRollback();
550 vfRollback.setCloudSiteId(cloudSiteId);
551 vfRollback.setCloudOwner(cloudOwner);
552 vfRollback.setTenantId(tenantId);
553 vfRollback.setMsoRequest(msoRequest);
554 vfRollback.setRequestType(requestType);
555 vfRollback.setIsBase(false); // Until we know better
556 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
557 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
558 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
559 vfRollback.setMode("CFY");
561 rollback.value = vfRollback; // Default rollback - no updates performed
563 // Get the VNF/VF Module definition from the Catalog DB first.
564 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
567 VnfResource vnfResource = null;
568 VfModuleCustomization vfmc = null;
571 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
574 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
575 + modelCustomizationUuid;
577 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
578 "VF Module " + "ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb",
579 ErrorCode.DataError.getValue(), error);
580 throw new VnfException(error, MsoExceptionCategory.USERDATA);
582 logger.debug("Found vfModuleCust entry " + vfmc.toString());
585 // Get the vfModule and vnfResource records
586 vf = vfmc.getVfModule();
587 vnfResource = vfmc.getVfModule().getVnfResources();
588 } catch (Exception e) {
590 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
591 throw new VnfException("Exception during create VF " + e.getMessage());
594 // Perform a version check against cloudSite
595 // Obtain the cloud site information where we will create the VF Module
596 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
597 if (!cloudSiteOp.isPresent()) {
598 throw new VnfException(new MsoCloudSiteNotFound(cloudSiteId));
600 CloudSite cloudSite = cloudSiteOp.get();
601 MavenLikeVersioning aicV = new MavenLikeVersioning();
602 aicV.setVersion(cloudSite.getCloudVersion());
604 String vnfMin = vnfResource.getAicVersionMin();
605 String vnfMax = vnfResource.getAicVersionMax();
607 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
608 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
610 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
611 + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax
612 + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
613 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK,
614 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
616 throw new VnfException(error, MsoExceptionCategory.USERDATA);
621 DeploymentInfo cloudifyDeployment = null;
623 // First, look up to see if the VF already exists.
625 long subStartTime1 = System.currentTimeMillis();
627 cloudifyDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vfModuleName);
628 } catch (MsoException me) {
629 // Failed to query the Deployment due to a cloudify exception.
630 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
631 + tenantId + ": " + me;
632 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudSiteId,
633 tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
634 "Exception - queryDeployment", me);
637 // Convert to a generic VnfException
638 me.addContext("CreateVFModule");
639 throw new VnfException(me);
642 // More precise handling/messaging if the Module already exists
643 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus() == DeploymentStatus.NOTFOUND)) {
644 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
645 DeploymentStatus status = cloudifyDeployment.getStatus();
646 logger.debug("Found Existing Deployment, status=" + status);
648 if (status == DeploymentStatus.INSTALLED) {
650 if (failIfExists != null && failIfExists) {
651 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
652 + cloudSiteId + "/" + tenantId;
653 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
654 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
655 "Deployment " + vfModuleName + " already exists");
657 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
658 cloudifyDeployment.getId());
660 // Found existing deployment and client has not requested "failIfExists".
661 // Populate the outputs from the existing deployment.
663 vnfId.value = cloudifyDeployment.getId();
664 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
668 // Check through various detailed error cases
669 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
670 // fail - it's in progress - return meaningful error
671 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
672 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
673 + "; please wait for it to complete, or fix manually.";
674 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
675 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
676 "Deployment " + vfModuleName + " already exists");
678 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
679 } else if (status == DeploymentStatus.FAILED) {
680 // fail - it exists and is in a FAILED state
681 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
682 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
683 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
684 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
685 "Deployment " + vfModuleName + " already " + "exists and is in FAILED state");
687 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
688 } else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
689 // fail - it exists and is in a UNKNOWN state
690 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
691 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
692 + "; requires manual intervention.";
693 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
694 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
695 "Deployment " + vfModuleName + " already " + "exists and is in " + status.toString()
698 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
700 // Unexpected, since all known status values have been tested for
701 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
702 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
703 + "; requires manual intervention.";
704 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
705 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
706 "Deployment " + vfModuleName + " already " + "exists and is in an unknown state");
708 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
713 // Collect outputs from Base Modules and Volume Modules
714 Map<String, Object> baseModuleOutputs = null;
715 Map<String, Object> volumeGroupOutputs = null;
717 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
718 if (volumeGroupId != null) {
719 long subStartTime2 = System.currentTimeMillis();
720 DeploymentInfo volumeDeployment = null;
722 volumeDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, volumeGroupId);
723 } catch (MsoException me) {
724 // Failed to query the Volume GroupDeployment due to a cloudify exception.
725 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
726 + cloudSiteId + "/" + tenantId + ": " + me;
727 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner, cloudSiteId,
728 tenantId, CLOUDIFY, "queryDeployment(volume)", ErrorCode.DataError.getValue(),
729 "Exception - queryDeployment(volume)", me);
731 // Convert to a generic VnfException
732 me.addContext("CreateVFModule(QueryVolume)");
733 throw new VnfException(me);
736 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
737 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
738 + cloudSiteId + "/" + tenantId + " USER ERROR";
739 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudSiteId, tenantId,
740 error, CLOUDIFY, "queryDeployment(volume)", ErrorCode.BusinessProcesssError.getValue(),
741 "Create VFModule: Attached Volume Group DOES NOT EXIST");
743 throw new VnfException(error, MsoExceptionCategory.USERDATA);
745 logger.debug("Found nested volume group");
746 volumeGroupOutputs = volumeDeployment.getOutputs();
747 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
751 // If this is an Add-On Module, query the Base Module outputs
752 // Note: This will be performed whether or not the current request is for an
753 // Add-On Volume Group or Add-On VF Module
755 if (vf.getIsBase()) {
756 logger.debug("This is a BASE Module request");
757 vfRollback.setIsBase(true);
759 logger.debug("This is an Add-On Module request");
761 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
762 // Add-on Volume requests may or may not specify a base.
763 if (!isVolumeRequest && baseVfModuleId == null) {
764 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
767 if (baseVfModuleId != null) {
768 long subStartTime2 = System.currentTimeMillis();
769 DeploymentInfo baseDeployment = null;
771 baseDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, baseVfModuleId);
772 } catch (MsoException me) {
773 // Failed to query the Volume GroupDeployment due to a cloudify exception.
774 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
775 + cloudSiteId + "/" + tenantId + ": " + me;
776 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudOwner,
777 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)", ErrorCode.DataError.getValue(),
778 "Exception - queryDeployment(Base)", me);
780 // Convert to a generic VnfException
781 me.addContext("CreateVFModule(QueryBase)");
782 throw new VnfException(me);
785 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
786 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in "
787 + cloudSiteId + "/" + tenantId + " USER ERROR";
788 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudSiteId,
789 tenantId, error, CLOUDIFY, "queryDeployment(Base)",
790 ErrorCode.BusinessProcesssError.getValue(),
791 "Create VFModule: Base " + "Module DOES NOT EXIST");
793 throw new VnfException(error, MsoExceptionCategory.USERDATA);
795 logger.debug("Found base module");
796 baseModuleOutputs = baseDeployment.getOutputs();
797 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
803 // Ready to deploy the new VNF
805 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
806 // In final implementation (post-POC), the template object would either be generic or there would
807 // be a separate DB Table/Object for Blueprints.
810 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
811 HeatTemplate heatTemplate = null;
812 HeatEnvironment heatEnvironment = null;
813 if (isVolumeRequest) {
814 heatTemplate = vf.getVolumeHeatTemplate();
815 heatEnvironment = vfmc.getVolumeHeatEnv();
817 heatTemplate = vf.getModuleHeatTemplate();
818 heatEnvironment = vfmc.getHeatEnvironment();
821 if (heatTemplate == null) {
822 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
823 + ", modelCustomizationUuid=" + modelCustomizationUuid + ", vfModuleUuid=" + vf.getModelUUID()
824 + ", reqType=" + requestType;
825 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
826 vfModuleType, OPENSTACK, ErrorCode.DataError.getValue(), error);
827 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
829 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
832 if (heatEnvironment == null) {
833 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + ", modelCustomizationUuid="
834 + modelCustomizationUuid + ", vfModuleUuid=" + vf.getModelUUID() + ", reqType=" + requestType;
835 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
836 OPENSTACK, ErrorCode.DataError.getValue(), error);
837 // Alarm on this error, configuration must be fixed
838 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
840 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
845 // All variables converted to their native object types
846 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
847 List<String> extraInputs = new ArrayList<String>();
849 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
850 // This whole section needs to be rewritten.
851 Boolean skipInputChecks = false;
853 if (skipInputChecks) {
854 goldenInputs = new HashMap<String, Object>();
855 for (String key : inputs.keySet()) {
856 goldenInputs.put(key, inputs.get(key));
859 // Build maps for the parameters (including aliases) to simplify checks
860 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
862 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
863 logger.debug("paramSet has {} entries", paramSet.size());
865 for (HeatTemplateParam htp : paramSet) {
866 params.put(htp.getParamName(), htp);
869 String alias = htp.getParamAlias();
870 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
871 params.put(alias, htp);
875 // First, convert all inputs to their "template" type
876 for (String key : inputs.keySet()) {
877 if (params.containsKey(key)) {
878 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
880 goldenInputs.put(key, value);
882 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
883 + params.get(key).getParamType());
886 extraInputs.add(key);
890 if (!extraInputs.isEmpty()) {
891 logger.debug("Ignoring extra inputs: " + extraInputs);
894 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
895 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
896 for (String key : volumeGroupOutputs.keySet()) {
897 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
898 goldenInputs.put(key, volumeGroupOutputs.get(key));
903 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
904 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
905 for (String key : baseModuleOutputs.keySet()) {
906 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
907 goldenInputs.put(key, baseModuleOutputs.get(key));
912 // Last, add in values from the "environment" file.
913 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
915 // TODO: This may take a different form for Cloudify, but for now process it
916 // with Heat environment file syntax
917 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
918 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
920 if (mhee.getParameters() != null) {
921 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
922 // If this is a template input, copy to golden inputs
923 String envKey = envParam.getName();
924 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
925 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
927 goldenInputs.put(envKey, value);
929 logger.debug("Failed to convert environment parameter " + envKey + "='"
930 + envParam.getValue() + "' to " + params.get(envKey).getParamType());
936 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
939 // Check that required parameters have been supplied from any of the sources
940 String missingParams = null;
941 boolean checkRequiredParameters = true;
943 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
944 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
945 checkRequiredParameters = false;
946 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
947 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
949 } catch (Exception e) {
950 // No problem - default is true
951 logger.debug("An exception occured trying to get property {}",
952 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
956 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
957 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
958 logger.debug("adding to missing parameters list: {}", parm.getParamName());
959 if (missingParams == null) {
960 missingParams = parm.getParamName();
962 missingParams += "," + parm.getParamName();
967 if (missingParams != null) {
968 if (checkRequiredParameters) {
969 // Problem - missing one or more required parameters
970 String error = "Create VFModule: Missing Required inputs: " + missingParams;
971 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams,
972 CLOUDIFY, ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
974 throw new VnfException(error, MsoExceptionCategory.USERDATA);
976 logger.debug("found missing parameters [" + missingParams
977 + "] - but checkRequiredParameters is false -" + " will not block");
980 logger.debug("No missing parameters found - ok to proceed");
983 } // NOTE: END PARAMETER CHECKING
985 // Ready to deploy the VF Module.
986 // *First step - make sure the blueprint is loaded into Cloudify.
987 String blueprintName = heatTemplate.getTemplateName();
988 String blueprint = heatTemplate.getTemplateBody();
989 String blueprintId = blueprintName;
991 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
992 if (blueprintId.endsWith(".yaml"))
993 blueprintId = blueprintId.substring(0, blueprintId.lastIndexOf(".yaml"));
996 if (!cloudifyUtils.isBlueprintLoaded(cloudSiteId, blueprintId)) {
997 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
999 Map<String, byte[]> blueprintFiles = new HashMap<String, byte[]>();
1001 blueprintFiles.put(blueprintName, blueprint.getBytes());
1003 // TODO: Implement nested blueprint logic based on Cloudify structures.
1004 // For now, just use the Heat structures.
1005 // The query returns a map of String->Object, where the map keys provide one layer of
1006 // indirection from the Heat template names. For this case, assume the map key matches
1007 // the nested blueprint name.
1008 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1009 if (nestedBlueprints != null) {
1010 for (HeatTemplate nestedBlueprint : nestedBlueprints) {
1011 blueprintFiles.put(nestedBlueprint.getTemplateName(),
1012 nestedBlueprint.getTemplateBody().getBytes());
1016 // TODO: Implement file artifact logic based on Cloudify structures.
1017 // For now, just use the Heat structures.
1018 List<HeatFiles> heatFiles = vf.getHeatFiles();
1019 if (heatFiles != null) {
1020 for (HeatFiles heatFile : heatFiles) {
1021 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1025 // Upload the blueprint package
1026 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1031 catch (MsoException me) {
1032 me.addContext("CreateVFModule");
1033 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1034 logger.error(LoggingAnchor.SEVEN, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudSiteId,
1035 tenantId, CLOUDIFY, ErrorCode.DataError.getValue(), "MsoException - uploadBlueprint", me);
1036 logger.debug(error);
1037 throw new VnfException(me);
1040 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1041 // because we already checked for those.
1042 long createDeploymentStarttime = System.currentTimeMillis();
1044 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1045 // Go directly to Keystone until APIs could be updated to supply the name.
1046 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1047 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
1049 if (backout == null) {
1053 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment(cloudSiteId, tenantName, vfModuleName,
1054 blueprintId, goldenInputs, true, heatTemplate.getTimeoutMinutes(), backout.booleanValue());
1056 } catch (MsoException me) {
1057 me.addContext("CreateVFModule");
1058 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1059 + tenantId + ": " + me;
1060 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1061 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1062 "MsoException - createDeployment", me);
1063 logger.debug(error);
1064 throw new VnfException(me);
1065 } catch (NullPointerException npe) {
1066 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1067 + tenantId + ": " + npe;
1068 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1069 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1070 "NullPointerException - createDeployment", npe);
1071 logger.debug(error);
1072 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1073 // npe.addContext ("CreateVNF");
1074 throw new VnfException("NullPointerException during cloudify.createAndInstallDeployment");
1075 } catch (Exception e) {
1076 logger.debug("unhandled exception at cloudify.createAndInstallDeployment");
1077 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1079 } catch (Exception e) {
1080 logger.debug("unhandled exception in create VF");
1081 throw new VnfException("Exception during create VF " + e.getMessage());
1085 // Reach this point if create is successful.
1086 // Populate remaining rollback info and response parameters.
1087 vfRollback.setVnfCreated(true);
1088 vfRollback.setVnfId(cloudifyDeployment.getId());
1089 vnfId.value = cloudifyDeployment.getId();
1090 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
1092 rollback.value = vfRollback;
1094 logger.debug("VF Module successfully created", vfModuleName);
1098 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1099 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1100 logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1101 // Will capture execution time for metrics
1102 long startTime = System.currentTimeMillis();
1104 // 1702 capture the output parameters on a delete
1105 // so we'll need to query first
1106 DeploymentInfo deployment = null;
1108 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1109 } catch (MsoException me) {
1110 // Failed to query the deployment. Convert to a generic VnfException
1111 me.addContext("DeleteVFModule");
1112 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1113 + "/" + tenantId + ": " + me;
1114 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1115 CLOUDIFY, "QueryDeployment", ErrorCode.DataError.getValue(), "Exception - QueryDeployment", me);
1116 logger.debug(error);
1117 throw new VnfException(me);
1119 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1121 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1123 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1124 // The possible outcomes of deleteStack are a StackInfo object with status
1125 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1127 long subStartTime = System.currentTimeMillis();
1129 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1130 } catch (MsoException me) {
1131 me.addContext("DeleteVfModule");
1132 // Convert to a generic VnfException
1134 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1135 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1136 "DeleteDeployment", "DeleteDeployment", ErrorCode.DataError.getValue(),
1137 "Exception - DeleteDeployment: " + me.getMessage());
1138 logger.debug(error);
1139 throw new VnfException(me);
1142 // On success, nothing is returned.
1146 // TODO: Should Update be supported for Cloudify? What would this look like?
1148 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1149 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1150 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1151 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1152 throws VnfException {
1153 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1154 logger.debug("Update VF Module command attempted but not supported");
1155 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);