2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.mso.adapters.vnf;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
28 import java.util.Optional;
31 import javax.jws.WebService;
32 import javax.xml.ws.Holder;
34 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
35 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
36 import org.openecomp.mso.cloud.CloudConfig;
37 import org.openecomp.mso.cloud.CloudConfigFactory;
38 import org.openecomp.mso.cloud.CloudSite;
39 import org.openecomp.mso.cloudify.beans.DeploymentInfo;
40 import org.openecomp.mso.cloudify.beans.DeploymentStatus;
41 import org.openecomp.mso.cloudify.exceptions.MsoCloudifyManagerNotFound;
42 import org.openecomp.mso.cloudify.utils.MsoCloudifyUtils;
43 import org.openecomp.mso.db.catalog.CatalogDatabase;
44 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
45 import org.openecomp.mso.db.catalog.beans.HeatFiles;
46 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
47 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
48 import org.openecomp.mso.db.catalog.beans.VfModule;
49 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
50 import org.openecomp.mso.db.catalog.beans.VnfResource;
51 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
52 import org.openecomp.mso.entity.MsoRequest;
53 import org.openecomp.mso.logger.MessageEnum;
54 import org.openecomp.mso.logger.MsoAlarmLogger;
55 import org.openecomp.mso.logger.MsoLogger;
56 import org.openecomp.mso.openstack.beans.MsoTenant;
57 import org.openecomp.mso.openstack.beans.VnfRollback;
58 import org.openecomp.mso.openstack.beans.VnfStatus;
59 import org.openecomp.mso.openstack.exceptions.MsoCloudSiteNotFound;
60 import org.openecomp.mso.openstack.exceptions.MsoException;
61 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
62 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
63 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentParameter;
64 import org.openecomp.mso.openstack.utils.MsoKeystoneUtils;
65 import org.openecomp.mso.properties.MsoPropertiesFactory;
67 import com.fasterxml.jackson.core.JsonParseException;
68 import com.fasterxml.jackson.databind.JsonNode;
69 import com.fasterxml.jackson.databind.ObjectMapper;
71 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
72 public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter {
74 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
75 protected CloudConfig cloudConfig = cloudConfigFactory.getCloudConfig();
77 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
79 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
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);
84 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
85 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
86 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
87 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
90 * Health Check web method. Does nothing but return to show the adapter is deployed.
93 public void healthCheck () {
94 LOGGER.debug ("Health check call in VNF Cloudify Adapter");
98 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
99 * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
101 public MsoVnfCloudifyAdapterImpl() {
106 * This constructor MUST be used if this class is called with the new operator.
107 * @param msoPropFactory
109 public MsoVnfCloudifyAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
110 this.msoPropertiesFactory = msoPropFactory;
111 this.cloudConfigFactory = cloudConfigFact;
115 * This is the "Create VNF" web service implementation.
116 * This function is now unsupported and will return an error.
120 public void createVnf (String cloudSiteId,
126 String volumeGroupHeatStackId,
127 Map <String, String> inputs,
128 Boolean failIfExists,
130 MsoRequest msoRequest,
131 Holder <String> vnfId,
132 Holder <Map <String, String>> outputs,
133 Holder <VnfRollback> rollback)
136 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
137 LOGGER.debug ("CreateVNF command attempted but not supported");
138 throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
142 * This is the "Update VNF" web service implementation.
143 * This function is now unsupported and will return an error.
147 public void updateVnf (String cloudSiteId,
153 String volumeGroupHeatStackId,
154 Map <String, String> inputs,
155 MsoRequest msoRequest,
156 Holder <Map <String, String>> outputs,
157 Holder <VnfRollback> rollback)
160 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
161 LOGGER.debug ("UpdateVNF command attempted but not supported");
162 throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA);
166 * This is the "Query VNF" web service implementation.
168 * This really should be QueryVfModule, but nobody ever changed it.
170 * For Cloudify, this will look up a deployment by its deployment ID, which is really the same
171 * as deployment name, since it assigned by the client when a deployment is created.
172 * Also, the input cloudSiteId is used only to identify which Cloudify instance to query,
173 * and the tenantId is ignored (since that really only applies for Openstack/Heat).
175 * The method returns an indicator that the VNF exists, along with its status and outputs.
176 * The input "vnfName" will also be reflected back as its ID.
178 * @param cloudSiteId CLLI code of the cloud site in which to query
179 * @param tenantId Openstack tenant identifier - ignored for Cloudify
180 * @param vnfName VNF Name (should match a deployment ID)
181 * @param msoRequest Request tracking information for logs
182 * @param vnfExists Flag reporting the result of the query
183 * @param vnfId Holder for output VNF ID
184 * @param outputs Holder for Map of VNF outputs from Cloudify deployment (assigned IPs, etc)
187 public void queryVnf (String cloudSiteId,
190 MsoRequest msoRequest,
191 Holder <Boolean> vnfExists,
192 Holder <String> vnfId,
193 Holder <VnfStatus> status,
194 Holder <Map <String, String>> outputs)
197 MsoLogger.setLogContext (msoRequest);
198 MsoLogger.setServiceName ("QueryVnfCloudify");
199 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
201 // Will capture execution time for metrics
202 long startTime = System.currentTimeMillis ();
203 long subStartTime = System.currentTimeMillis ();
205 MsoCloudifyUtils cloudifyUtils = new MsoCloudifyUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
206 DeploymentInfo deployment = null;
209 deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName);
210 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "QueryDeployment", vnfName);
212 catch (MsoCloudifyManagerNotFound e) {
213 // This site does not have a Cloudify Manager.
214 // This isn't an error, just means we won't find the VNF here.
217 catch (MsoException me) {
218 // Failed to query the Deployment due to a cloudify exception.
219 // Convert to a generic VnfException
220 me.addContext ("QueryVNF");
221 String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
222 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", vnfName);
223 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "Cloudify", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me);
224 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
225 throw new VnfException (me);
228 if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) {
229 vnfExists.value = Boolean.TRUE;
230 status.value = deploymentStatusToVnfStatus(deployment);
231 vnfId.value = deployment.getId();
232 outputs.value = copyStringOutputs (deployment.getOutputs ());
234 LOGGER.debug ("VNF " + vnfName + " found in Cloudify, ID = " + vnfId.value);
237 vnfExists.value = Boolean.FALSE;
238 status.value = VnfStatus.NOTFOUND;
240 outputs.value = new HashMap <String, String> (); // Return as an empty map
242 LOGGER.debug ("VNF " + vnfName + " not found");
244 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
250 * This is the "Delete VNF" web service implementation.
251 * This function is now unsupported and will return an error.
255 public void deleteVnf (String cloudSiteId,
258 MsoRequest msoRequest) throws VnfException {
259 MsoLogger.setLogContext (msoRequest);
260 MsoLogger.setServiceName ("DeleteVnf");
262 // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules.
263 LOGGER.debug ("DeleteVNF command attempted but not supported");
264 throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA);
268 * This web service endpoint will rollback a previous Create VNF operation.
269 * A rollback object is returned to the client in a successful creation
270 * response. The client can pass that object as-is back to the rollbackVnf
271 * operation to undo the creation.
273 * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup,
274 * but APIs were apparently never updated.
277 public void rollbackVnf (VnfRollback rollback) throws VnfException {
278 long startTime = System.currentTimeMillis ();
279 MsoLogger.setServiceName ("RollbackVnf");
280 // rollback may be null (e.g. if stack already existed when Create was called)
281 if (rollback == null) {
282 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
283 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
287 // Don't rollback if nothing was done originally
288 if (!rollback.getVnfCreated()) {
289 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back");
293 // Get the elements of the VnfRollback object for easier access
294 String cloudSiteId = rollback.getCloudSiteId ();
295 String tenantId = rollback.getTenantId ();
296 String vfModuleId = rollback.getVfModuleStackId ();
298 MsoLogger.setLogContext (rollback.getMsoRequest());
300 LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId);
302 MsoCloudifyUtils cloudifyUtils = new MsoCloudifyUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
303 DeploymentInfo deployment = null;
305 // Use the MsoCloudifyUtils to delete the deployment. Set the polling flag to true.
306 // The possible outcomes of deleteStack are a StackInfo object with status
307 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
309 long subStartTime = System.currentTimeMillis ();
311 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
312 // Go directly to Keystone until APIs could be updated to supply the name.
313 MsoKeystoneUtils keystone = new MsoKeystoneUtils(MSO_PROP_VNF_ADAPTER);
314 MsoTenant msoTenant = keystone.queryTenant(tenantId, cloudSiteId);
315 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
317 // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that.
318 deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5);
319 LOGGER.debug("Rolled back deployment: " + deployment.getId());
320 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "DeleteDeployment", null);
321 } catch (MsoException me) {
322 // Failed to rollback the VNF due to a cloudify exception.
323 // Convert to a generic VnfException
324 me.addContext ("RollbackVNF");
325 String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
326 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "DeleteDeployment", null);
327 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "Cloudify", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment", me);
328 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
329 throw new VnfException (me);
331 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module");
336 private VnfStatus deploymentStatusToVnfStatus (DeploymentInfo deployment) {
337 // Determine the status based on last action & status
338 // DeploymentInfo object should be enhanced to report a better status internally.
339 DeploymentStatus status = deployment.getStatus();
340 String lastAction = deployment.getLastAction();
342 if (status == null || lastAction == null) {
343 return VnfStatus.UNKNOWN;
345 else if (status == DeploymentStatus.NOTFOUND) {
346 return VnfStatus.NOTFOUND;
348 else if (status == DeploymentStatus.INSTALLED) {
349 return VnfStatus.ACTIVE;
351 else if (status == DeploymentStatus.CREATED) {
352 // Should have an INACTIVE status for this case. Shouldn't really happen, but
353 // Install was never run, or Uninstall was done but deployment didn't get deleted.
354 return VnfStatus.UNKNOWN;
356 else if (status == DeploymentStatus.FAILED) {
357 return VnfStatus.FAILED;
360 return VnfStatus.UNKNOWN;
363 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
364 Map <String, String> stringOutputs = new HashMap <String, String> ();
365 for (String key : stackOutputs.keySet ()) {
366 if (stackOutputs.get (key) instanceof String) {
367 stringOutputs.put (key, (String) stackOutputs.get (key));
368 } else if (stackOutputs.get(key) instanceof Integer) {
370 String str = "" + stackOutputs.get(key);
371 stringOutputs.put(key, str);
372 } catch (Exception e) {
373 LOGGER.debug("Unable to add " + key + " to outputs");
375 } else if (stackOutputs.get(key) instanceof JsonNode) {
377 String str = this.convertNode((JsonNode) stackOutputs.get(key));
378 stringOutputs.put(key, str);
379 } catch (Exception e) {
380 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
382 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
384 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
385 stringOutputs.put(key, str);
386 } catch (Exception e) {
387 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
391 String str = stackOutputs.get(key).toString();
392 stringOutputs.put(key, str);
393 } catch (Exception e) {
394 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
398 return stringOutputs;
402 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
404 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
405 if (inputs == null) {
408 else if (inputs.size() < 1) {
409 sb.append("\tEMPTY");
411 for (String str : inputs.keySet()) {
414 outputString = inputs.get(str).toString();
415 } catch (Exception e) {
416 outputString = "Unable to call toString() on the value for " + str;
418 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
421 LOGGER.debug(sb.toString());
425 private void sendMapToDebug(Map<String, String> inputs) {
427 StringBuilder sb = new StringBuilder("inputs:");
428 if (inputs == null) {
431 else if (inputs.size() < 1) {
432 sb.append("\tEMPTY");
434 for (String str : inputs.keySet()) {
435 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
438 LOGGER.debug(sb.toString());
442 private String convertNode(final JsonNode node) {
444 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
445 final String json = JSON_MAPPER.writeValueAsString(obj);
447 } catch (JsonParseException jpe) {
448 LOGGER.debug("Error converting json to string " + jpe.getMessage());
449 } catch (Exception e) {
450 LOGGER.debug("Error converting json to string " + e.getMessage());
452 return "[Error converting json to string]";
455 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
456 if (objectMap == null) {
459 Map<String, String> stringMap = new HashMap<String, String>();
460 for (String key : objectMap.keySet()) {
461 if (!stringMap.containsKey(key)) {
462 Object obj = objectMap.get(key);
463 if (obj instanceof String) {
464 stringMap.put(key, (String) objectMap.get(key));
465 } else if (obj instanceof JsonNode ){
466 // This is a bit of mess - but I think it's the least impacting
467 // let's convert it BACK to a string - then it will get converted back later
469 String str = this.convertNode((JsonNode) obj);
470 stringMap.put(key, str);
471 } catch (Exception e) {
472 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key);
473 //okay in this instance - only string values (fqdn) are expected to be needed
475 } else if (obj instanceof java.util.LinkedHashMap) {
476 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
478 String str = JSON_MAPPER.writeValueAsString(obj);
479 stringMap.put(key, str);
480 } catch (Exception e) {
481 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key);
483 } else if (obj instanceof Integer) {
485 String str = "" + obj;
486 stringMap.put(key, str);
487 } catch (Exception e) {
488 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key);
492 String str = obj.toString();
493 stringMap.put(key, str);
494 } catch (Exception e) {
495 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")");
505 * This is the "Create VF Module" web service implementation.
506 * It will instantiate a new VF Module of the requested type in the specified cloud
507 * and tenant. The tenant must exist before this service is called.
509 * If a VF Module with the same name already exists, this can be considered a
510 * success or failure, depending on the value of the 'failIfExists' parameter.
512 * All VF Modules are defined in the MSO catalog. The caller must request
513 * one of the pre-defined module types or an error will be returned. Within the
514 * catalog, each VF Module references (among other things) a cloud template
515 * which is used to deploy the required artifacts (VMs, networks, etc.)
516 * to the cloud. In this adapter implementation, that artifact is expected
517 * to be a Cloudify blueprint.
519 * Depending on the blueprint, a variable set of input parameters will
520 * be defined, some of which are required. The caller is responsible to
521 * pass the necessary input data for the module or an error will be thrown.
523 * The method returns the vfModuleId, a Map of output attributes, and a VnfRollback
524 * object. This last object can be passed as-is to the rollbackVnf operation to
525 * undo everything that was created for the Module. This is useful if a VF module
526 * is successfully created but the orchestration fails on a subsequent step.
528 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
529 * @param tenantId Openstack tenant identifier
530 * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB.
531 * Deprecated - should use modelCustomizationUuid
532 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
533 * Deprecated - VF Module versions also captured by modelCustomizationUuid
534 * @param vfModuleName Name to be assigned to the new VF Module
535 * @param requestType Indicates if this is a Volume Group or Module request
536 * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group
537 * to attach to a VF Module
538 * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if
539 * this is an Add-on module
540 * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces
541 * the use of vfModuleType.
542 * @param inputs Map of key=value inputs for VNF stack creation
543 * @param failIfExists Flag whether already existing VNF should be considered
544 * @param backout Flag whether to suppress automatic backout (for testing)
545 * @param msoRequest Request tracking information for logs
546 * @param vnfId Holder for output VNF Cloudify Deployment ID
547 * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc)
548 * @param rollback Holder for returning VnfRollback object
550 public void createVfModule(String cloudSiteId,
556 String volumeGroupId,
557 String baseVfModuleId,
558 String modelCustomizationUuid,
559 Map <String, String> inputs,
560 Boolean failIfExists,
562 MsoRequest msoRequest,
563 Holder <String> vnfId,
564 Holder <Map <String, String>> outputs,
565 Holder <VnfRollback> rollback)
568 // Will capture execution time for metrics
569 long startTime = System.currentTimeMillis ();
571 MsoLogger.setLogContext (msoRequest);
572 MsoLogger.setServiceName ("CreateVfModule");
574 // Require a model customization ID. Every VF Module definition must have one.
575 if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) {
576 LOGGER.debug("Missing required input: modelCustomizationUuid");
577 String error = "Create vfModule error: Missing required input: modelCustomizationUuid";
578 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
579 "VF Module ModelCustomizationUuid", "null", "Cloudify", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid");
580 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
581 throw new VnfException(error, MsoExceptionCategory.USERDATA);
584 // Clean up some inputs to make comparisons easier
585 if (requestType == null)
588 if ("".equals(volumeGroupId) || "null".equals(volumeGroupId))
589 volumeGroupId = null;
591 if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId))
592 baseVfModuleId = null;
594 if (inputs == null) {
595 // Create an empty set of inputs
596 inputs = new HashMap<String,String>();
597 LOGGER.debug("inputs == null - setting to empty");
599 this.sendMapToDebug(inputs);
602 // Check if this is for a "Volume" module
603 boolean isVolumeRequest = false;
604 if (requestType.startsWith("VOLUME")) {
605 isVolumeRequest = true;
608 LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId);
610 // Build a default rollback object (no actions performed)
611 VnfRollback vfRollback = new VnfRollback();
612 vfRollback.setCloudSiteId(cloudSiteId);
613 vfRollback.setTenantId(tenantId);
614 vfRollback.setMsoRequest(msoRequest);
615 vfRollback.setRequestType(requestType);
616 vfRollback.setIsBase(false); // Until we know better
617 vfRollback.setVolumeGroupHeatStackId(volumeGroupId);
618 vfRollback.setBaseGroupHeatStackId(baseVfModuleId);
619 vfRollback.setModelCustomizationUuid(modelCustomizationUuid);
620 vfRollback.setMode("CFY");
622 rollback.value = vfRollback; // Default rollback - no updates performed
624 // Get the VNF/VF Module definition from the Catalog DB first.
625 // There are three relevant records: VfModule, VfModuleCustomization, VnfResource
627 CatalogDatabase db = CatalogDatabase.getInstance();
629 VnfResource vnfResource = null;
630 VfModuleCustomization vfmc = null;
633 vfmc = db.getVfModuleCustomizationByModelCustomizationId(modelCustomizationUuid);
636 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid;
638 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
639 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error);
640 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
641 throw new VnfException(error, MsoExceptionCategory.USERDATA);
643 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
646 // Get the vfModule and vnfResource records
647 vf = vfmc.getVfModule();
648 vnfResource = db.getVnfResourceByModelUuid(vf.getVnfResourceModelUUId());
650 catch (Exception e) {
652 LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage());
653 throw new VnfException("Exception during create VF " + e.getMessage());
656 // Perform a version check against cloudSite
657 // Obtain the cloud site information where we will create the VF Module
658 Optional<CloudSite> cloudSite = cloudConfig.getCloudSite (cloudSiteId);
659 if (!cloudSite.isPresent()) {
660 throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId));
662 MavenLikeVersioning aicV = new MavenLikeVersioning();
663 aicV.setVersion(cloudSite.get().getAic_version());
665 String vnfMin = vnfResource.getAicVersionMin();
666 String vnfMax = vnfResource.getAicVersionMax();
668 if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) ||
669 (vnfMax != null && aicV.isMoreRecentThan(vnfMax)))
672 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSite.get().getId() + " with AIC_Version:" + cloudSite.get().getAic_version();
673 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
675 throw new VnfException(error, MsoExceptionCategory.USERDATA);
680 // Get Utilities for Cloudify.
681 MsoCloudifyUtils cloudify = new MsoCloudifyUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
682 DeploymentInfo cloudifyDeployment = null;
684 // First, look up to see if the VF already exists.
686 long subStartTime1 = System.currentTimeMillis ();
688 cloudifyDeployment = cloudify.queryDeployment (cloudSiteId, tenantId, vfModuleName);
689 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "QueryDeployment", vfModuleName);
691 catch (MsoException me) {
692 // Failed to query the Deployment due to a cloudify exception.
693 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
694 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me);
695 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", vfModuleName);
696 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
698 // Convert to a generic VnfException
699 me.addContext ("CreateVFModule");
700 throw new VnfException (me);
703 // More precise handling/messaging if the Module already exists
704 if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus () == DeploymentStatus.NOTFOUND)) {
705 // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN
706 DeploymentStatus status = cloudifyDeployment.getStatus();
707 LOGGER.debug ("Found Existing Deployment, status=" + status);
709 if (status == DeploymentStatus.INSTALLED) {
711 if (failIfExists != null && failIfExists) {
712 String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
713 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists");
714 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
715 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
717 // Found existing deployment and client has not requested "failIfExists".
718 // Populate the outputs from the existing deployment.
720 vnfId.value = cloudifyDeployment.getId();
721 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
722 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)");
726 // Check through various detailed error cases
727 if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) {
728 // fail - it's in progress - return meaningful error
729 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.";
730 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists");
731 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
732 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
734 else if (status == DeploymentStatus.FAILED) {
735 // fail - it exists and is in a FAILED state
736 String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
737 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in FAILED state");
738 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
739 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
741 else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) {
742 // fail - it exists and is in a UNKNOWN state
743 String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
744 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");
745 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
746 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
749 // Unexpected, since all known status values have been tested for
750 String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
751 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");
752 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
753 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId());
758 // Collect outputs from Base Modules and Volume Modules
759 Map<String, Object> baseModuleOutputs = null;
760 Map<String, Object> volumeGroupOutputs = null;
762 // If a Volume Group was provided, query its outputs for inclusion in Module input parameters
763 if (volumeGroupId != null) {
764 long subStartTime2 = System.currentTimeMillis ();
765 DeploymentInfo volumeDeployment = null;
767 volumeDeployment = cloudify.queryDeployment (cloudSiteId, tenantId, volumeGroupId);
768 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", "Cloudify", "QueryDeployment", volumeGroupId);
770 catch (MsoException me) {
771 // Failed to query the Volume GroupDeployment due to a cloudify exception.
772 String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
773 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "Cloudify", "queryDeployment(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(volume)", me);
774 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment(volume)", volumeGroupId);
775 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
777 // Convert to a generic VnfException
778 me.addContext ("CreateVFModule(QueryVolume)");
779 throw new VnfException (me);
782 if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
783 String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
784 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");
785 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
787 throw new VnfException (error, MsoExceptionCategory.USERDATA);
789 LOGGER.debug("Found nested volume group");
790 volumeGroupOutputs = volumeDeployment.getOutputs();
791 this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs");
795 // If this is an Add-On Module, query the Base Module outputs
796 // Note: This will be performed whether or not the current request is for an
797 // Add-On Volume Group or Add-On VF Module
800 LOGGER.debug("This is a BASE Module request");
801 vfRollback.setIsBase(true);
803 LOGGER.debug("This is an Add-On Module request");
805 // Add-On Modules should always have a Base, but just treat as a warning if not provided.
806 // Add-on Volume requests may or may not specify a base.
807 if (!isVolumeRequest && baseVfModuleId == null) {
808 LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided");
811 if (baseVfModuleId != null) {
812 long subStartTime2 = System.currentTimeMillis ();
813 DeploymentInfo baseDeployment = null;
815 baseDeployment = cloudify.queryDeployment (cloudSiteId, tenantId, baseVfModuleId);
816 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", "Cloudify", "QueryDeployment(Base)", baseVfModuleId);
818 catch (MsoException me) {
819 // Failed to query the Volume GroupDeployment due to a cloudify exception.
820 String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
821 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "Cloudify", "queryDeployment(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(Base)", me);
822 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment(Base)", baseVfModuleId);
823 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
825 // Convert to a generic VnfException
826 me.addContext ("CreateVFModule(QueryBase)");
827 throw new VnfException (me);
830 if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) {
831 String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
832 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, "Cloudify", "queryDeployment(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module DOES NOT EXIST");
833 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
835 throw new VnfException (error, MsoExceptionCategory.USERDATA);
837 LOGGER.debug("Found base module");
838 baseModuleOutputs = baseDeployment.getOutputs();
839 this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs");
845 // Ready to deploy the new VNF
847 // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints.
848 // In final implementation (post-POC), the template object would either be generic or there would
849 // be a separate DB Table/Object for Blueprints.
852 // NOTE: The template is fixed for the VF Module. The environment is part of the customization.
853 String heatTemplateArtifactUuid = null;
854 String heatEnvironmentArtifactUuid = null;
856 if (isVolumeRequest) {
857 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
858 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
860 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
861 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
864 if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) {
865 String error = "Create: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType;
866 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "Cloudify", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
867 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
868 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
869 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
872 HeatTemplate heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
874 if (heatTemplate == null) {
875 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
876 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
878 String.valueOf(heatTemplateArtifactUuid), "Cloudify", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
879 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
880 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
881 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
883 LOGGER.debug("Got HEAT Template record from DB");
885 // Next get the Environment record. This is optional.
886 HeatEnvironment heatEnvironment = null;
887 if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals(""))
889 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
890 if (heatEnvironment == null) {
891 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
892 + ", Environment ID="
893 + heatEnvironmentArtifactUuid;
894 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "Cloudify", "getEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
895 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
896 // Alarm on this error, configuration must be fixed
897 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
899 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
901 LOGGER.debug ("Got Heat Environment from DB");
903 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
907 // NOTE: Logic to support nested templates and "get_file" attachments was removed from
908 // Cloudify-based adapter. Assumption is that the actual blueprints and associated
909 // artifacts have been pre-loaded to Cloudify. If that changes, logic will need
910 // to be added in to dynamically build and deploy the blueprint (with all associated
911 // artifacts required for the CSAR/ZIP) before starting the actual orchestration.
914 // All variables converted to their native object types
915 HashMap<String, Object> goldenInputs = new HashMap<String,Object>();
916 List<String> extraInputs = new ArrayList<String>();
918 // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in.
919 // This whole section needs to be rewritten.
920 Boolean skipInputChecks = false;
922 if (skipInputChecks) {
923 goldenInputs = new HashMap<String,Object>();
924 for (String key : inputs.keySet()) {
925 goldenInputs.put(key, inputs.get(key));
929 // Build maps for the parameters (including aliases) to simplify checks
930 HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>();
932 Set<HeatTemplateParam> paramSet = heatTemplate.getParameters();
933 LOGGER.debug("paramSet has " + paramSet.size() + " entries");
935 for (HeatTemplateParam htp : paramSet) {
936 params.put(htp.getParamName(), htp);
939 String alias = htp.getParamAlias();
940 if (alias != null && !alias.equals("") && !params.containsKey(alias)) {
941 params.put(alias, htp);
945 // First, convert all inputs to their "template" type
946 for (String key : inputs.keySet()) {
947 if (params.containsKey(key)) {
948 Object value = cloudify.convertInputValue(inputs.get(key), params.get(key));
950 goldenInputs.put(key, value);
953 LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType());
956 extraInputs.add(key);
960 if (!extraInputs.isEmpty()) {
961 LOGGER.debug("Ignoring extra inputs: " + extraInputs);
964 // Next add in Volume Group Outputs if there are any. Copy directly without conversions.
965 if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) {
966 for (String key : volumeGroupOutputs.keySet()) {
967 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
968 goldenInputs.put(key, volumeGroupOutputs.get(key));
973 // Next add in Base Module Outputs if there are any. Copy directly without conversions.
974 if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) {
975 for (String key : baseModuleOutputs.keySet()) {
976 if (params.containsKey(key) && !goldenInputs.containsKey(key)) {
977 goldenInputs.put(key, baseModuleOutputs.get(key));
982 // Last, add in values from the "environment" file.
983 // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat.
984 if (heatEnvironment != null)
986 // TODO: This may take a different form for Cloudify, but for now process it
987 // with Heat environment file syntax
988 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
989 MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb);
991 if (mhee.getParameters() != null) {
992 for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) {
993 // If this is a template input, copy to golden inputs
994 String envKey = envParam.getName();
995 if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) {
996 Object value = cloudify.convertInputValue(envParam.getValue(), params.get(envKey));
998 goldenInputs.put(envKey, value);
1001 LOGGER.debug("Failed to convert environment parameter " + envKey + "='" + envParam.getValue() + "' to " + params.get(envKey).getParamType());
1008 LOGGER.debug("NO ENVIRONMENT for this entry");
1011 this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify");
1014 // Check that required parameters have been supplied from any of the sources
1015 String missingParams = null;
1016 boolean checkRequiredParameters = true;
1018 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1019 .getProperty (MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS,null);
1020 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1021 checkRequiredParameters = false;
1022 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1023 + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS);
1025 } catch (Exception e) {
1026 // No problem - default is true
1027 LOGGER.debug ("An exception occured trying to get property " + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e);
1031 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1032 if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) {
1033 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1034 if (missingParams == null) {
1035 missingParams = parm.getParamName ();
1037 missingParams += "," + parm.getParamName ();
1042 if (missingParams != null) {
1043 if (checkRequiredParameters) {
1044 // Problem - missing one or more required parameters
1045 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1046 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "Cloudify", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1047 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1048 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1050 LOGGER.debug ("found missing parameters [" + missingParams + "] - but checkRequiredParameters is false - will not block");
1053 LOGGER.debug ("No missing parameters found - ok to proceed");
1056 } // NOTE: END PARAMETER CHECKING
1058 // Ready to deploy the VF Module.
1059 // First step - make sure the blueprint is loaded into Cloudify.
1061 String blueprintName = heatTemplate.getTemplateName();
1062 String blueprint = heatTemplate.getTemplateBody();
1064 // Use the main blueprint name as the blueprint ID (strip yaml extensions).
1065 String blueprintId = blueprintName;
1066 if (blueprintId.endsWith(".yaml"))
1067 blueprintId = blueprintId.substring(0,blueprintId.lastIndexOf(".yaml"));
1070 if (! cloudify.isBlueprintLoaded (cloudSiteId, blueprintId)) {
1071 LOGGER.debug ("Blueprint " + blueprintId + " is not loaded. Will upload it now.");
1073 Map<String,byte[]> blueprintFiles = new HashMap<String,byte[]>();
1075 blueprintFiles.put(blueprintName, blueprint.getBytes());
1077 // TODO: Implement nested blueprint logic based on Cloudify structures.
1078 // For now, just use the Heat structures.
1079 // The query returns a map of String->Object, where the map keys provide one layer of
1080 // indirection from the Heat template names. For this case, assume the map key matches
1081 // the nested blueprint name.
1082 Map <String, Object> nestedBlueprints = db.getNestedTemplates (heatTemplate.getArtifactUuid());
1083 if (nestedBlueprints != null) {
1084 for (String nestedBlueprintName: nestedBlueprints.keySet()) {
1085 String nestedBlueprint = (String) nestedBlueprints.get(nestedBlueprintName);
1086 blueprintFiles.put(nestedBlueprintName, nestedBlueprint.getBytes());
1090 // TODO: Implement file artifact logic based on Cloudify structures.
1091 // For now, just use the Heat structures.
1092 Map<String, HeatFiles> heatFiles = db.getHeatFilesForVfModule (vf.getModelUUID());
1093 if (heatFiles != null) {
1094 for (String heatFileName: heatFiles.keySet()) {
1095 String heatFile = heatFiles.get(heatFileName).getFileBody();
1096 blueprintFiles.put(heatFileName, heatFile.getBytes());
1100 // Upload the blueprint package
1101 cloudify.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false);
1105 catch (MsoException me) {
1106 me.addContext ("CreateVFModule");
1107 String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me;
1108 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "MsoException - uploadBlueprint", me);
1109 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1110 throw new VnfException (me);
1114 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1115 // because we already checked for those.
1116 long createDeploymentStarttime = System.currentTimeMillis ();
1118 // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID.
1119 // Go directly to Keystone until APIs could be updated to supply the name.
1120 MsoKeystoneUtils keystone = new MsoKeystoneUtils(MSO_PROP_VNF_ADAPTER);
1121 MsoTenant msoTenant = keystone.queryTenant(tenantId, cloudSiteId);
1122 String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId);
1124 if (backout == null) {
1127 cloudifyDeployment = cloudify.createAndInstallDeployment (cloudSiteId,
1133 heatTemplate.getTimeoutMinutes (),
1134 backout.booleanValue());
1136 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "CreateDeployment", vfModuleName);
1137 } catch (MsoException me) {
1138 me.addContext ("CreateVFModule");
1139 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1140 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "CreateDeployment", vfModuleName);
1141 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "MsoException - createDeployment", me);
1142 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1143 throw new VnfException (me);
1144 } catch (NullPointerException npe) {
1145 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1146 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "CreateDeployment", vfModuleName);
1147 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createDeployment", npe);
1148 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1149 LOGGER.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment");
1150 //npe.addContext ("CreateVNF");
1151 throw new VnfException ("NullPointerException during cloudify.createAndInstallDeployment");
1152 } catch (Exception e) {
1153 LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify", "Cloudify", "CreateDeployment", vfModuleName);
1154 LOGGER.debug("unhandled exception at cloudify.createAndInstallDeployment");
1155 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify");
1156 throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + e.getMessage());
1158 } catch (Exception e) {
1159 LOGGER.debug("unhandled exception in create VF");
1160 throw new VnfException("Exception during create VF " + e.getMessage());
1163 // Make sure DB session is closed
1167 // Reach this point if create is successful.
1168 // Populate remaining rollback info and response parameters.
1169 vfRollback.setVnfCreated (true);
1170 vfRollback.setVnfId (cloudifyDeployment.getId());
1171 vnfId.value = cloudifyDeployment.getId();
1172 outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ());
1174 rollback.value = vfRollback;
1176 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1177 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1181 public void deleteVfModule (String cloudSiteId,
1184 MsoRequest msoRequest,
1185 Holder <Map <String, String>> outputs) throws VnfException {
1186 MsoLogger.setLogContext (msoRequest);
1187 MsoLogger.setServiceName ("DeleteVf");
1188 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1189 // Will capture execution time for metrics
1190 long startTime = System.currentTimeMillis ();
1192 MsoCloudifyUtils cloudify = new MsoCloudifyUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1194 // 1702 capture the output parameters on a delete
1195 // so we'll need to query first
1196 DeploymentInfo deployment = null;
1198 deployment = cloudify.queryDeployment(cloudSiteId, tenantId, vnfName);
1199 } catch (MsoException me) {
1200 // Failed to query the deployment. Convert to a generic VnfException
1201 me.addContext ("DeleteVFModule");
1202 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1203 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", null);
1204 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "Cloudify", "QueryDeployment", MsoLogger.ErrorCode.DataError, "Exception - QueryDeployment", me);
1205 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1206 throw new VnfException (me);
1208 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1209 outputs.value = convertMapStringObjectToStringString(deployment.getOutputs());
1211 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1212 // The possible outcomes of deleteStack are a StackInfo object with status
1213 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1215 long subStartTime = System.currentTimeMillis ();
1217 cloudify.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5);
1218 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from DeleteDeployment", "Cloudify", "DeleteDeployment", vnfName);
1219 } catch (MsoException me) {
1220 me.addContext ("DeleteVfModule");
1221 // Convert to a generic VnfException
1222 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1223 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteDeployment", "DeleteDeployment", vnfName);
1224 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "DeleteDeployment", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment: " + me.getMessage());
1225 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1226 throw new VnfException (me);
1229 // On success, nothing is returned.
1230 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1234 // TODO: Should Update be supported for Cloudify? What would this look like?
1236 public void updateVfModule (String cloudSiteId,
1242 String volumeGroupHeatStackId,
1243 String baseVfHeatStackId,
1244 String vfModuleStackId,
1245 String modelCustomizationUuid,
1246 Map <String, String> inputs,
1247 MsoRequest msoRequest,
1248 Holder <Map <String, String>> outputs,
1249 Holder <VnfRollback> rollback) throws VnfException
1251 // This operation is not currently supported for Cloudify-orchestrated VF Modules.
1252 LOGGER.debug ("Update VF Module command attempted but not supported");
1253 throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA);