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 MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
83 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
84 private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN.";
85 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
86 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq";
87 private static final String CLOUDIFY_RESPONSE_SUCCESS = "Successfully received response from Cloudify";
88 private static final String CLOUDIFY = "Cloudify";
90 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
93 protected CloudConfig cloudConfig;
96 private VFModuleCustomizationRepository vfModuleCustomRepo;
99 private Environment environment;
102 protected MsoKeystoneUtils keystoneUtils;
105 protected MsoCloudifyUtils cloudifyUtils;
108 * Health Check web method. Does nothing but return to show the adapter is deployed.
111 public void healthCheck() {
112 logger.debug("Health check call in VNF Cloudify Adapter");
116 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
118 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
120 public MsoVnfCloudifyAdapterImpl() {
125 * This is the "Create VNF" web service implementation. This function is now unsupported and will return an error.
129 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
130 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
131 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
132 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
133 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
134 logger.debug("CreateVNF command attempted but not supported");
135 throw new VnfException("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
139 * This is the "Update VNF" web service implementation. This function is now unsupported and will return an error.
143 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
144 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
145 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
146 throws VnfException {
147 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
148 logger.debug("UpdateVNF command attempted but not supported");
149 throw new VnfException("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
153 * This is the "Query VNF" web service implementation.
155 * This really should be QueryVfModule, but nobody ever changed it.
157 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same as deployment name,
158 * since it assigned by the client when a deployment is created. Also, the input cloudSiteId is used only to
159 * identify which Cloudify instance to query, and the tenantId is ignored (since that really only applies for
162 * The method returns an indicator that the VNF exists, along with its status and outputs. The input "vnfName" will
163 * also be reflected back as its ID.
165 * @param cloudSiteId CLLI code of the cloud site in which to query
166 * @param cloudOwner cloud owner of the cloud site in which to query
167 * @param tenantId Openstack tenant identifier - ignored for Cloudify
168 * @param vnfName VNF Name (should match a deployment ID)
169 * @param msoRequest Request tracking information for logs
170 * @param vnfExists Flag reporting the result of the query
171 * @param vnfId Holder for output VNF ID
172 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
175 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
176 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
177 Holder<Map<String, String>> outputs) throws VnfException {
178 logger.debug("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
180 // Will capture execution time for metrics
181 long startTime = System.currentTimeMillis();
182 long subStartTime = System.currentTimeMillis();
184 DeploymentInfo deployment = null;
187 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
188 } catch (MsoCloudifyManagerNotFound e) {
189 // This site does not have a Cloudify Manager.
190 // This isn't an error, just means we won't find the VNF here.
192 } catch (MsoException me) {
193 // Failed to query the Deployment due to a cloudify exception.
194 // Convert to a generic VnfException
195 me.addContext("QueryVNF");
196 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
198 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
199 cloudSiteId, tenantId, CLOUDIFY, "QueryVNF", ErrorCode.DataError.getValue(),
200 "Exception - queryDeployment", me);
202 throw new VnfException(me);
205 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
206 vnfExists.value = Boolean.TRUE;
207 status.value = deploymentStatusToVnfStatus(deployment);
208 vnfId.value = deployment.getId();
209 outputs.value = copyStringOutputs(deployment.getOutputs());
211 logger.debug("VNF {} found in Cloudify, ID = {}", vnfName, vnfId.value);
213 vnfExists.value = Boolean.FALSE;
214 status.value = VnfStatus.NOTFOUND;
216 outputs.value = new HashMap<String, String>(); // Return as an empty map
218 logger.debug("VNF {} not found", vnfName);
225 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
229 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
230 throws VnfException {
232 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
233 logger.debug("DeleteVNF command attempted but not supported");
234 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
238 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
239 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
240 * to undo the creation.
242 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
245 public void rollbackVnf(VnfRollback rollback) throws VnfException {
246 long startTime = System.currentTimeMillis();
247 // rollback may be null (e.g. if stack already existed when Create was called)
248 if (rollback == null) {
249 logger.info("{} {} {}", MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
253 // Don't rollback if nothing was done originally
254 if (!rollback.getVnfCreated()) {
258 // Get the elements of the VnfRollback object for easier access
259 String cloudSiteId = rollback.getCloudSiteId();
260 String cloudOwner = rollback.getCloudOwner();
261 String tenantId = rollback.getTenantId();
262 String vfModuleId = rollback.getVfModuleStackId();
264 logger.debug("Rolling Back VF Module {} in {}", vfModuleId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
266 DeploymentInfo deployment = null;
268 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
269 // The possible outcomes of deleteStack are a StackInfo object with status
270 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
272 long subStartTime = System.currentTimeMillis();
274 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
275 // Go directly to Keystone until APIs could be updated to supply the name.
276 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
277 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
279 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
281 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
282 logger.debug("Rolled back deployment: {}", deployment.getId());
283 } catch (MsoException me) {
284 // Failed to rollback the VNF due to a cloudify exception.
285 // Convert to a generic VnfException
286 me.addContext("RollbackVNF");
287 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
288 + tenantId + ": " + me;
289 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner,
290 cloudSiteId, tenantId, CLOUDIFY, "DeleteDeployment", ErrorCode.DataError.getValue(),
291 "Exception - DeleteDeployment", me);
293 throw new VnfException(me);
299 private VnfStatus deploymentStatusToVnfStatus(DeploymentInfo deployment) {
300 // Determine the status based on last action & status
301 // DeploymentInfo object should be enhanced to report a better status internally.
302 DeploymentStatus status = deployment.getStatus();
303 String lastAction = deployment.getLastAction();
305 if (status == null || lastAction == null) {
306 return VnfStatus.UNKNOWN;
307 } else if (status == DeploymentStatus.NOTFOUND) {
308 return VnfStatus.NOTFOUND;
309 } else if (status == DeploymentStatus.INSTALLED) {
310 return VnfStatus.ACTIVE;
311 } else if (status == DeploymentStatus.CREATED) {
312 // Should have an INACTIVE status for this case. Shouldn't really happen, but
313 // Install was never run, or Uninstall was done but deployment didn't get deleted.
314 return VnfStatus.UNKNOWN;
315 } else if (status == DeploymentStatus.FAILED) {
316 return VnfStatus.FAILED;
319 return VnfStatus.UNKNOWN;
322 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
323 Map<String, String> stringOutputs = new HashMap<String, String>();
324 for (String key : stackOutputs.keySet()) {
325 if (stackOutputs.get(key) instanceof String) {
326 stringOutputs.put(key, (String) stackOutputs.get(key));
327 } else if (stackOutputs.get(key) instanceof Integer) {
329 String str = "" + stackOutputs.get(key);
330 stringOutputs.put(key, str);
331 } catch (Exception e) {
332 logger.debug("Unable to add " + key + " to outputs");
334 } else if (stackOutputs.get(key) instanceof JsonNode) {
336 String str = this.convertNode((JsonNode) stackOutputs.get(key));
337 stringOutputs.put(key, str);
338 } catch (Exception e) {
339 logger.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
341 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
343 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
344 stringOutputs.put(key, str);
345 } catch (Exception e) {
346 logger.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
350 String str = stackOutputs.get(key).toString();
351 stringOutputs.put(key, str);
352 } catch (Exception e) {
353 logger.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
357 return stringOutputs;
361 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
363 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
364 if (inputs == null) {
366 } else if (inputs.size() < 1) {
367 sb.append("\tEMPTY");
369 for (String str : inputs.keySet()) {
372 outputString = inputs.get(str).toString();
373 } catch (Exception e) {
374 outputString = "Unable to call toString() on the value for " + str;
376 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
379 logger.debug(sb.toString());
383 private void sendMapToDebug(Map<String, Object> inputs) {
385 StringBuilder sb = new StringBuilder("inputs:");
386 if (inputs == null) {
388 } else if (inputs.size() < 1) {
389 sb.append("\tEMPTY");
391 for (String str : inputs.keySet()) {
392 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
395 logger.debug(sb.toString());
399 private String convertNode(final JsonNode node) {
401 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
402 final String json = JSON_MAPPER.writeValueAsString(obj);
404 } catch (JsonParseException jpe) {
405 logger.debug("Error converting json to string " + jpe.getMessage());
406 } catch (Exception e) {
407 logger.debug("Error converting json to string " + e.getMessage());
409 return "[Error converting json to string]";
412 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
413 if (objectMap == null) {
416 Map<String, String> stringMap = new HashMap<String, String>();
417 for (String key : objectMap.keySet()) {
418 if (!stringMap.containsKey(key)) {
419 Object obj = objectMap.get(key);
420 if (obj instanceof String) {
421 stringMap.put(key, (String) objectMap.get(key));
422 } else if (obj instanceof JsonNode) {
423 // This is a bit of mess - but I think it's the least impacting
424 // let's convert it BACK to a string - then it will get converted back later
426 String str = this.convertNode((JsonNode) obj);
427 stringMap.put(key, str);
428 } catch (Exception e) {
429 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key);
430 // okay in this instance - only string values (fqdn) are expected to be needed
432 } else if (obj instanceof java.util.LinkedHashMap) {
433 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
435 String str = JSON_MAPPER.writeValueAsString(obj);
436 stringMap.put(key, str);
437 } catch (Exception e) {
438 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key);
440 } else if (obj instanceof Integer) {
442 String str = "" + obj;
443 stringMap.put(key, str);
444 } catch (Exception e) {
445 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key);
449 String str = obj.toString();
450 stringMap.put(key, str);
451 } catch (Exception e) {
453 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")");
463 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
464 * type in the specified cloud and tenant. The tenant must exist before this service is called.
466 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
467 * value of the 'failIfExists' parameter.
469 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
470 * error will be returned. Within the catalog, each VF Module references (among other things) a cloud template which
471 * is used to deploy the required artifacts (VMs, networks, etc.) to the cloud. In this adapter implementation, that
472 * artifact is expected to be a Cloudify blueprint.
474 * Depending on the blueprint, a variable set of input parameters will be defined, some of which are required. The
475 * caller is responsible to pass the necessary input data for the module or an error will be thrown.
477 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
478 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
479 * VF module is successfully created but the orchestration fails on a subsequent step.
481 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
482 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
483 * @param tenantId Openstack tenant identifier
484 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
485 * modelCustomizationUuid
486 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
487 * also captured by modelCustomizationUuid
488 * @param genericVnfId Generic VNF ID
489 * @param vfModuleName Name to be assigned to the new VF Module
490 * @param vfModuleId Id of the new VF Module
491 * @param requestType Indicates if this is a Volume Group or Module request
492 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
493 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
494 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
495 * @param inputs Map of key=value inputs for VNF stack creation
496 * @param failIfExists Flag whether already existing VNF should be considered
497 * @param backout Flag whether to suppress automatic backout (for testing)
498 * @param msoRequest Request tracking information for logs
499 * @param vnfId Holder for output VNF Cloudify Deployment ID
500 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
501 * @param rollback Holder for returning VnfRollback object
504 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
505 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
506 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
507 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
508 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
509 // Will capture execution time for metrics
510 long startTime = System.currentTimeMillis();
512 // Require a model customization ID. Every VF Module definition must have one.
513 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
514 logger.debug("Missing required input: modelCustomizationUuid");
515 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
516 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
517 "VF Module ModelCustomizationUuid", CLOUDIFY, ErrorCode.DataError.getValue(),
518 "Create VF Module: Missing required input: modelCustomizationUuid");
520 throw new VnfException(error, MsoExceptionCategory.USERDATA);
523 // Clean up some inputs to make comparisons easier
524 if (requestType == null)
527 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
528 volumeGroupId = null;
530 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
531 baseVfModuleId = null;
533 if (inputs == null) {
534 // Create an empty set of inputs
535 inputs = new HashMap<>();
536 logger.debug("inputs == null - setting to empty");
538 this.sendMapToDebug(inputs);
541 // Check if this is for a "Volume" module
542 boolean isVolumeRequest = false;
543 if (requestType.startsWith("VOLUME")) {
544 isVolumeRequest = true;
547 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
550 // Build a default rollback object (no actions performed)
551 VnfRollback vfRollback = new VnfRollback();
552 vfRollback.setCloudSiteId(cloudSiteId);
553 vfRollback.setCloudOwner(cloudOwner);
554 vfRollback.setTenantId(tenantId);
555 vfRollback.setMsoRequest(msoRequest);
556 vfRollback.setRequestType(requestType);
557 vfRollback.setIsBase(false); // Until we know better
558 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
559 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
560 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
561 vfRollback.setMode("CFY");
563 rollback.value = vfRollback; // Default rollback - no updates performed
565 // Get the VNF/VF Module definition from the Catalog DB first.
566 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
569 VnfResource vnfResource = null;
570 VfModuleCustomization vfmc = null;
573 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
576 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
577 + modelCustomizationUuid;
579 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
580 "VF Module " + "ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb",
581 ErrorCode.DataError.getValue(), error);
582 throw new VnfException(error, MsoExceptionCategory.USERDATA);
584 logger.debug("Found vfModuleCust entry " + vfmc.toString());
587 // Get the vfModule and vnfResource records
588 vf = vfmc.getVfModule();
589 vnfResource = vfmc.getVfModule().getVnfResources();
590 } catch (Exception e) {
592 logger.debug("unhandled exception in create VF - [Query]" + e.getMessage());
593 throw new VnfException("Exception during create VF " + e.getMessage());
596 // Perform a version check against cloudSite
597 // Obtain the cloud site information where we will create the VF Module
598 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
599 if (!cloudSiteOp.isPresent()) {
600 throw new VnfException(new MsoCloudSiteNotFound(cloudSiteId));
602 CloudSite cloudSite = cloudSiteOp.get();
603 MavenLikeVersioning aicV = new MavenLikeVersioning();
604 aicV.setVersion(cloudSite.getCloudVersion());
606 String vnfMin = vnfResource.getAicVersionMin();
607 String vnfMax = vnfResource.getAicVersionMax();
609 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
610 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
612 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
613 + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax
614 + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
615 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
616 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
618 throw new VnfException(error, MsoExceptionCategory.USERDATA);
623 DeploymentInfo cloudifyDeployment = null;
625 // First, look up to see if the VF already exists.
627 long subStartTime1 = System.currentTimeMillis();
629 cloudifyDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vfModuleName);
630 } catch (MsoException me) {
631 // Failed to query the Deployment due to a cloudify exception.
632 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
633 + tenantId + ": " + me;
634 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudSiteId,
635 tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
636 "Exception - queryDeployment", me);
639 // Convert to a generic VnfException
640 me.addContext("CreateVFModule");
641 throw new VnfException(me);
644 // More precise handling/messaging if the Module already exists
645 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus() == DeploymentStatus.NOTFOUND)) {
646 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
647 DeploymentStatus status = cloudifyDeployment.getStatus();
648 logger.debug("Found Existing Deployment, status=" + status);
650 if (status == DeploymentStatus.INSTALLED) {
652 if (failIfExists != null && failIfExists) {
653 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
654 + cloudSiteId + "/" + tenantId;
655 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(),
656 vfModuleName, cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment",
657 ErrorCode.DataError.getValue(), "Deployment " + vfModuleName + " already exists");
659 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
660 cloudifyDeployment.getId());
662 // Found existing deployment and client has not requested "failIfExists".
663 // Populate the outputs from the existing deployment.
665 vnfId.value = cloudifyDeployment.getId();
666 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
670 // Check through various detailed error cases
671 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
672 // fail - it's in progress - return meaningful error
673 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
674 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
675 + "; please wait for it to complete, or fix manually.";
676 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
677 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
678 "Deployment " + vfModuleName + " already exists");
680 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
681 } else if (status == DeploymentStatus.FAILED) {
682 // fail - it exists and is in a FAILED state
683 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
684 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
685 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
686 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
687 "Deployment " + vfModuleName + " already " + "exists and is in FAILED state");
689 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
690 } else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
691 // fail - it exists and is in a UNKNOWN state
692 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
693 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
694 + "; requires manual intervention.";
695 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
696 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
697 "Deployment " + vfModuleName + " already " + "exists and is in " + status.toString()
700 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
702 // Unexpected, since all known status values have been tested for
703 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status "
704 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
705 + "; requires manual intervention.";
706 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
707 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
708 "Deployment " + vfModuleName + " already " + "exists and is in an unknown state");
710 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
715 // Collect outputs from Base Modules and Volume Modules
716 Map<String, Object> baseModuleOutputs = null;
717 Map<String, Object> volumeGroupOutputs = null;
719 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
720 if (volumeGroupId != null) {
721 long subStartTime2 = System.currentTimeMillis();
722 DeploymentInfo volumeDeployment = null;
724 volumeDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, volumeGroupId);
725 } catch (MsoException me) {
726 // Failed to query the Volume GroupDeployment due to a cloudify exception.
727 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
728 + cloudSiteId + "/" + tenantId + ": " + me;
729 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
730 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(volume)",
731 ErrorCode.DataError.getValue(), "Exception - queryDeployment(volume)", me);
733 // Convert to a generic VnfException
734 me.addContext("CreateVFModule(QueryVolume)");
735 throw new VnfException(me);
738 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
739 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
740 + cloudSiteId + "/" + tenantId + " USER ERROR";
741 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId,
742 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(volume)",
743 ErrorCode.BusinessProcesssError.getValue(),
744 "Create VFModule: Attached Volume Group DOES NOT EXIST");
746 throw new VnfException(error, MsoExceptionCategory.USERDATA);
748 logger.debug("Found nested volume group");
749 volumeGroupOutputs = volumeDeployment.getOutputs();
750 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
754 // If this is an Add-On Module, query the Base Module outputs
755 // Note: This will be performed whether or not the current request is for an
756 // Add-On Volume Group or Add-On VF Module
758 if (vf.getIsBase()) {
759 logger.debug("This is a BASE Module request");
760 vfRollback.setIsBase(true);
762 logger.debug("This is an Add-On Module request");
764 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
765 // Add-on Volume requests may or may not specify a base.
766 if (!isVolumeRequest && baseVfModuleId == null) {
767 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
770 if (baseVfModuleId != null) {
771 long subStartTime2 = System.currentTimeMillis();
772 DeploymentInfo baseDeployment = null;
774 baseDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, baseVfModuleId);
775 } catch (MsoException me) {
776 // Failed to query the Volume GroupDeployment due to a cloudify exception.
777 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
778 + cloudSiteId + "/" + tenantId + ": " + me;
779 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
780 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)",
781 ErrorCode.DataError.getValue(), "Exception - queryDeployment(Base)", me);
783 // Convert to a generic VnfException
784 me.addContext("CreateVFModule(QueryBase)");
785 throw new VnfException(me);
788 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
789 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in "
790 + cloudSiteId + "/" + tenantId + " USER ERROR";
791 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId,
792 cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(Base)",
793 ErrorCode.BusinessProcesssError.getValue(),
794 "Create VFModule: Base " + "Module DOES NOT EXIST");
796 throw new VnfException(error, MsoExceptionCategory.USERDATA);
798 logger.debug("Found base module");
799 baseModuleOutputs = baseDeployment.getOutputs();
800 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
806 // Ready to deploy the new VNF
808 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
809 // In final implementation (post-POC), the template object would either be generic or there would
810 // be a separate DB Table/Object for Blueprints.
813 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
814 HeatTemplate heatTemplate = null;
815 HeatEnvironment heatEnvironment = null;
816 if (isVolumeRequest) {
817 heatTemplate = vf.getVolumeHeatTemplate();
818 heatEnvironment = vfmc.getVolumeHeatEnv();
820 heatTemplate = vf.getModuleHeatTemplate();
821 heatEnvironment = vfmc.getHeatEnvironment();
824 if (heatTemplate == null) {
825 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
826 + ", reqType=" + requestType;
827 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
828 vfModuleType, "OpenStack", ErrorCode.DataError.getValue(), error);
829 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
831 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
834 if (heatEnvironment == null) {
835 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
836 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
837 "OpenStack", ErrorCode.DataError.getValue(), error);
838 // Alarm on this error, configuration must be fixed
839 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
841 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
846 // All variables converted to their native object types
847 HashMap<String, Object> goldenInputs = new HashMap<String, Object>();
848 List<String> extraInputs = new ArrayList<String>();
850 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
851 // This whole section needs to be rewritten.
852 Boolean skipInputChecks = false;
854 if (skipInputChecks) {
855 goldenInputs = new HashMap<String, Object>();
856 for (String key : inputs.keySet()) {
857 goldenInputs.put(key, inputs.get(key));
860 // Build maps for the parameters (including aliases) to simplify checks
861 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
863 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
864 logger.debug("paramSet has {} entries", paramSet.size());
866 for (HeatTemplateParam htp : paramSet) {
867 params.put(htp.getParamName(), htp);
870 String alias = htp.getParamAlias();
871 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
872 params.put(alias, htp);
876 // First, convert all inputs to their "template" type
877 for (String key : inputs.keySet()) {
878 if (params.containsKey(key)) {
879 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
881 goldenInputs.put(key, value);
883 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
884 + params.get(key).getParamType());
887 extraInputs.add(key);
891 if (!extraInputs.isEmpty()) {
892 logger.debug("Ignoring extra inputs: " + extraInputs);
895 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
896 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
897 for (String key : volumeGroupOutputs.keySet()) {
898 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
899 goldenInputs.put(key, volumeGroupOutputs.get(key));
904 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
905 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
906 for (String key : baseModuleOutputs.keySet()) {
907 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
908 goldenInputs.put(key, baseModuleOutputs.get(key));
913 // Last, add in values from the "environment" file.
914 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
916 // TODO: This may take a different form for Cloudify, but for now process it
917 // with Heat environment file syntax
918 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
919 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
921 if (mhee.getParameters() != null) {
922 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
923 // If this is a template input, copy to golden inputs
924 String envKey = envParam.getName();
925 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
926 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
928 goldenInputs.put(envKey, value);
930 logger.debug("Failed to convert environment parameter " + envKey + "='"
931 + envParam.getValue() + "' to " + params.get(envKey).getParamType());
937 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
940 // Check that required parameters have been supplied from any of the sources
941 String missingParams = null;
942 boolean checkRequiredParameters = true;
944 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
945 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
946 checkRequiredParameters = false;
947 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
948 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
950 } catch (Exception e) {
951 // No problem - default is true
952 logger.debug("An exception occured trying to get property {}",
953 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
957 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
958 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
959 logger.debug("adding to missing parameters list: {}", parm.getParamName());
960 if (missingParams == null) {
961 missingParams = parm.getParamName();
963 missingParams += "," + parm.getParamName();
968 if (missingParams != null) {
969 if (checkRequiredParameters) {
970 // Problem - missing one or more required parameters
971 String error = "Create VFModule: Missing Required inputs: " + missingParams;
972 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, CLOUDIFY,
973 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
975 throw new VnfException(error, MsoExceptionCategory.USERDATA);
977 logger.debug("found missing parameters [" + missingParams
978 + "] - but checkRequiredParameters is false -" + " will not block");
981 logger.debug("No missing parameters found - ok to proceed");
984 } // NOTE: END PARAMETER CHECKING
986 // Ready to deploy the VF Module.
987 // *First step - make sure the blueprint is loaded into Cloudify.
988 String blueprintName = heatTemplate.getTemplateName();
989 String blueprint = heatTemplate.getTemplateBody();
990 String blueprintId = blueprintName;
992 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
993 if (blueprintId.endsWith(".yaml"))
994 blueprintId = blueprintId.substring(0, blueprintId.lastIndexOf(".yaml"));
997 if (!cloudifyUtils.isBlueprintLoaded(cloudSiteId, blueprintId)) {
998 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
1000 Map<String, byte[]> blueprintFiles = new HashMap<String, byte[]>();
1002 blueprintFiles.put(blueprintName, blueprint.getBytes());
1004 // TODO: Implement nested blueprint logic based on Cloudify structures.
1005 // For now, just use the Heat structures.
1006 // The query returns a map of String->Object, where the map keys provide one layer of
1007 // indirection from the Heat template names. For this case, assume the map key matches
1008 // the nested blueprint name.
1009 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1010 if (nestedBlueprints != null) {
1011 for (HeatTemplate nestedBlueprint : nestedBlueprints) {
1012 blueprintFiles.put(nestedBlueprint.getTemplateName(),
1013 nestedBlueprint.getTemplateBody().getBytes());
1017 // TODO: Implement file artifact logic based on Cloudify structures.
1018 // For now, just use the Heat structures.
1019 List<HeatFiles> heatFiles = vf.getHeatFiles();
1020 if (heatFiles != null) {
1021 for (HeatFiles heatFile : heatFiles) {
1022 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1026 // Upload the blueprint package
1027 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1032 catch (MsoException me) {
1033 me.addContext("CreateVFModule");
1034 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1035 logger.error("{} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1036 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1037 "MsoException - uploadBlueprint", me);
1038 logger.debug(error);
1039 throw new VnfException(me);
1042 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1043 // because we already checked for those.
1044 long createDeploymentStarttime = System.currentTimeMillis();
1046 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1047 // Go directly to Keystone until APIs could be updated to supply the name.
1048 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1049 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
1051 if (backout == null) {
1055 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment(cloudSiteId, tenantName, vfModuleName,
1056 blueprintId, goldenInputs, true, heatTemplate.getTimeoutMinutes(), backout.booleanValue());
1058 } catch (MsoException me) {
1059 me.addContext("CreateVFModule");
1060 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1061 + tenantId + ": " + me;
1062 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1063 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1064 "MsoException - createDeployment", me);
1065 logger.debug(error);
1066 throw new VnfException(me);
1067 } catch (NullPointerException npe) {
1068 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1069 + tenantId + ": " + npe;
1070 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1071 cloudOwner, cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1072 "NullPointerException - createDeployment", npe);
1073 logger.debug(error);
1074 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1075 // npe.addContext ("CreateVNF");
1076 throw new VnfException("NullPointerException during cloudify.createAndInstallDeployment");
1077 } catch (Exception e) {
1078 logger.debug("unhandled exception at cloudify.createAndInstallDeployment");
1079 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1081 } catch (Exception e) {
1082 logger.debug("unhandled exception in create VF");
1083 throw new VnfException("Exception during create VF " + e.getMessage());
1087 // Reach this point if create is successful.
1088 // Populate remaining rollback info and response parameters.
1089 vfRollback.setVnfCreated(true);
1090 vfRollback.setVnfId(cloudifyDeployment.getId());
1091 vnfId.value = cloudifyDeployment.getId();
1092 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
1094 rollback.value = vfRollback;
1096 logger.debug("VF Module successfully created", vfModuleName);
1100 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1101 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1102 logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1103 // Will capture execution time for metrics
1104 long startTime = System.currentTimeMillis();
1106 // 1702 capture the output parameters on a delete
1107 // so we'll need to query first
1108 DeploymentInfo deployment = null;
1110 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1111 } catch (MsoException me) {
1112 // Failed to query the deployment. Convert to a generic VnfException
1113 me.addContext("DeleteVFModule");
1114 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1115 + "/" + tenantId + ": " + me;
1116 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1117 cloudSiteId, tenantId, CLOUDIFY, "QueryDeployment", ErrorCode.DataError.getValue(),
1118 "Exception - QueryDeployment", me);
1119 logger.debug(error);
1120 throw new VnfException(me);
1122 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1124 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1126 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1127 // The possible outcomes of deleteStack are a StackInfo object with status
1128 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1130 long subStartTime = System.currentTimeMillis();
1132 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1133 } catch (MsoException me) {
1134 me.addContext("DeleteVfModule");
1135 // Convert to a generic VnfException
1137 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1138 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner,
1139 cloudSiteId, tenantId, "DeleteDeployment", "DeleteDeployment", ErrorCode.DataError.getValue(),
1140 "Exception - DeleteDeployment: " + me.getMessage());
1141 logger.debug(error);
1142 throw new VnfException(me);
1145 // On success, nothing is returned.
1149 // TODO: Should Update be supported for Cloudify? What would this look like?
1151 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1152 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1153 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1154 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1155 throws VnfException {
1156 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1157 logger.debug("Update VF Module command attempted but not supported");
1158 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);