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;
55 import org.onap.so.logger.MsoAlarmLogger;
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);
84 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
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, String> 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, String> 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, String> 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, String> 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<String,String>();
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 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
878 MsoAlarmLogger.CRITICAL, error);
879 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
881 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
884 if (heatEnvironment == null) {
885 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
886 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
887 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
888 // Alarm on this error, configuration must be fixed
889 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
891 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
893 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
898 // All variables converted to their native object types
899 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
900 List<String> extraInputs = new ArrayList<String>();
902 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
903 // This whole section needs to be rewritten.
904 Boolean skipInputChecks = false;
906 if (skipInputChecks) {
907 goldenInputs = new HashMap<String,Object>();
908 for (String key : inputs.keySet()) {
909 goldenInputs.put(key, inputs.get(key));
913 // Build maps for the parameters (including aliases) to simplify checks
914 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
916 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
917 LOGGER.debug("paramSet has " + paramSet.size() + " entries");
919 for (HeatTemplateParam htp : paramSet) {
920 params.put(htp.getParamName(), htp);
923 String alias = htp.getParamAlias();
924 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
925 params.put(alias, htp);
929 // First, convert all inputs to their "template" type
930 for (String key : inputs.keySet()) {
931 if (params.containsKey(key)) {
932 Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key));
934 goldenInputs.put(key, value);
937 LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType());
940 extraInputs.add(key);
944 if (!extraInputs.isEmpty()) {
945 LOGGER.debug("Ignoring extra inputs: " + extraInputs);
948 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
949 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
950 for (String key : volumeGroupOutputs.keySet()) {
951 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
952 goldenInputs.put(key, volumeGroupOutputs.get(key));
957 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
958 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
959 for (String key : baseModuleOutputs.keySet()) {
960 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
961 goldenInputs.put(key, baseModuleOutputs.get(key));
966 // Last, add in values from the "environment" file.
967 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
969 // TODO: This may take a different form for Cloudify, but for now process it
970 // with Heat environment file syntax
971 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
972 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
974 if (mhee.getParameters() != null) {
975 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
976 // If this is a template input, copy to golden inputs
977 String envKey = envParam.getName();
978 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
979 Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey));
981 goldenInputs.put(envKey, value);
984 LOGGER.debug("Failed to convert environment parameter " + envKey + "='" + envParam.getValue() + "' to " + params.get(envKey).getParamType());
990 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
993 // Check that required parameters have been supplied from any of the sources
994 String missingParams = null;
995 boolean checkRequiredParameters = true;
997 String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
998 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
999 checkRequiredParameters = false;
1000 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1001 + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
1003 } catch (Exception e) {
1004 // No problem - default is true
1005 LOGGER.debug ("An exception occured trying to get property " + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
1009 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1010 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1011 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1012 if (missingParams == null) {
1013 missingParams = parm.getParamName ();
1015 missingParams += "," + parm.getParamName ();
1020 if (missingParams != null) {
1021 if (checkRequiredParameters) {
1022 // Problem - missing one or more required parameters
1023 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1024 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1025 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1026 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1028 LOGGER.debug ("found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - will not block");
1031 LOGGER.debug ("No missing parameters found - ok to proceed");
1034 } // NOTE: END PARAMETER CHECKING
1036 // Ready to deploy the VF Module.
1037 // *First step - make sure the blueprint is loaded into Cloudify.
1038 String blueprintName = heatTemplate.getTemplateName();
1039 String blueprint = heatTemplate.getTemplateBody();
1040 String blueprintId = blueprintName;
1042 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
1043 if (blueprintId.endsWith(".yaml"))
1044 blueprintId = blueprintId.substring(0,blueprintId.lastIndexOf(".yaml"));
1047 if (! cloudifyUtils.isBlueprintLoaded (cloudSiteId, blueprintId)) {
1048 LOGGER.debug ("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
1050 Map<String,byte[]> blueprintFiles = new HashMap<String,byte[]>();
1052 blueprintFiles.put(blueprintName, blueprint.getBytes());
1054 // TODO: Implement nested blueprint logic based on Cloudify structures.
1055 // For now, just use the Heat structures.
1056 // The query returns a map of String->Object, where the map keys provide one layer of
1057 // indirection from the Heat template names. For this case, assume the map key matches
1058 // the nested blueprint name.
1059 List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates();
1060 if (nestedBlueprints != null) {
1061 for (HeatTemplate nestedBlueprint: nestedBlueprints) {
1062 blueprintFiles.put(nestedBlueprint.getTemplateName(), nestedBlueprint.getTemplateBody().getBytes());
1066 // TODO: Implement file artifact logic based on Cloudify structures.
1067 // For now, just use the Heat structures.
1068 List<HeatFiles> heatFiles = vf.getHeatFiles();
1069 if (heatFiles != null) {
1070 for (HeatFiles heatFile: heatFiles) {
1071 blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes());
1075 // Upload the blueprint package
1076 cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1081 catch (MsoException me) {
1082 me.addContext ("CreateVFModule");
1083 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1084 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "MsoException - uploadBlueprint", me);
1085 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1086 throw new VnfException (me);
1090 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1091 // because we already checked for those.
1092 long createDeploymentStarttime = System.currentTimeMillis ();
1094 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1095 // Go directly to Keystone until APIs could be updated to supply the name.
1096 MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId);
1097 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
1099 if (backout == null) {
1103 cloudifyDeployment = cloudifyUtils.createAndInstallDeployment (cloudSiteId,
1109 heatTemplate.getTimeoutMinutes (),
1110 backout.booleanValue());
1112 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, CLOUDIFY_RESPONSE_SUCCESS, CLOUDIFY, "CreateDeployment", vfModuleName);
1113 } catch (MsoException me) {
1114 me.addContext ("CreateVFModule");
1115 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1116 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "CreateDeployment", vfModuleName);
1117 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "MsoException - createDeployment", me);
1118 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1119 throw new VnfException (me);
1120 } catch (NullPointerException npe) {
1121 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1122 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "CreateDeployment", vfModuleName);
1123 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, CLOUDIFY, "", MsoLogger.ErrorCode.DataError, "NullPointerException - createDeployment", npe);
1124 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1125 LOGGER.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1126 //npe.addContext ("CreateVNF");
1127 throw new VnfException ("NullPointerException during cloudify.createAndInstallDeployment");
1128 } catch (Exception e) {
1129 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify", CLOUDIFY, "CreateDeployment", vfModuleName);
1130 LOGGER.debug("unhandled exception at cloudify.createAndInstallDeployment");
1131 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify");
1132 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1134 } catch (Exception e) {
1135 LOGGER.debug("unhandled exception in create VF");
1136 throw new VnfException("Exception during create VF " + e.getMessage());
1140 // Reach this point if create is successful.
1141 // Populate remaining rollback info and response parameters.
1142 vfRollback.setVnfCreated (true);
1143 vfRollback.setVnfId (cloudifyDeployment.getId());
1144 vnfId.value = cloudifyDeployment.getId();
1145 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
1147 rollback.value = vfRollback;
1149 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1150 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1154 public void deleteVfModule (String cloudSiteId,
1157 MsoRequest msoRequest,
1158 Holder <Map <String, String>> outputs) throws VnfException {
1159 MsoLogger.setLogContext (msoRequest);
1160 MsoLogger.setServiceName ("DeleteVf");
1161 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1162 // Will capture execution time for metrics
1163 long startTime = System.currentTimeMillis ();
1165 // 1702 capture the output parameters on a delete
1166 // so we'll need to query first
1167 DeploymentInfo deployment = null;
1169 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
1170 } catch (MsoException me) {
1171 // Failed to query the deployment. Convert to a generic VnfException
1172 me.addContext ("DeleteVFModule");
1173 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1174 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, CLOUDIFY, "QueryDeployment", null);
1175 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, CLOUDIFY, "QueryDeployment", MsoLogger.ErrorCode.DataError, "Exception - QueryDeployment", me);
1176 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1177 throw new VnfException (me);
1179 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1180 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1182 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1183 // The possible outcomes of deleteStack are a StackInfo object with status
1184 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1186 long subStartTime = System.currentTimeMillis ();
1188 cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1189 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from DeleteDeployment", CLOUDIFY, "DeleteDeployment", vnfName);
1190 } catch (MsoException me) {
1191 me.addContext ("DeleteVfModule");
1192 // Convert to a generic VnfException
1193 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1194 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteDeployment", "DeleteDeployment", vnfName);
1195 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "DeleteDeployment", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment: " + me.getMessage());
1196 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1197 throw new VnfException (me);
1200 // On success, nothing is returned.
1201 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1205 // TODO: Should Update be supported for Cloudify? What would this look like?
1207 public void updateVfModule (String cloudSiteId,
1213 String volumeGroupHeatStackId,
1214 String baseVfHeatStackId,
1215 String vfModuleStackId,
1216 String modelCustomizationUuid,
1217 Map <String, String> inputs,
1218 MsoRequest msoRequest,
1219 Holder <Map <String, String>> outputs,
1220 Holder <VnfRollback> rollback) throws VnfException
1222 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1223 LOGGER.debug ("Update VF Module command attempted but not supported");
1224 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);