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 DeploymentInfo deployment = null;
182 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
183 } catch (MsoCloudifyManagerNotFound e) {
184 // This site does not have a Cloudify Manager.
185 // This isn't an error, just means we won't find the VNF here.
187 } catch (MsoException me) {
188 // Failed to query the Deployment due to a cloudify exception.
189 logger.debug("Failed to query the Deployment due to a cloudify exception");
190 // Convert to a generic VnfException
191 me.addContext("QueryVNF");
192 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
194 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
195 CLOUDIFY, "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryDeployment", me);
197 throw new VnfException(me);
200 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
201 vnfExists.value = Boolean.TRUE;
202 status.value = deploymentStatusToVnfStatus(deployment);
203 vnfId.value = deployment.getId();
204 outputs.value = copyStringOutputs(deployment.getOutputs());
206 logger.debug("VNF {} found in Cloudify, ID = {}", vnfName, vnfId.value);
208 vnfExists.value = Boolean.FALSE;
209 status.value = VnfStatus.NOTFOUND;
211 outputs.value = new HashMap<String, String>(); // Return as an empty map
213 logger.debug("VNF {} not found", vnfName);
219 * This is the "Delete VNF" web service implementation. This function is now unsupported and will return an error.
223 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
224 throws VnfException {
226 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
227 logger.debug("DeleteVNF command attempted but not supported");
228 throw new VnfException("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
232 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
233 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
234 * to undo the creation.
236 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, but APIs were apparently never updated.
239 public void rollbackVnf(VnfRollback rollback) throws VnfException {
240 // rollback may be null (e.g. if stack already existed when Create was called)
241 if (rollback == null) {
242 logger.info(LoggingAnchor.THREE, MessageEnum.RA_ROLLBACK_NULL.toString(), OPENSTACK, "rollbackVnf");
246 // Don't rollback if nothing was done originally
247 if (!rollback.getVnfCreated()) {
251 // Get the elements of the VnfRollback object for easier access
252 String cloudSiteId = rollback.getCloudSiteId();
253 String cloudOwner = rollback.getCloudOwner();
254 String tenantId = rollback.getTenantId();
255 String vfModuleId = rollback.getVfModuleStackId();
257 logger.debug("Rolling Back VF Module {} in {}", vfModuleId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
259 DeploymentInfo deployment = null;
261 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
262 // The possible outcomes of deleteStack are a StackInfo object with status
263 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
266 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
267 // Go directly to Keystone until APIs could be updated to supply the name.
268 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
269 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
271 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object
273 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
274 logger.debug("Rolled back deployment: {}", deployment.getId());
275 } catch (MsoException me) {
276 // Failed to rollback the VNF due to a cloudify exception.
277 // Convert to a generic VnfException
278 me.addContext("RollbackVNF");
279 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/"
280 + tenantId + ": " + me;
281 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vfModuleId, cloudOwner, cloudSiteId,
282 tenantId, CLOUDIFY, "DeleteDeployment", ErrorCode.DataError.getValue(),
283 "Exception - DeleteDeployment", me);
285 throw new VnfException(me);
290 private VnfStatus deploymentStatusToVnfStatus(DeploymentInfo deployment) {
291 // Determine the status based on last action & status
292 // DeploymentInfo object should be enhanced to report a better status internally.
293 DeploymentStatus status = deployment.getStatus();
294 String lastAction = deployment.getLastAction();
296 if (status == null || lastAction == null) {
297 return VnfStatus.UNKNOWN;
298 } else if (status == DeploymentStatus.NOTFOUND) {
299 return VnfStatus.NOTFOUND;
300 } else if (status == DeploymentStatus.INSTALLED) {
301 return VnfStatus.ACTIVE;
302 } else if (status == DeploymentStatus.CREATED) {
303 // Should have an INACTIVE status for this case. Shouldn't really happen, but
304 // Install was never run, or Uninstall was done but deployment didn't get deleted.
305 return VnfStatus.UNKNOWN;
306 } else if (status == DeploymentStatus.FAILED) {
307 return VnfStatus.FAILED;
310 return VnfStatus.UNKNOWN;
313 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
314 Map<String, String> stringOutputs = new HashMap<>();
315 for (Map.Entry<String, Object> entry : stackOutputs.entrySet()) {
316 if (entry.getValue() instanceof String) {
317 stringOutputs.put(entry.getKey(), (String) entry.getValue());
318 } else if (entry.getValue() instanceof Integer) {
320 String str = "" + entry.getValue();
321 stringOutputs.put(entry.getKey(), str);
322 } catch (Exception e) {
323 logger.error("Unable to add " + entry.getKey() + " to outputs", e);
325 } else if (entry.getValue() instanceof JsonNode) {
327 String str = this.convertNode((JsonNode) entry.getValue());
328 stringOutputs.put(entry.getKey(), str);
329 } catch (Exception e) {
330 logger.error("Unable to add " + entry.getKey() + " to outputs - exception converting JsonNode", e);
332 } else if (entry.getValue() instanceof java.util.LinkedHashMap) {
334 String str = JSON_MAPPER.writeValueAsString(entry.getValue());
335 stringOutputs.put(entry.getKey(), str);
336 } catch (Exception e) {
337 logger.error("Unable to add " + entry.getKey() + " to outputs - exception converting LinkedHashMap",
342 String str = entry.getValue().toString();
343 stringOutputs.put(entry.getKey(), str);
344 } catch (Exception e) {
345 logger.error("Unable to add " + entry.getKey() + " to outputs - unable to call .toString() ", e);
349 return stringOutputs;
353 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
355 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
356 if (inputs == null) {
358 } else if (inputs.size() < 1) {
359 sb.append("\tEMPTY");
361 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
364 outputString = entry.getValue().toString();
365 } catch (Exception e) {
366 outputString = "Unable to call toString() on the value for " + entry.getKey();
368 sb.append("\t\nitem " + i++ + ": '" + entry.getKey() + "'='" + outputString + "'");
371 logger.debug(sb.toString());
374 private void sendMapToDebug(Map<String, Object> inputs) {
376 StringBuilder sb = new StringBuilder("inputs:");
377 if (inputs == null) {
379 } else if (inputs.size() < 1) {
380 sb.append("\tEMPTY");
382 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
383 sb.append("\titem " + i++ + ": " + entry.getKey() + "=" + entry.getValue());
386 logger.debug(sb.toString());
389 private String convertNode(final JsonNode node) {
391 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
392 final String json = JSON_MAPPER.writeValueAsString(obj);
394 } catch (JsonParseException jpe) {
395 logger.error("Error converting json to string ", jpe);
396 } catch (Exception e) {
397 logger.error("Error converting json to string ", e);
399 return "[Error converting json to string]";
402 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
403 if (objectMap == null) {
406 Map<String, String> stringMap = new HashMap<>();
407 for (Map.Entry<String, Object> entry : objectMap.entrySet()) {
408 if (!stringMap.containsKey(entry.getKey())) {
409 Object obj = entry.getValue();
410 if (obj instanceof String) {
411 stringMap.put(entry.getKey(), (String) entry.getValue());
412 } else if (obj instanceof JsonNode) {
413 // This is a bit of mess - but I think it's the least impacting
414 // let's convert it BACK to a string - then it will get converted back later
416 String str = this.convertNode((JsonNode) obj);
417 stringMap.put(entry.getKey(), str);
418 } catch (Exception e) {
419 logger.error("DANGER WILL ROBINSON: unable to convert value for JsonNode " + entry.getKey(), e);
420 // okay in this instance - only string values (fqdn) are expected to be needed
422 } else if (obj instanceof java.util.LinkedHashMap) {
423 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
425 String str = JSON_MAPPER.writeValueAsString(obj);
426 stringMap.put(entry.getKey(), str);
427 } catch (Exception e) {
429 "DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + entry.getKey(), e);
431 } else if (obj instanceof Integer) {
433 String str = "" + obj;
434 stringMap.put(entry.getKey(), str);
435 } catch (Exception e) {
436 logger.error("DANGER WILL ROBINSON: unable to convert value for Integer " + entry.getKey(), e);
440 String str = obj.toString();
441 stringMap.put(entry.getKey(), str);
442 } catch (Exception e) {
443 logger.error("DANGER WILL ROBINSON: unable to convert value " + entry.getKey(), e);
453 * This is the "Create VF Module" web service implementation. It will instantiate a new VF Module of the requested
454 * type in the specified cloud and tenant. The tenant must exist before this service is called.
456 * If a VF Module with the same name already exists, this can be considered a success or failure, depending on the
457 * value of the 'failIfExists' parameter.
459 * All VF Modules are defined in the MSO catalog. The caller must request one of the pre-defined module types or an
460 * error will be returned. Within the catalog, each VF Module references (among other things) a cloud template which
461 * is used to deploy the required artifacts (VMs, networks, etc.) to the cloud. In this adapter implementation, that
462 * artifact is expected to be a Cloudify blueprint.
464 * Depending on the blueprint, a variable set of input parameters will be defined, some of which are required. The
465 * caller is responsible to pass the necessary input data for the module or an error will be thrown.
467 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback object. This last object can be
468 * passed as-is to the rollbackVnf operation to undo everything that was created for the Module. This is useful if a
469 * VF module is successfully created but the orchestration fails on a subsequent step.
471 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
472 * @param cloudOwner cloud owner of the cloud site in which to create the VNF
473 * @param tenantId Openstack tenant identifier
474 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. Deprecated - should use
475 * modelCustomizationUuid
476 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB Deprecated - VF Module versions
477 * also captured by modelCustomizationUuid
478 * @param genericVnfId Generic VNF ID
479 * @param vfModuleName Name to be assigned to the new VF Module
480 * @param vfModuleId Id of the new VF Module
481 * @param requestType Indicates if this is a Volume Group or Module request
482 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group to attach to a VF Module
483 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if this is an Add-on module
484 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces the use of vfModuleType.
485 * @param inputs Map of key=value inputs for VNF stack creation
486 * @param failIfExists Flag whether already existing VNF should be considered
487 * @param backout Flag whether to suppress automatic backout (for testing)
488 * @param msoRequest Request tracking information for logs
489 * @param vnfId Holder for output VNF Cloudify Deployment ID
490 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
491 * @param rollback Holder for returning VnfRollback object
494 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleType,
495 String vnfVersion, String genericVnfId, String vfModuleName, String vfModuleId, String requestType,
496 String volumeGroupId, String baseVfModuleId, String modelCustomizationUuid, Map<String, Object> inputs,
497 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
498 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
500 // Require a model customization ID. Every VF Module definition must have one.
501 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
502 logger.debug("Missing required input: modelCustomizationUuid");
503 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
504 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
505 "VF Module ModelCustomizationUuid", CLOUDIFY, ErrorCode.DataError.getValue(),
506 "Create VF Module: Missing required input: modelCustomizationUuid");
508 throw new VnfException(error, MsoExceptionCategory.USERDATA);
511 // Clean up some inputs to make comparisons easier
512 if (requestType == null)
515 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
516 volumeGroupId = null;
518 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
519 baseVfModuleId = null;
521 if (inputs == null) {
522 // Create an empty set of inputs
523 inputs = new HashMap<>();
524 logger.debug("inputs == null - setting to empty");
526 this.sendMapToDebug(inputs);
529 // Check if this is for a "Volume" module
530 boolean isVolumeRequest = false;
531 if (requestType.startsWith("VOLUME")) {
532 isVolumeRequest = true;
535 logger.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = "
538 // Build a default rollback object (no actions performed)
539 VnfRollback vfRollback = new VnfRollback();
540 vfRollback.setCloudSiteId(cloudSiteId);
541 vfRollback.setCloudOwner(cloudOwner);
542 vfRollback.setTenantId(tenantId);
543 vfRollback.setMsoRequest(msoRequest);
544 vfRollback.setRequestType(requestType);
545 vfRollback.setIsBase(false); // Until we know better
546 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
547 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
548 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
549 vfRollback.setMode("CFY");
551 rollback.value = vfRollback; // Default rollback - no updates performed
553 // Get the VNF/VF Module definition from the Catalog DB first.
554 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
557 VnfResource vnfResource = null;
558 VfModuleCustomization vfmc = null;
561 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
564 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid="
565 + modelCustomizationUuid;
567 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
568 "VF Module " + "ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb",
569 ErrorCode.DataError.getValue(), error);
570 throw new VnfException(error, MsoExceptionCategory.USERDATA);
572 logger.debug("Found vfModuleCust entry " + vfmc.toString());
575 // Get the vfModule and vnfResource records
576 vf = vfmc.getVfModule();
577 vnfResource = vfmc.getVfModule().getVnfResources();
578 } catch (Exception e) {
580 logger.error("unhandled exception in create VF - [Query]", e);
581 throw new VnfException("Exception during create VF " + e.getMessage());
584 // Perform a version check against cloudSite
585 // Obtain the cloud site information where we will create the VF Module
586 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId);
587 if (!cloudSiteOp.isPresent()) {
588 throw new VnfException(new MsoCloudSiteNotFound(cloudSiteId));
590 CloudSite cloudSite = cloudSiteOp.get();
591 MavenLikeVersioning aicV = new MavenLikeVersioning();
592 aicV.setVersion(cloudSite.getCloudVersion());
594 String vnfMin = vnfResource.getAicVersionMin();
595 String vnfMax = vnfResource.getAicVersionMax();
597 if ((vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin)))
598 || (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) {
600 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
601 + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax
602 + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
603 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK,
604 ErrorCode.BusinessProcessError.getValue(), "Exception - setVersion");
606 throw new VnfException(error, MsoExceptionCategory.USERDATA);
611 DeploymentInfo cloudifyDeployment = null;
613 // First, look up to see if the VF already exists.
616 cloudifyDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vfModuleName);
617 } catch (MsoException me) {
618 // Failed to query the Deployment due to a cloudify exception.
619 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
620 + tenantId + ": " + me;
621 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudSiteId,
622 tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
623 "Exception - queryDeployment", me);
626 // Convert to a generic VnfException
627 me.addContext("CreateVFModule");
628 throw new VnfException(me);
631 // More precise handling/messaging if the Module already exists
632 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus() == DeploymentStatus.NOTFOUND)) {
633 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
634 DeploymentStatus status = cloudifyDeployment.getStatus();
635 logger.debug("Found Existing Deployment, status=" + status);
637 if (status == DeploymentStatus.INSTALLED) {
639 if (failIfExists != null && failIfExists) {
640 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudOwner + "/"
641 + cloudSiteId + "/" + tenantId;
642 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
643 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
644 "Deployment " + vfModuleName + " already exists");
646 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId,
647 cloudifyDeployment.getId());
649 // Found existing deployment and client has not requested "failIfExists".
650 // Populate the outputs from the existing deployment.
652 vnfId.value = cloudifyDeployment.getId();
653 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
657 // Check through various detailed error cases
658 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
659 // fail - it's in progress - return meaningful error
660 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
661 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
662 + "; please wait for it to complete, or fix manually.";
663 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
664 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
665 "Deployment " + vfModuleName + " already exists");
667 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
668 } else if (status == DeploymentStatus.FAILED) {
669 // fail - it exists and is in a FAILED state
670 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in "
671 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
672 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
673 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
674 "Deployment " + vfModuleName + " already " + "exists and is in FAILED state");
676 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
677 } else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
678 // fail - it exists and is in a UNKNOWN state
679 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status "
680 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
681 + "; requires manual intervention.";
682 logger.error(BRACKETS, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
683 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", ErrorCode.DataError.getValue(),
684 "Deployment " + vfModuleName + " already " + "exists and is in " + status.toString()
687 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
689 // Unexpected, since all known status values have been tested for
690 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected 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 an unknown state");
697 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, cloudOwner, tenantId, cloudifyDeployment.getId());
702 // Collect outputs from Base Modules and Volume Modules
703 Map<String, Object> baseModuleOutputs = null;
704 Map<String, Object> volumeGroupOutputs = null;
706 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
707 if (volumeGroupId != null) {
708 DeploymentInfo volumeDeployment = null;
710 volumeDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, volumeGroupId);
711 } catch (MsoException me) {
712 // Failed to query the Volume GroupDeployment due to a cloudify exception.
713 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudOwner + "/"
714 + cloudSiteId + "/" + tenantId + ": " + me;
715 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner, cloudSiteId,
716 tenantId, CLOUDIFY, "queryDeployment(volume)", ErrorCode.DataError.getValue(),
717 "Exception - queryDeployment(volume)", me);
719 // Convert to a generic VnfException
720 me.addContext("CreateVFModule(QueryVolume)");
721 throw new VnfException(me);
724 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
725 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in "
726 + cloudSiteId + "/" + tenantId + " USER ERROR";
727 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudSiteId, tenantId,
728 error, CLOUDIFY, "queryDeployment(volume)", ErrorCode.BusinessProcessError.getValue(),
729 "Create VFModule: Attached Volume Group DOES NOT EXIST");
731 throw new VnfException(error, MsoExceptionCategory.USERDATA);
733 logger.debug("Found nested volume group");
734 volumeGroupOutputs = volumeDeployment.getOutputs();
735 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
739 // If this is an Add-On Module, query the Base Module outputs
740 // Note: This will be performed whether or not the current request is for an
741 // Add-On Volume Group or Add-On VF Module
743 if (vf.getIsBase()) {
744 logger.debug("This is a BASE Module request");
745 vfRollback.setIsBase(true);
747 logger.debug("This is an Add-On Module request");
749 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
750 // Add-on Volume requests may or may not specify a base.
751 if (!isVolumeRequest && baseVfModuleId == null) {
752 logger.debug("WARNING: Add-on Module request - no Base Module ID provided");
755 if (baseVfModuleId != null) {
756 DeploymentInfo baseDeployment = null;
758 baseDeployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, baseVfModuleId);
759 } catch (MsoException me) {
760 // Failed to query the Volume GroupDeployment due to a cloudify exception.
761 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudOwner + "/"
762 + cloudSiteId + "/" + tenantId + ": " + me;
763 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudOwner,
764 cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)", ErrorCode.DataError.getValue(),
765 "Exception - queryDeployment(Base)", me);
767 // Convert to a generic VnfException
768 me.addContext("CreateVFModule(QueryBase)");
769 throw new VnfException(me);
772 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
773 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in "
774 + cloudSiteId + "/" + tenantId + " USER ERROR";
775 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudSiteId,
776 tenantId, error, CLOUDIFY, "queryDeployment(Base)",
777 ErrorCode.BusinessProcessError.getValue(),
778 "Create VFModule: Base " + "Module DOES NOT EXIST");
780 throw new VnfException(error, MsoExceptionCategory.USERDATA);
782 logger.debug("Found base module");
783 baseModuleOutputs = baseDeployment.getOutputs();
784 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
790 // Ready to deploy the new VNF
792 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
793 // In final implementation (post-POC), the template object would either be generic or there would
794 // be a separate DB Table/Object for Blueprints.
797 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
798 HeatTemplate heatTemplate = null;
799 HeatEnvironment heatEnvironment = null;
800 if (isVolumeRequest) {
801 heatTemplate = vf.getVolumeHeatTemplate();
802 heatEnvironment = vfmc.getVolumeHeatEnv();
804 heatTemplate = vf.getModuleHeatTemplate();
805 heatEnvironment = vfmc.getHeatEnvironment();
808 if (heatTemplate == null) {
809 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
810 + ", modelCustomizationUuid=" + modelCustomizationUuid + ", vfModuleUuid=" + vf.getModelUUID()
811 + ", reqType=" + requestType;
812 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
813 vfModuleType, OPENSTACK, ErrorCode.DataError.getValue(), error);
814 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
816 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
819 if (heatEnvironment == null) {
820 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + ", modelCustomizationUuid="
821 + modelCustomizationUuid + ", vfModuleUuid=" + vf.getModelUUID() + ", reqType=" + requestType;
822 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
823 OPENSTACK, ErrorCode.DataError.getValue(), error);
824 // Alarm on this error, configuration must be fixed
825 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
827 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
832 // All variables converted to their native object types
833 HashMap<String, Object> goldenInputs = new HashMap<>();
834 List<String> extraInputs = new ArrayList<>();
836 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
837 // This whole section needs to be rewritten.
838 Boolean skipInputChecks = false;
840 if (skipInputChecks) {
841 goldenInputs = new HashMap<>();
842 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
843 goldenInputs.put(entry.getKey(), entry.getValue());
846 // Build maps for the parameters (including aliases) to simplify checks
847 HashMap<String, HeatTemplateParam> params = new HashMap<>();
849 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
850 logger.debug("paramSet has {} entries", paramSet.size());
852 for (HeatTemplateParam htp : paramSet) {
853 params.put(htp.getParamName(), htp);
856 String alias = htp.getParamAlias();
857 if (alias != null && !"".equals(alias) && !params.containsKey(alias)) {
858 params.put(alias, htp);
862 // First, convert all inputs to their "template" type
863 for (String key : inputs.keySet()) {
864 if (params.containsKey(key)) {
865 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
867 goldenInputs.put(key, value);
869 logger.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to "
870 + params.get(key).getParamType());
873 extraInputs.add(key);
877 if (!extraInputs.isEmpty()) {
878 logger.debug("Ignoring extra inputs: " + extraInputs);
881 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
882 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
883 for (Map.Entry<String, Object> entry : volumeGroupOutputs.entrySet()) {
884 if (params.containsKey(entry.getKey()) && !goldenInputs.containsKey(entry.getKey())) {
885 goldenInputs.put(entry.getKey(), entry.getValue());
890 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
891 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
892 for (Map.Entry<String, Object> entry : baseModuleOutputs.entrySet()) {
893 if (params.containsKey(entry.getKey()) && !goldenInputs.containsKey(entry.getKey())) {
894 goldenInputs.put(entry.getKey(), entry.getValue());
899 // Last, add in values from the "environment" file.
900 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
902 // TODO: This may take a different form for Cloudify, but for now process it
903 // with Heat environment file syntax
904 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
905 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry(sb);
907 if (mhee.getParameters() != null) {
908 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
909 // If this is a template input, copy to golden inputs
910 String envKey = envParam.getName();
911 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
912 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
914 goldenInputs.put(envKey, value);
916 logger.debug("Failed to convert environment parameter " + envKey + "='"
917 + envParam.getValue() + "' to " + params.get(envKey).getParamType());
923 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
926 // Check that required parameters have been supplied from any of the sources
927 String missingParams = null;
928 boolean checkRequiredParameters = true;
930 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
931 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
932 checkRequiredParameters = false;
933 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking... {}",
934 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
936 } catch (Exception e) {
937 // No problem - default is true
938 logger.error("An exception occured trying to get property {}",
939 MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
943 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
944 if (parm.isRequired() && (!goldenInputs.containsKey(parm.getParamName()))) {
945 logger.debug("adding to missing parameters list: {}", parm.getParamName());
946 if (missingParams == null) {
947 missingParams = parm.getParamName();
949 missingParams += "," + parm.getParamName();
954 if (missingParams != null) {
955 if (checkRequiredParameters) {
956 // Problem - missing one or more required parameters
957 String error = "Create VFModule: Missing Required inputs: " + missingParams;
958 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams,
959 CLOUDIFY, ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
961 throw new VnfException(error, MsoExceptionCategory.USERDATA);
963 logger.debug("found missing parameters [" + missingParams
964 + "] - but checkRequiredParameters is false -" + " will not block");
967 logger.debug("No missing parameters found - ok to proceed");
970 } // NOTE: END PARAMETER CHECKING
972 // Ready to deploy the VF Module.
973 // *First step - make sure the blueprint is loaded into Cloudify.
974 String blueprintName = heatTemplate.getTemplateName();
975 String blueprint = heatTemplate.getTemplateBody();
976 String blueprintId = blueprintName;
978 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
979 if (blueprintId.endsWith(".yaml"))
980 blueprintId = blueprintId.substring(0, blueprintId.lastIndexOf(".yaml"));
983 if (!cloudifyUtils.isBlueprintLoaded(cloudSiteId, blueprintId)) {
984 logger.debug("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
986 Map<String, byte[]> blueprintFiles = new HashMap<>();
988 blueprintFiles.put(blueprintName, blueprint.getBytes());
990 // TODO: Implement nested blueprint logic based on Cloudify structures.
991 // For now, just use the Heat structures.
992 // The query returns a map of String->Object, where the map keys provide one layer of
993 // indirection from the Heat template names. For this case, assume the map key matches
994 // the nested blueprint name.
995 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
996 if (nestedBlueprints != null) {
997 for (HeatTemplate nestedBlueprint : nestedBlueprints) {
998 blueprintFiles.put(nestedBlueprint.getTemplateName(),
999 nestedBlueprint.getTemplateBody().getBytes());
1003 // TODO: Implement file artifact logic based on Cloudify structures.
1004 // For now, just use the Heat structures.
1005 List<HeatFiles> heatFiles = vf.getHeatFiles();
1006 if (heatFiles != null) {
1007 for (HeatFiles heatFile : heatFiles) {
1008 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1012 // Upload the blueprint package
1013 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1018 catch (MsoException me) {
1019 me.addContext("CreateVFModule");
1020 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1021 logger.error(LoggingAnchor.SEVEN, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudSiteId,
1022 tenantId, CLOUDIFY, ErrorCode.DataError.getValue(), "MsoException - uploadBlueprint", me);
1023 logger.debug(error);
1024 throw new VnfException(me);
1027 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1028 // because we already checked for those.
1030 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1031 // Go directly to Keystone until APIs could be updated to supply the name.
1032 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1033 String tenantName = (msoTenant != null ? msoTenant.getTenantName() : tenantId);
1035 if (backout == null) {
1039 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment(cloudSiteId, tenantName, vfModuleName,
1040 blueprintId, goldenInputs, true, heatTemplate.getTimeoutMinutes(), backout.booleanValue());
1042 } catch (MsoException me) {
1043 me.addContext("CreateVFModule");
1044 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1045 + tenantId + ": " + me;
1046 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1047 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1048 "MsoException - createDeployment", me);
1049 logger.debug(error);
1050 throw new VnfException(me);
1051 } catch (NullPointerException npe) {
1052 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1053 + tenantId + ": " + npe;
1054 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1055 cloudSiteId, tenantId, CLOUDIFY, ErrorCode.DataError.getValue(),
1056 "NullPointerException - createDeployment", npe);
1057 logger.debug(error);
1058 logger.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1059 // npe.addContext ("CreateVNF");
1060 throw new VnfException("NullPointerException during cloudify.createAndInstallDeployment");
1061 } catch (Exception e) {
1062 logger.error("unhandled exception at cloudify.createAndInstallDeployment", e);
1063 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1065 } catch (Exception e) {
1066 logger.error("unhandled exception in create VF", e);
1067 throw new VnfException("Exception during create VF " + e.getMessage());
1071 // Reach this point if create is successful.
1072 // Populate remaining rollback info and response parameters.
1073 vfRollback.setVnfCreated(true);
1074 vfRollback.setVnfId(cloudifyDeployment.getId());
1075 vnfId.value = cloudifyDeployment.getId();
1076 outputs.value = copyStringOutputs(cloudifyDeployment.getOutputs());
1078 rollback.value = vfRollback;
1080 logger.debug("VF Module successfully created {}", vfModuleName);
1084 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, String vnfId,
1085 String vfModuleId, MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1086 logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1088 // 1702 capture the output parameters on a delete
1089 // so we'll need to query first
1090 DeploymentInfo deployment = null;
1092 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1093 } catch (MsoException me) {
1094 // Failed to query the deployment. Convert to a generic VnfException
1095 me.addContext("DeleteVFModule");
1096 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1097 + "/" + tenantId + ": " + me;
1098 logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1099 CLOUDIFY, "QueryDeployment", ErrorCode.DataError.getValue(), "Exception - QueryDeployment", me);
1100 logger.debug(error);
1101 throw new VnfException(me);
1103 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1105 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1107 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1108 // The possible outcomes of deleteStack are a StackInfo object with status
1109 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1112 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1113 } catch (MsoException me) {
1114 me.addContext("DeleteVfModule");
1115 // Convert to a generic VnfException
1117 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1118 logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId, tenantId,
1119 "DeleteDeployment", "DeleteDeployment", ErrorCode.DataError.getValue(),
1120 "Exception - DeleteDeployment: " + me.getMessage());
1121 logger.debug(error);
1122 throw new VnfException(me);
1125 // On success, nothing is returned.
1129 // TODO: Should Update be supported for Cloudify? What would this look like?
1131 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1132 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1133 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1134 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1135 throws VnfException {
1136 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1137 logger.debug("Update VF Module command attempted but not supported");
1138 throw new VnfException("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);