2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (C) 2018 IBM.
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
23 package org.onap.so.adapters.vnf;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Optional;
33 import javax.jws.WebService;
34 import javax.xml.ws.Holder;
36 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
37 import org.onap.so.adapters.vnf.exceptions.VnfException;
38 import org.onap.so.cloud.CloudConfig;
39 import org.onap.so.db.catalog.beans.CloudSite;
40 import org.onap.so.cloudify.beans.DeploymentInfo;
41 import org.onap.so.cloudify.beans.DeploymentStatus;
42 import org.onap.so.cloudify.exceptions.MsoCloudifyManagerNotFound;
43 import org.onap.so.cloudify.utils.MsoCloudifyUtils;
44 import org.onap.so.db.catalog.beans.HeatEnvironment;
45 import org.onap.so.db.catalog.beans.HeatFiles;
46 import org.onap.so.db.catalog.beans.HeatTemplate;
47 import org.onap.so.db.catalog.beans.HeatTemplateParam;
48 import org.onap.so.db.catalog.beans.VfModule;
49 import org.onap.so.db.catalog.beans.VfModuleCustomization;
50 import org.onap.so.db.catalog.beans.VnfResource;
51 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
52 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
53 import org.onap.so.entity.MsoRequest;
54 import org.onap.so.logger.MessageEnum;
56 import org.onap.so.logger.MsoLogger;
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.springframework.beans.factory.annotation.Autowired;
67 import org.springframework.core.env.Environment;
68 import org.springframework.stereotype.Component;
70 import com.fasterxml.jackson.core.JsonParseException;
71 import com.fasterxml.jackson.databind.JsonNode;
72 import com.fasterxml.jackson.databind.ObjectMapper;
73 import org.springframework.transaction.annotation.Transactional;
77 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf")
78 public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter {
80 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
81 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
82 private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN.";
83 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfCloudifyAdapterImpl.class);
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;
107 * Health Check web method. Does nothing but return to show the adapter is deployed.
110 public void healthCheck () {
111 LOGGER.debug ("Health check call in VNF Cloudify Adapter");
115 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
116 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
118 public MsoVnfCloudifyAdapterImpl() {
123 * This is the "Create VNF" web service implementation.
124 * This function is now unsupported and will return an error.
128 public void createVnf (String cloudSiteId,
134 String volumeGroupHeatStackId,
135 Map <String, Object> inputs,
136 Boolean failIfExists,
138 Boolean enableBridge,
139 MsoRequest msoRequest,
140 Holder <String> vnfId,
141 Holder <Map <String, String>> outputs,
142 Holder <VnfRollback> rollback)
145 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
146 LOGGER.debug ("CreateVNF command attempted but not supported");
147 throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
151 * This is the "Update VNF" web service implementation.
152 * This function is now unsupported and will return an error.
156 public void updateVnf (String cloudSiteId,
162 String volumeGroupHeatStackId,
163 Map <String, Object> inputs,
164 MsoRequest msoRequest,
165 Holder <Map <String, String>> outputs,
166 Holder <VnfRollback> rollback)
169 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
170 LOGGER.debug ("UpdateVNF command attempted but not supported");
171 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
175 * This is the "Query VNF" web service implementation.
177 * This really should be QueryVfModule, but nobody ever changed it.
179 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same
180 * as deployment name, since it assigned by the client when a deployment is created.
181 * Also, the input cloudSiteId is used only to identify which Cloudify instance to query,
182 * and the tenantId is ignored (since that really only applies for Openstack/Heat).
184 * The method returns an indicator that the VNF exists, along with its status and outputs.
185 * The input "vnfName" will also be reflected back as its ID.
187 * @param cloudSiteId CLLI code of the cloud site in which to query
188 * @param tenantId Openstack tenant identifier - ignored for Cloudify
189 * @param vnfName VNF Name (should match a deployment ID)
190 * @param msoRequest Request tracking information for logs
191 * @param vnfExists Flag reporting the result of the query
192 * @param vnfId Holder for output VNF ID
193 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
196 public void queryVnf (String cloudSiteId,
199 MsoRequest msoRequest,
200 Holder <Boolean> vnfExists,
201 Holder <String> vnfId,
202 Holder <VnfStatus> status,
203 Holder <Map <String, String>> outputs)
206 MsoLogger.setLogContext (msoRequest);
207 MsoLogger.setServiceName ("QueryVnfCloudify");
208 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
210 // Will capture execution time for metrics
211 long startTime = System.currentTimeMillis ();
212 long subStartTime = System.currentTimeMillis ();
214 DeploymentInfo deployment = null;
217 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
218 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, CLOUDIFY_RESPONSE_SUCCESS, CLOUDIFY, "QueryDeployment", vnfName);
220 catch (MsoCloudifyManagerNotFound e) {
221 // This site does not have a Cloudify Manager.
222 // This isn't an error, just means we won't find the VNF here.
225 catch (MsoException me) {
226 // Failed to query the Deployment due to a cloudify exception.
227 // Convert to a generic VnfException
228 me.addContext ("QueryVNF");
229 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
230 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "QueryDeployment", vnfName);
231 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, CLOUDIFY, "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me);
232 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
233 throw new VnfException (me);
236 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
237 vnfExists.value = Boolean.TRUE;
238 status.value = deploymentStatusToVnfStatus(deployment);
239 vnfId.value = deployment.getId();
240 outputs.value = copyStringOutputs (deployment.getOutputs ());
242 LOGGER.debug ("VNF " + vnfName + " found in Cloudify, ID = " + vnfId.value);
245 vnfExists.value = Boolean.FALSE;
246 status.value = VnfStatus.NOTFOUND;
248 outputs.value = new HashMap <String, String> (); // Return as an empty map
250 LOGGER.debug ("VNF " + vnfName + " not found");
252 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
258 * This is the "Delete VNF" web service implementation.
259 * This function is now unsupported and will return an error.
263 public void deleteVnf (String cloudSiteId,
266 MsoRequest msoRequest) throws VnfException {
267 MsoLogger.setLogContext (msoRequest);
268 MsoLogger.setServiceName ("DeleteVnf");
270 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
271 LOGGER.debug ("DeleteVNF command attempted but not supported");
272 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
276 * This web service endpoint will rollback a previous Create VNF operation.
277 * A rollback object is returned to the client in a successful creation
278 * response. The client can pass that object as-is back to the rollbackVnf
279 * operation to undo the creation.
281 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
282 * but APIs were apparently never updated.
285 public void rollbackVnf (VnfRollback rollback) throws VnfException {
286 long startTime = System.currentTimeMillis ();
287 MsoLogger.setServiceName ("RollbackVnf");
288 // rollback may be null (e.g. if stack already existed when Create was called)
289 if (rollback == null) {
290 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf", MsoLogger.getServiceName());
291 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
295 // Don't rollback if nothing was done originally
296 if (!rollback.getVnfCreated()) {
297 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back");
301 // Get the elements of the VnfRollback object for easier access
302 String cloudSiteId = rollback.getCloudSiteId ();
303 String tenantId = rollback.getTenantId ();
304 String vfModuleId = rollback.getVfModuleStackId ();
306 MsoLogger.setLogContext (rollback.getMsoRequest());
308 LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
310 DeploymentInfo deployment = null;
312 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
313 // The possible outcomes of deleteStack are a StackInfo object with status
314 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
316 long subStartTime = System.currentTimeMillis ();
318 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
319 // Go directly to Keystone until APIs could be updated to supply the name.
320 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
321 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
323 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
324 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
325 LOGGER.debug("Rolled back deployment: " + deployment.getId());
326 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, CLOUDIFY_RESPONSE_SUCCESS, CLOUDIFY, "DeleteDeployment", null);
327 } catch (MsoException me) {
328 // Failed to rollback the VNF due to a cloudify exception.
329 // Convert to a generic VnfException
330 me.addContext ("RollbackVNF");
331 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
332 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "DeleteDeployment", null);
333 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, CLOUDIFY, "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment", me);
334 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
335 throw new VnfException (me);
337 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module");
342 private VnfStatus deploymentStatusToVnfStatus (DeploymentInfo deployment) {
343 // Determine the status based on last action & status
344 // DeploymentInfo object should be enhanced to report a better status internally.
345 DeploymentStatus status = deployment.getStatus();
346 String lastAction = deployment.getLastAction();
348 if (status == null || lastAction == null) {
349 return VnfStatus.UNKNOWN;
351 else if (status == DeploymentStatus.NOTFOUND) {
352 return VnfStatus.NOTFOUND;
354 else if (status == DeploymentStatus.INSTALLED) {
355 return VnfStatus.ACTIVE;
357 else if (status == DeploymentStatus.CREATED) {
358 // Should have an INACTIVE status for this case. Shouldn't really happen, but
359 // Install was never run, or Uninstall was done but deployment didn't get deleted.
360 return VnfStatus.UNKNOWN;
362 else if (status == DeploymentStatus.FAILED) {
363 return VnfStatus.FAILED;
366 return VnfStatus.UNKNOWN;
369 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
370 Map <String, String> stringOutputs = new HashMap <String, String> ();
371 for (String key : stackOutputs.keySet ()) {
372 if (stackOutputs.get (key) instanceof String) {
373 stringOutputs.put (key, (String) stackOutputs.get (key));
374 } else if (stackOutputs.get(key) instanceof Integer) {
376 String str = "" + stackOutputs.get(key);
377 stringOutputs.put(key, str);
378 } catch (Exception e) {
379 LOGGER.debug("Unable to add " + key + " to outputs");
381 } else if (stackOutputs.get(key) instanceof JsonNode) {
383 String str = this.convertNode((JsonNode) stackOutputs.get(key));
384 stringOutputs.put(key, str);
385 } catch (Exception e) {
386 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
388 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
390 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
391 stringOutputs.put(key, str);
392 } catch (Exception e) {
393 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
397 String str = stackOutputs.get(key).toString();
398 stringOutputs.put(key, str);
399 } catch (Exception e) {
400 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
404 return stringOutputs;
408 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
410 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
411 if (inputs == null) {
414 else if (inputs.size() < 1) {
415 sb.append("\tEMPTY");
417 for (String str : inputs.keySet()) {
420 outputString = inputs.get(str).toString();
421 } catch (Exception e) {
422 outputString = "Unable to call toString() on the value for " + str;
424 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
427 LOGGER.debug(sb.toString());
431 private void sendMapToDebug(Map<String, Object> inputs) {
433 StringBuilder sb = new StringBuilder("inputs:");
434 if (inputs == null) {
437 else if (inputs.size() < 1) {
438 sb.append("\tEMPTY");
440 for (String str : inputs.keySet()) {
441 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
444 LOGGER.debug(sb.toString());
448 private String convertNode(final JsonNode node) {
450 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
451 final String json = JSON_MAPPER.writeValueAsString(obj);
453 } catch (JsonParseException jpe) {
454 LOGGER.debug("Error converting json to string " + jpe.getMessage());
455 } catch (Exception e) {
456 LOGGER.debug("Error converting json to string " + e.getMessage());
458 return "[Error converting json to string]";
461 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
462 if (objectMap == null) {
465 Map<String, String> stringMap = new HashMap<String, String>();
466 for (String key : objectMap.keySet()) {
467 if (!stringMap.containsKey(key)) {
468 Object obj = objectMap.get(key);
469 if (obj instanceof String) {
470 stringMap.put(key, (String) objectMap.get(key));
471 } else if (obj instanceof JsonNode ){
472 // This is a bit of mess - but I think it's the least impacting
473 // let's convert it BACK to a string - then it will get converted back later
475 String str = this.convertNode((JsonNode) obj);
476 stringMap.put(key, str);
477 } catch (Exception e) {
478 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key);
479 //okay in this instance - only string values (fqdn) are expected to be needed
481 } else if (obj instanceof java.util.LinkedHashMap) {
482 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
484 String str = JSON_MAPPER.writeValueAsString(obj);
485 stringMap.put(key, str);
486 } catch (Exception e) {
487 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key);
489 } else if (obj instanceof Integer) {
491 String str = "" + obj;
492 stringMap.put(key, str);
493 } catch (Exception e) {
494 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key);
498 String str = obj.toString();
499 stringMap.put(key, str);
500 } catch (Exception e) {
501 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")");
511 * This is the "Create VF Module" web service implementation.
512 * It will instantiate a new VF Module of the requested type in the specified cloud
513 * and tenant. The tenant must exist before this service is called.
515 * If a VF Module with the same name already exists, this can be considered a
516 * success or failure, depending on the value of the 'failIfExists' parameter.
518 * All VF Modules are defined in the MSO catalog. The caller must request
519 * one of the pre-defined module types or an error will be returned. Within the
520 * catalog, each VF Module references (among other things) a cloud template
521 * which is used to deploy the required artifacts (VMs, networks, etc.)
522 * to the cloud. In this adapter implementation, that artifact is expected
523 * to be a Cloudify blueprint.
525 * Depending on the blueprint, a variable set of input parameters will
526 * be defined, some of which are required. The caller is responsible to
527 * pass the necessary input data for the module or an error will be thrown.
529 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
530 * object. This last object can be passed as-is to the rollbackVnf operation to
531 * undo everything that was created for the Module. This is useful if a VF module
532 * is successfully created but the orchestration fails on a subsequent step.
534 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
535 * @param tenantId Openstack tenant identifier
536 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
537 * Deprecated - should use modelCustomizationUuid
538 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
539 * Deprecated - VF Module versions also captured by modelCustomizationUuid
540 * @param genericVnfId Generic VNF ID
541 * @param vfModuleName Name to be assigned to the new VF Module
542 * @param vfModuleId Id of the new VF Module
543 * @param requestType Indicates if this is a Volume Group or Module request
544 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
545 * to attach to a VF Module
546 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
547 * this is an Add-on module
548 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
549 * the use of vfModuleType.
550 * @param inputs Map of key=value inputs for VNF stack creation
551 * @param failIfExists Flag whether already existing VNF should be considered
552 * @param backout Flag whether to suppress automatic backout (for testing)
553 * @param msoRequest Request tracking information for logs
554 * @param vnfId Holder for output VNF Cloudify Deployment ID
555 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
556 * @param rollback Holder for returning VnfRollback object
559 public void createVfModule(String cloudSiteId,
567 String volumeGroupId,
568 String baseVfModuleId,
569 String modelCustomizationUuid,
570 Map <String, Object> inputs,
571 Boolean failIfExists,
573 Boolean enableBridge,
574 MsoRequest msoRequest,
575 Holder <String> vnfId,
576 Holder <Map <String, String>> outputs,
577 Holder <VnfRollback> rollback)
580 // Will capture execution time for metrics
581 long startTime = System.currentTimeMillis ();
583 MsoLogger.setLogContext (msoRequest);
584 MsoLogger.setServiceName ("CreateVfModule");
586 // Require a model customization ID. Every VF Module definition must have one.
587 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
588 LOGGER.debug("Missing required input: modelCustomizationUuid");
589 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
590 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
591 "VF Module ModelCustomizationUuid", "null", CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid");
592 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
593 throw new VnfException(error, MsoExceptionCategory.USERDATA);
596 // Clean up some inputs to make comparisons easier
597 if (requestType == null)
600 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
601 volumeGroupId = null;
603 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
604 baseVfModuleId = null;
606 if (inputs == null) {
607 // Create an empty set of inputs
608 inputs = new HashMap<>();
609 LOGGER.debug("inputs == null - setting to empty");
611 this.sendMapToDebug(inputs);
614 // Check if this is for a "Volume" module
615 boolean isVolumeRequest = false;
616 if (requestType.startsWith("VOLUME")) {
617 isVolumeRequest = true;
620 LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId);
622 // Build a default rollback object (no actions performed)
623 VnfRollback vfRollback = new VnfRollback();
624 vfRollback.setCloudSiteId(cloudSiteId);
625 vfRollback.setTenantId(tenantId);
626 vfRollback.setMsoRequest(msoRequest);
627 vfRollback.setRequestType(requestType);
628 vfRollback.setIsBase(false); // Until we know better
629 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
630 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
631 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
632 vfRollback.setMode("CFY");
634 rollback.value = vfRollback; // Default rollback - no updates performed
636 // Get the VNF/VF Module definition from the Catalog DB first.
637 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
640 VnfResource vnfResource = null;
641 VfModuleCustomization vfmc = null;
644 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
647 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid;
649 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
650 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error);
651 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
652 throw new VnfException(error, MsoExceptionCategory.USERDATA);
654 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
657 // Get the vfModule and vnfResource records
658 vf = vfmc.getVfModule();
659 vnfResource = vfmc.getVfModule().getVnfResources();
661 catch (Exception e) {
663 LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage());
664 throw new VnfException("Exception during create VF " + e.getMessage());
667 // Perform a version check against cloudSite
668 // Obtain the cloud site information where we will create the VF Module
669 Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId);
670 if (!cloudSiteOp.isPresent()) {
671 throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId));
673 CloudSite cloudSite = cloudSiteOp.get();
674 MavenLikeVersioning aicV = new MavenLikeVersioning();
675 aicV.setVersion(cloudSite.getCloudVersion());
677 String vnfMin = vnfResource.getAicVersionMin();
678 String vnfMax = vnfResource.getAicVersionMax();
680 if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) ||
681 (vnfMax != null && aicV.isMoreRecentThan(vnfMax)))
684 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion();
685 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
687 throw new VnfException(error, MsoExceptionCategory.USERDATA);
692 DeploymentInfo cloudifyDeployment = null;
694 // First, look up to see if the VF already exists.
696 long subStartTime1 = System.currentTimeMillis ();
698 cloudifyDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, vfModuleName);
699 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, CLOUDIFY_RESPONSE_SUCCESS, CLOUDIFY, "QueryDeployment", vfModuleName);
701 catch (MsoException me) {
702 // Failed to query the Deployment due to a cloudify exception.
703 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
704 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me);
705 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "QueryDeployment", vfModuleName);
706 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
708 // Convert to a generic VnfException
709 me.addContext ("CreateVFModule");
710 throw new VnfException (me);
713 // More precise handling/messaging if the Module already exists
714 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus () == DeploymentStatus.NOTFOUND)) {
715 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
716 DeploymentStatus status = cloudifyDeployment.getStatus();
717 LOGGER.debug ("Found Existing Deployment, status=" + status);
719 if (status == DeploymentStatus.INSTALLED) {
721 if (failIfExists != null && failIfExists) {
722 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
723 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists");
724 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
725 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
727 // Found existing deployment and client has not requested "failIfExists".
728 // Populate the outputs from the existing deployment.
730 vnfId.value = cloudifyDeployment.getId();
731 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
732 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)");
736 // Check through various detailed error cases
737 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
738 // fail - it's in progress - return meaningful error
739 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
740 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists");
741 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
742 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
744 else if (status == DeploymentStatus.FAILED) {
745 // fail - it exists and is in a FAILED state
746 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
747 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in FAILED state");
748 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
749 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
751 else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
752 // fail - it exists and is in a UNKNOWN state
753 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
754 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in " + status.toString() + " state");
755 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
756 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
759 // Unexpected, since all known status values have been tested for
760 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
761 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in an unknown state");
762 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
763 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
768 // Collect outputs from Base Modules and Volume Modules
769 Map<String, Object> baseModuleOutputs = null;
770 Map<String, Object> volumeGroupOutputs = null;
772 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
773 if (volumeGroupId != null) {
774 long subStartTime2 = System.currentTimeMillis ();
775 DeploymentInfo volumeDeployment = null;
777 volumeDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, volumeGroupId);
778 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", CLOUDIFY, "QueryDeployment", volumeGroupId);
780 catch (MsoException me) {
781 // Failed to query the Volume GroupDeployment due to a cloudify exception.
782 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
783 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(volume)", me);
784 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "QueryDeployment(volume)", volumeGroupId);
785 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
787 // Convert to a generic VnfException
788 me.addContext ("CreateVFModule(QueryVolume)");
789 throw new VnfException (me);
792 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
793 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
794 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(volume)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached Volume Group DOES NOT EXIST");
795 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
797 throw new VnfException (error, MsoExceptionCategory.USERDATA);
799 LOGGER.debug("Found nested volume group");
800 volumeGroupOutputs = volumeDeployment.getOutputs();
801 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
805 // If this is an Add-On Module, query the Base Module outputs
806 // Note: This will be performed whether or not the current request is for an
807 // Add-On Volume Group or Add-On VF Module
809 if (vf.getIsBase()) {
810 LOGGER.debug("This is a BASE Module request");
811 vfRollback.setIsBase(true);
813 LOGGER.debug("This is an Add-On Module request");
815 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
816 // Add-on Volume requests may or may not specify a base.
817 if (!isVolumeRequest && baseVfModuleId == null) {
818 LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided");
821 if (baseVfModuleId != null) {
822 long subStartTime2 = System.currentTimeMillis ();
823 DeploymentInfo baseDeployment = null;
825 baseDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, baseVfModuleId);
826 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", CLOUDIFY, "QueryDeployment(Base)", baseVfModuleId);
828 catch (MsoException me) {
829 // Failed to query the Volume GroupDeployment due to a cloudify exception.
830 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
831 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, CLOUDIFY, "queryDeployment(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(Base)", me);
832 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "QueryDeployment(Base)", baseVfModuleId);
833 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
835 // Convert to a generic VnfException
836 me.addContext ("CreateVFModule(QueryBase)");
837 throw new VnfException (me);
840 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
841 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
842 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module DOES NOT EXIST");
843 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
845 throw new VnfException (error, MsoExceptionCategory.USERDATA);
847 LOGGER.debug("Found base module");
848 baseModuleOutputs = baseDeployment.getOutputs();
849 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
855 // Ready to deploy the new VNF
857 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
858 // In final implementation (post-POC), the template object would either be generic or there would
859 // be a separate DB Table/Object for Blueprints.
862 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
863 HeatTemplate heatTemplate = null;
864 HeatEnvironment heatEnvironment = null;
865 if (isVolumeRequest) {
866 heatTemplate = vf.getVolumeHeatTemplate();
867 heatEnvironment = vfmc.getVolumeHeatEnv();
869 heatTemplate = vf.getModuleHeatTemplate();
870 heatEnvironment = vfmc.getHeatEnvironment();
873 if (heatTemplate == null) {
874 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType;
875 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
876 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
877 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
879 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
882 if (heatEnvironment == null) {
883 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
884 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
885 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
886 // Alarm on this error, configuration must be fixed
889 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
891 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
896 // All variables converted to their native object types
897 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
898 List<String> extraInputs = new ArrayList<String>();
900 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
901 // This whole section needs to be rewritten.
902 Boolean skipInputChecks = false;
904 if (skipInputChecks) {
905 goldenInputs = new HashMap<String,Object>();
906 for (String key : inputs.keySet()) {
907 goldenInputs.put(key, inputs.get(key));
911 // Build maps for the parameters (including aliases) to simplify checks
912 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
914 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
915 LOGGER.debug("paramSet has " + paramSet.size() + " entries");
917 for (HeatTemplateParam htp : paramSet) {
918 params.put(htp.getParamName(), htp);
921 String alias = htp.getParamAlias();
922 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
923 params.put(alias, htp);
927 // First, convert all inputs to their "template" type
928 for (String key : inputs.keySet()) {
929 if (params.containsKey(key)) {
930 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
932 goldenInputs.put(key, value);
935 LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType());
938 extraInputs.add(key);
942 if (!extraInputs.isEmpty()) {
943 LOGGER.debug("Ignoring extra inputs: " + extraInputs);
946 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
947 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
948 for (String key : volumeGroupOutputs.keySet()) {
949 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
950 goldenInputs.put(key, volumeGroupOutputs.get(key));
955 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
956 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
957 for (String key : baseModuleOutputs.keySet()) {
958 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
959 goldenInputs.put(key, baseModuleOutputs.get(key));
964 // Last, add in values from the "environment" file.
965 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
967 // TODO: This may take a different form for Cloudify, but for now process it
968 // with Heat environment file syntax
969 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
970 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
972 if (mhee.getParameters() != null) {
973 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
974 // If this is a template input, copy to golden inputs
975 String envKey = envParam.getName();
976 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
977 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
979 goldenInputs.put(envKey, value);
982 LOGGER.debug("Failed to convert environment parameter " + envKey + "='" + envParam.getValue() + "' to " + params.get(envKey).getParamType());
988 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
991 // Check that required parameters have been supplied from any of the sources
992 String missingParams = null;
993 boolean checkRequiredParameters = true;
995 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
996 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
997 checkRequiredParameters = false;
998 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
999 + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
1001 } catch (Exception e) {
1002 // No problem - default is true
1003 LOGGER.debug ("An exception occured trying to get property " + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
1007 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1008 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1009 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1010 if (missingParams == null) {
1011 missingParams = parm.getParamName ();
1013 missingParams += "," + parm.getParamName ();
1018 if (missingParams != null) {
1019 if (checkRequiredParameters) {
1020 // Problem - missing one or more required parameters
1021 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1022 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1023 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1024 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1026 LOGGER.debug ("found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - will not block");
1029 LOGGER.debug ("No missing parameters found - ok to proceed");
1032 } // NOTE: END PARAMETER CHECKING
1034 // Ready to deploy the VF Module.
1035 // *First step - make sure the blueprint is loaded into Cloudify.
1036 String blueprintName = heatTemplate.getTemplateName();
1037 String blueprint = heatTemplate.getTemplateBody();
1038 String blueprintId = blueprintName;
1040 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
1041 if (blueprintId.endsWith(".yaml"))
1042 blueprintId = blueprintId.substring(0,blueprintId.lastIndexOf(".yaml"));
1045 if (! cloudifyUtils.isBlueprintLoaded (cloudSiteId, blueprintId)) {
1046 LOGGER.debug ("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
1048 Map<String,byte[]> blueprintFiles = new HashMap<String,byte[]>();
1050 blueprintFiles.put(blueprintName, blueprint.getBytes());
1052 // TODO: Implement nested blueprint logic based on Cloudify structures.
1053 // For now, just use the Heat structures.
1054 // The query returns a map of String->Object, where the map keys provide one layer of
1055 // indirection from the Heat template names. For this case, assume the map key matches
1056 // the nested blueprint name.
1057 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1058 if (nestedBlueprints != null) {
1059 for (HeatTemplate nestedBlueprint: nestedBlueprints) {
1060 blueprintFiles.put(nestedBlueprint.getTemplateName(), nestedBlueprint.getTemplateBody().getBytes());
1064 // TODO: Implement file artifact logic based on Cloudify structures.
1065 // For now, just use the Heat structures.
1066 List<HeatFiles> heatFiles = vf.getHeatFiles();
1067 if (heatFiles != null) {
1068 for (HeatFiles heatFile: heatFiles) {
1069 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1073 // Upload the blueprint package
1074 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1079 catch (MsoException me) {
1080 me.addContext ("CreateVFModule");
1081 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1082 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "MsoException - uploadBlueprint", me);
1083 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1084 throw new VnfException (me);
1088 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1089 // because we already checked for those.
1090 long createDeploymentStarttime = System.currentTimeMillis ();
1092 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1093 // Go directly to Keystone until APIs could be updated to supply the name.
1094 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1095 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
1097 if (backout == null) {
1101 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment (cloudSiteId,
1107 heatTemplate.getTimeoutMinutes (),
1108 backout.booleanValue());
1110 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, CLOUDIFY_RESPONSE_SUCCESS, CLOUDIFY, "CreateDeployment", vfModuleName);
1111 } catch (MsoException me) {
1112 me.addContext ("CreateVFModule");
1113 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1114 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "CreateDeployment", vfModuleName);
1115 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "MsoException - createDeployment", me);
1116 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1117 throw new VnfException (me);
1118 } catch (NullPointerException npe) {
1119 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1120 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "CreateDeployment", vfModuleName);
1121 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "NullPointerException - createDeployment", npe);
1122 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1123 LOGGER.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1124 //npe.addContext ("CreateVNF");
1125 throw new VnfException ("NullPointerException during cloudify.createAndInstallDeployment");
1126 } catch (Exception e) {
1127 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify", CLOUDIFY, "CreateDeployment", vfModuleName);
1128 LOGGER.debug("unhandled exception at cloudify.createAndInstallDeployment");
1129 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify");
1130 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1132 } catch (Exception e) {
1133 LOGGER.debug("unhandled exception in create VF");
1134 throw new VnfException("Exception during create VF " + e.getMessage());
1138 // Reach this point if create is successful.
1139 // Populate remaining rollback info and response parameters.
1140 vfRollback.setVnfCreated (true);
1141 vfRollback.setVnfId (cloudifyDeployment.getId());
1142 vnfId.value = cloudifyDeployment.getId();
1143 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
1145 rollback.value = vfRollback;
1147 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1148 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1152 public void deleteVfModule (String cloudSiteId,
1155 MsoRequest msoRequest,
1156 Holder <Map <String, String>> outputs) throws VnfException {
1157 MsoLogger.setLogContext (msoRequest);
1158 MsoLogger.setServiceName ("DeleteVf");
1159 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1160 // Will capture execution time for metrics
1161 long startTime = System.currentTimeMillis ();
1163 // 1702 capture the output parameters on a delete
1164 // so we'll need to query first
1165 DeploymentInfo deployment = null;
1167 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1168 } catch (MsoException me) {
1169 // Failed to query the deployment. Convert to a generic VnfException
1170 me.addContext ("DeleteVFModule");
1171 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1172 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "QueryDeployment", null);
1173 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, CLOUDIFY, "QueryDeployment", MsoLogger.ErrorCode.DataError, "Exception - QueryDeployment", me);
1174 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1175 throw new VnfException (me);
1177 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1178 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1180 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1181 // The possible outcomes of deleteStack are a StackInfo object with status
1182 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1184 long subStartTime = System.currentTimeMillis ();
1186 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1187 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from DeleteDeployment", CLOUDIFY, "DeleteDeployment", vnfName);
1188 } catch (MsoException me) {
1189 me.addContext ("DeleteVfModule");
1190 // Convert to a generic VnfException
1191 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1192 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteDeployment", "DeleteDeployment", vnfName);
1193 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "DeleteDeployment", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment: " + me.getMessage());
1194 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1195 throw new VnfException (me);
1198 // On success, nothing is returned.
1199 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1203 // TODO: Should Update be supported for Cloudify? What would this look like?
1205 public void updateVfModule (String cloudSiteId,
1211 String volumeGroupHeatStackId,
1212 String baseVfHeatStackId,
1213 String vfModuleStackId,
1214 String modelCustomizationUuid,
1215 Map <String, Object> inputs,
1216 MsoRequest msoRequest,
1217 Holder <Map <String, String>> outputs,
1218 Holder <VnfRollback> rollback) throws VnfException
1220 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1221 LOGGER.debug ("Update VF Module command attempted but not supported");
1222 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);