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.Scanner;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
32 import javax.jws.WebService;
33 import javax.xml.ws.Holder;
35 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
36 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
37 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
38 import org.openecomp.mso.cloud.CloudConfigFactory;
39 import org.openecomp.mso.cloud.CloudConfig;
40 import org.openecomp.mso.cloud.CloudSite;
41 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
42 import org.openecomp.mso.db.catalog.CatalogDatabase;
43 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
44 import org.openecomp.mso.db.catalog.beans.HeatFiles;
45 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
46 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
47 import org.openecomp.mso.db.catalog.beans.VnfResource;
48 import org.openecomp.mso.db.catalog.beans.VfModule;
49 import org.openecomp.mso.db.catalog.beans.VnfComponent;
50 import org.openecomp.mso.entity.MsoRequest;
51 import org.openecomp.mso.logger.MessageEnum;
52 import org.openecomp.mso.logger.MsoAlarmLogger;
53 import org.openecomp.mso.logger.MsoLogger;
54 import org.openecomp.mso.openstack.beans.HeatStatus;
55 import org.openecomp.mso.openstack.beans.StackInfo;
56 import org.openecomp.mso.openstack.beans.VnfStatus;
57 import org.openecomp.mso.openstack.beans.VnfRollback;
58 import org.openecomp.mso.openstack.exceptions.MsoException;
59 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
60 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
61 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
62 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
63 import org.openecomp.mso.properties.MsoPropertiesFactory;
65 import org.codehaus.jackson.JsonFactory;
66 import org.codehaus.jackson.JsonNode;
67 import org.codehaus.jackson.JsonParser;
68 import org.codehaus.jackson.JsonParseException;
69 import org.codehaus.jackson.map.ObjectMapper;
71 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
72 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
74 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
75 protected CloudConfig cloudConfig = null;
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 Adapter");
98 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
99 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
101 public MsoVnfAdapterImpl() {
106 * This constructor MUST be used if this class is called with the new operator.
107 * @param msoPropFactory
109 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
110 this.msoPropertiesFactory = msoPropFactory;
111 this.cloudConfigFactory = cloudConfigFact;
115 * This is the "Create VNF" web service implementation.
116 * It will create a new VNF of the requested type in the specified cloud
117 * and tenant. The tenant must exist before this service is called.
119 * If a VNF with the same name already exists, this can be considered a
120 * success or failure, depending on the value of the 'failIfExists' parameter.
122 * All VNF types will be defined in the MSO catalog. The caller must request
123 * one of these pre-defined types or an error will be returned. Within the
124 * catalog, each VNF type references (among other things) a Heat template
125 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
128 * Depending on the Heat template, a variable set of input parameters will
129 * be defined, some of which are required. The caller is responsible to
130 * pass the necessary input data for the VNF or an error will be thrown.
132 * The method returns the vnfId (the canonical name), a Map of VNF output
133 * attributes, and a VnfRollback object. This last object can be passed
134 * as-is to the rollbackVnf operation to undo everything that was created
135 * for the VNF. This is useful if a VNF is successfully created but the
136 * orchestrator fails on a subsequent operation.
138 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
139 * @param tenantId Openstack tenant identifier
140 * @param vnfType VNF type key, should match a VNF definition in catalog DB
141 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
142 * @param vnfName Name to be assigned to the new VNF
143 * @param inputs Map of key=value inputs for VNF stack creation
144 * @param failIfExists Flag whether already existing VNF should be considered
145 * a success or failure
146 * @param msoRequest Request tracking information for logs
147 * @param vnfId Holder for output VNF Openstack ID
148 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
149 * @param rollback Holder for returning VnfRollback object
152 public void createVnf (String cloudSiteId,
158 String volumeGroupHeatStackId,
159 Map <String, String> inputs,
160 Boolean failIfExists,
162 MsoRequest msoRequest,
163 Holder <String> vnfId,
164 Holder <Map <String, String>> outputs,
165 Holder <VnfRollback> rollback) throws VnfException {
166 // Create a hook here to catch shortcut createVf requests:
167 if (requestType != null) {
168 if (requestType.startsWith("VFMOD")) {
169 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
170 String newRequestType = requestType.substring(5);
171 String vfVolGroupHeatStackId = "";
172 String vfBaseHeatStackId = "";
174 if (volumeGroupHeatStackId != null) {
175 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
176 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
178 } catch (Exception e) {
179 // might be ok - both are just blank
180 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId);
182 this.createVfModule(cloudSiteId,
188 vfVolGroupHeatStackId,
201 // createVf will know if the requestType starts with "X" that it's the "old" way
202 StringBuilder newRequestTypeSb = new StringBuilder("X");
203 String vfVolGroupHeatStackId = "";
204 String vfBaseHeatStackId = "";
205 if (requestType != null) {
206 newRequestTypeSb.append(requestType);
208 this.createVfModule(cloudSiteId,
213 newRequestTypeSb.toString(),
214 vfVolGroupHeatStackId,
225 // End createVf shortcut
229 public void updateVnf (String cloudSiteId,
235 String volumeGroupHeatStackId,
236 Map <String, String> inputs,
237 MsoRequest msoRequest,
238 Holder <Map <String, String>> outputs,
239 Holder <VnfRollback> rollback) throws VnfException {
240 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
241 MsoLogger.setServiceName ("UpdateVnf");
242 String requestTypeString = "";
243 if (requestType != null && !requestType.equals("")) {
244 requestTypeString = requestType;
246 String nestedStackId = null;
247 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
248 nestedStackId = volumeGroupHeatStackId;
251 LOGGER.debug ("Updating VNF: " + vnfName + " of type " + vnfType + "in " + cloudSiteId + "/" + tenantId);
252 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId);
254 // Will capture execution time for metrics
255 long startTime = System.currentTimeMillis ();
257 // Build a default rollback object (no actions performed)
258 VnfRollback vnfRollback = new VnfRollback ();
259 vnfRollback.setCloudSiteId (cloudSiteId);
260 vnfRollback.setTenantId (tenantId);
261 vnfRollback.setMsoRequest (msoRequest);
262 vnfRollback.setRequestType(requestTypeString);
264 // First, look up to see if the VNF already exists.
265 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
266 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
268 StackInfo heatStack = null;
269 long queryStackStarttime1 = System.currentTimeMillis ();
271 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
272 LOGGER.recordMetricEvent (queryStackStarttime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
273 } catch (MsoException me) {
274 // Failed to query the Stack due to an openstack exception.
275 // Convert to a generic VnfException
276 me.addContext ("UpdateVNF");
277 String error = "Update VNF: Query " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
278 LOGGER.recordMetricEvent (queryStackStarttime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
279 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in updateVnf", me);
280 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
281 throw new VnfException (me);
284 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
286 String error = "Update VNF: Stack " + vnfName + " does not exist in " + cloudSiteId + "/" + tenantId;
287 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Stack " + vnfName + " does not exist");
288 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
289 throw new VnfNotFound (cloudSiteId, tenantId, vnfName);
291 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
292 // Populate the outputs from the existing stack.
293 outputs.value = copyStringOutputs (heatStack.getOutputs ());
294 rollback.value = vnfRollback; // Default rollback - no updates performed
297 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
298 StackInfo nestedHeatStack = null;
299 long queryStackStarttime2 = System.currentTimeMillis ();
300 if (nestedStackId != null) {
302 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
303 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
304 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
305 } catch (MsoException me) {
306 // Failed to query the Stack due to an openstack exception.
307 // Convert to a generic VnfException
308 me.addContext ("UpdateVNF");
309 String error = "Update VNF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
310 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
311 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.AvailabilityError, "Exception trying to query nested stack", me);
312 LOGGER.debug("ERROR trying to query nested stack= " + error);
313 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
314 throw new VnfException (me);
316 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
317 String error = "Update VNF: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
318 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.AvailabilityError, "Attached heatStack ID DOES NOT EXIST");
319 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
321 throw new VnfException (error, MsoExceptionCategory.USERDATA);
323 LOGGER.debug("Found nested heat stack - copying values to inputs");
324 this.sendMapToDebug(inputs);
325 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
326 this.sendMapToDebug(inputs);
330 // Ready to deploy the new VNF
332 // Get a handle to the Catalog Database
333 CatalogDatabase db = new CatalogDatabase ();
335 // Make sure DB session is closed
337 // Retrieve the VNF definition
339 if (vnfVersion != null && !vnfVersion.isEmpty ()) {
340 vnf = db.getVnfResource (vnfType, vnfVersion);
342 vnf = db.getVnfResource (vnfType);
345 String error = "Update VNF: Unknown VNF Type: " + vnfType;
346 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Unknown VNF Type");
347 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
348 throw new VnfException (error, MsoExceptionCategory.USERDATA);
350 LOGGER.debug ("Got VNF definition from Catalog: " + vnf.toString ());
352 // Currently, all VNFs are orchestrated via HEAT
353 if (!"HEAT".equals (vnf.getOrchestrationMode ())) {
354 String error = "Update VNF: Configuration error: VNF=" + vnfType;
355 LOGGER.error (MessageEnum.RA_CONFIG_EXC, " VNF=" + vnfType, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Configuration error");
356 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
357 // Alarm on this error, configuration must be fixed
358 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
359 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
362 //1604 - Need to handle an updateVolume request.
363 VnfComponent vnfComponent = null;
364 if (requestTypeString != null && !requestTypeString.equals("")) {
365 LOGGER.debug("About to query for vnfComponent id = " + vnf.getId() + ", type = " + requestTypeString.toUpperCase());
366 vnfComponent = db.getVnfComponent(vnf.getId(), requestTypeString.toUpperCase());
367 if (vnfComponent == null) {
368 String error = "Update VNF: Cannot find VNF Component entry for: " + vnfType + ", type = " + requestTypeString.toUpperCase();
369 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Cannot find VNF Component entry");
370 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
371 throw new VnfException (error, MsoExceptionCategory.USERDATA);
373 LOGGER.debug("FOUND VnfComponent: " + vnfComponent.toString());
376 HeatTemplate heatTemplate = db.getHeatTemplate (vnf.getTemplateId ());
377 if (heatTemplate == null) {
378 String error = "Update VNF: undefined Heat Template. VNF=" + vnfType;
379 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", String.valueOf(vnf.getTemplateId ()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: undefined Heat Template");
380 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
381 // Alarm on this error, configuration must be fixed
382 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
384 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
387 // If this is a component request - get the template associated for volumes
388 // May change this - for now get both templates - but volume will be 2nd, which makes sense
389 // for the rest of the code. Same with envt later
390 if (vnfComponent != null) {
391 LOGGER.debug("Querying db to find component template " + vnfComponent.getHeatTemplateId());
392 heatTemplate = db.getHeatTemplate(vnfComponent
393 .getHeatTemplateId());
394 if (heatTemplate == null) {
395 String error = "Update VNF: undefined Heat Template for Volume Component. VNF="
397 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
399 String.valueOf(vnfComponent.getHeatTemplateId()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: undefined Heat Template for Volume Component");
400 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
401 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
402 MsoAlarmLogger.CRITICAL, error);
403 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
407 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
409 // Add check for any Environment variable
410 HeatEnvironment heatEnvironment = null;
411 String heatEnvironmentString = null;
413 if (vnf.getEnvironmentId () != null) {
414 LOGGER.debug ("about to call getHeatEnvironment with :" + vnf.getEnvironmentId () + ":");
415 heatEnvironment = db.getHeatEnvironment (vnf.getEnvironmentId ());
416 if (heatEnvironment == null) {
418 String error = "Create VNF: undefined Heat Environment. VNF=" + vnfType
419 + ", Environment ID="
420 + vnf.getEnvironmentId ();
421 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(vnf.getEnvironmentId ()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Create VNF: undefined Heat Environment");
422 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
423 // Alarm on this error, configuration must be fixed
424 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
426 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
428 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
429 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
430 LOGGER.debug ("After parsing: " + heatEnvironmentString);
433 LOGGER.debug ("no environment parameter for this VNF " + vnfType);
436 //1604 - override the VNF environment with the one for the component
437 if(vnfComponent != null) {
438 if (vnfComponent.getHeatEnvironmentId () != null) {
439 LOGGER.debug ("about to call getHeatEnvironment with :" + vnfComponent.getHeatEnvironmentId () + ":");
440 heatEnvironment = db.getHeatEnvironment (vnfComponent.getHeatEnvironmentId ());
441 if (heatEnvironment == null) {
442 String error = "Update VNF: undefined Heat Environment. VNF=" + vnfType
443 + ", Environment ID="
444 + vnfComponent.getHeatEnvironmentId ();
445 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(vnfComponent.getHeatEnvironmentId ()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: undefined Heat Environment");
446 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
447 // Alarm on this error, configuration must be fixed
448 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
450 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
452 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
453 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
454 LOGGER.debug ("after parsing: " + heatEnvironmentString);
457 LOGGER.debug ("no environment parameter for this VNF VOLUME component " + vnfType);
463 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
464 + heatTemplate.getId ());
465 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getId ());
466 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
467 if (nestedTemplates != null) {
468 // for debugging print them out
469 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
470 for (String providerResourceFile : nestedTemplates.keySet ()) {
471 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
472 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
473 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
474 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
477 LOGGER.debug ("No nested templates found - nothing to do here");
478 nestedTemplatesChecked = null;
481 // Also add the files: for any get_files associated with this vnf_resource_id
482 // *if* there are any
483 LOGGER.debug ("In MsoVnfAdapterImpl.updateVnf, about to call db.getHeatFiles avec vnfResourceId="
485 Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
486 Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
487 if (heatFiles != null) {
488 // add these to stack - to be done in createStack
489 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
490 // this will match the nested templates format
491 LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
493 for (String heatFileName : heatFiles.keySet ()) {
494 String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
495 // Remove the file:/// enforcement for get_file:
496 //String heatFileNameChecked = this.enforceFilePrefix (heatFileName);
497 String heatFileNameChecked = heatFileName;
498 LOGGER.debug (heatFileNameChecked + " -> " + heatFileBody);
499 heatFilesObjects.put (heatFileNameChecked, heatFileBody);
502 LOGGER.debug ("No heat files found -nothing to do here");
503 heatFilesObjects = null;
506 // Check that required parameters have been supplied
507 String missingParams = null;
508 List <String> paramList = new ArrayList <String> ();
510 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
511 // supplied an alias. Only check if we don't find it initially.
512 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
513 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
515 boolean haveEnvironmentParameters = false;
516 boolean checkRequiredParameters = true;
518 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
519 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
520 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
521 checkRequiredParameters = false;
522 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
523 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
525 } catch (Exception e) {
526 // No problem - default is true
527 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
529 // 1604 - Add enhanced environment & parameter checking
530 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
531 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
532 // Note this also removes any comments
533 MsoHeatEnvironmentEntry mhee = null;
534 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) {
535 LOGGER.debug("Enhanced environment checking enabled - 1604");
536 haveEnvironmentParameters = true;
537 StringBuilder sb = new StringBuilder(heatEnvironmentString);
538 //LOGGER.debug("About to create MHEE with " + sb);
539 mhee = new MsoHeatEnvironmentEntry(sb);
540 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
541 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
542 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
544 if (!mhee.isValid()) {
545 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
547 sb2.append("\nEnvironment:");
548 sb2.append(mhee.toFullString());
550 LOGGER.debug(sb2.toString());
552 LOGGER.debug("NO ENVIRONMENT for this entry");
555 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
556 LOGGER.debug ("Parameter:'" + parm.getParamName ()
560 + parm.getParamAlias ());
561 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
562 if (inputs.containsKey (parm.getParamAlias ())) {
563 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
564 String realParamName = parm.getParamName ();
565 String alias = parm.getParamAlias ();
566 String value = inputs.get (alias);
567 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
572 inputs.remove (alias);
573 inputs.put (realParamName, value);
574 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
576 // enhanced - check if it's in the Environment (note: that method
577 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
579 LOGGER.debug ("Required parameter " + parm.getParamName ()
580 + " appears to be in environment - do not count as missing");
583 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
584 if (missingParams == null) {
585 missingParams = parm.getParamName ();
587 missingParams += "," + parm.getParamName ();
591 paramList.add (parm.getParamName ());
593 if (missingParams != null) {
594 // Problem - missing one or more required parameters
595 if (checkRequiredParameters) {
596 String error = "Update VNF: Missing Required inputs: " + missingParams;
597 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Missing Required inputs");
598 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
599 throw new VnfException (error, MsoExceptionCategory.USERDATA);
601 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
604 LOGGER.debug ("No missing parameters found - ok to proceed");
607 // Here - modify heatEnvironmentString
608 StringBuilder parsedEnvironmentString = null;
609 String newEnvironmentString = null;
611 LOGGER.debug("Environment before:\n" + heatEnvironmentString);
612 parsedEnvironmentString = mhee.toFullStringExcludeNonParams(heatTemplate.getParameters());
613 LOGGER.debug("Environment after:\n" + parsedEnvironmentString.toString());
614 newEnvironmentString = parsedEnvironmentString.toString();
617 // Remove any extraneous parameters (don't throw an error)
618 if (inputs != null) {
619 List <String> extraParams = new ArrayList <String> ();
620 extraParams.addAll (inputs.keySet ());
621 // This is not a valid parameter for this template
622 extraParams.removeAll (paramList);
623 if (!extraParams.isEmpty ()) {
624 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "VNF Extra params");
625 inputs.keySet ().removeAll (extraParams);
629 // "Fix" the template if it has CR/LF (getting this from Oracle)
630 String template = heatTemplate.getHeatTemplate ();
631 template = template.replaceAll ("\r\n", "\n");
633 // Have the tenant. Now deploy the stack itself
634 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
635 // because we already checked for those.
636 long updateStackStarttime = System.currentTimeMillis ();
638 heatStack = heatU.updateStack (cloudSiteId,
642 copyStringInputs (inputs),
644 heatTemplate.getTimeoutMinutes (),
645 newEnvironmentString,
646 //heatEnvironmentString,
647 nestedTemplatesChecked,
649 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateStack", vnfName);
650 } catch (MsoException me) {
651 me.addContext ("UpdateVNF");
652 String error = "Update VNF " + vnfType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
653 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", vnfName);
654 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vnfType, cloudSiteId, tenantId, "OpenStack", "updateStack", MsoLogger.ErrorCode.DataError, "Exception - updateStack", me);
655 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
656 throw new VnfException (me);
659 // Make sure DB session is closed
663 // Reach this point if updateStack is successful.
664 // Populate remaining rollback info and response parameters.
665 vnfRollback.setVnfId (heatStack.getCanonicalName ());
666 vnfRollback.setVnfCreated (true);
668 outputs.value = copyStringOutputs (heatStack.getOutputs ());
669 rollback.value = vnfRollback;
670 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VNF");
675 * This is the "Query VNF" web service implementation.
676 * It will look up a VNF by name or ID in the specified cloud and tenant.
678 * The method returns an indicator that the VNF exists, its Openstack internal
679 * ID, its status, and the set of outputs (from when the stack was created).
681 * @param cloudSiteId CLLI code of the cloud site in which to query
682 * @param tenantId Openstack tenant identifier
683 * @param vnfName VNF Name or Openstack ID
684 * @param msoRequest Request tracking information for logs
685 * @param vnfExists Flag reporting the result of the query
686 * @param vnfId Holder for output VNF Openstack ID
687 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
690 public void queryVnf (String cloudSiteId,
693 MsoRequest msoRequest,
694 Holder <Boolean> vnfExists,
695 Holder <String> vnfId,
696 Holder <VnfStatus> status,
697 Holder <Map <String, String>> outputs) throws VnfException {
698 MsoLogger.setLogContext (msoRequest);
699 MsoLogger.setServiceName ("QueryVnf");
700 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
702 // Will capture execution time for metrics
703 long startTime = System.currentTimeMillis ();
705 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
707 StackInfo heatStack = null;
708 long subStartTime = System.currentTimeMillis ();
710 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
711 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
712 } catch (MsoException me) {
713 me.addContext ("QueryVNF");
714 // Failed to query the Stack due to an openstack exception.
715 // Convert to a generic VnfException
716 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
717 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
718 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
719 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
720 throw new VnfException (me);
723 // Populate the outputs based on the returned Stack information
725 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
727 vnfExists.value = Boolean.FALSE;
728 status.value = VnfStatus.NOTFOUND;
730 outputs.value = new HashMap <String, String> (); // Return as an empty map
732 LOGGER.debug ("VNF " + vnfName + " not found");
734 vnfExists.value = Boolean.TRUE;
735 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
736 vnfId.value = heatStack.getCanonicalName ();
737 outputs.value = copyStringOutputs (heatStack.getOutputs ());
739 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
741 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
746 * This is the "Delete VNF" web service implementation.
747 * It will delete a VNF by name or ID in the specified cloud and tenant.
749 * The method has no outputs.
751 * @param cloudSiteId CLLI code of the cloud site in which to delete
752 * @param tenantId Openstack tenant identifier
753 * @param vnfName VNF Name or Openstack ID
754 * @param msoRequest Request tracking information for logs
757 public void deleteVnf (String cloudSiteId,
760 MsoRequest msoRequest) throws VnfException {
761 MsoLogger.setLogContext (msoRequest);
762 MsoLogger.setServiceName ("DeleteVnf");
763 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
764 // Will capture execution time for metrics
765 long startTime = System.currentTimeMillis ();
767 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
769 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
770 // The possible outcomes of deleteStack are a StackInfo object with status
771 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
773 long subStartTime = System.currentTimeMillis ();
775 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
776 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
777 } catch (MsoException me) {
778 me.addContext ("DeleteVNF");
779 // Failed to query the Stack due to an openstack exception.
780 // Convert to a generic VnfException
781 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
782 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
783 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
784 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
785 throw new VnfException (me);
788 // On success, nothing is returned.
789 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
794 * This web service endpoint will rollback a previous Create VNF operation.
795 * A rollback object is returned to the client in a successful creation
796 * response. The client can pass that object as-is back to the rollbackVnf
797 * operation to undo the creation.
800 public void rollbackVnf (VnfRollback rollback) throws VnfException {
801 long startTime = System.currentTimeMillis ();
802 MsoLogger.setServiceName ("RollbackVnf");
803 // rollback may be null (e.g. if stack already existed when Create was called)
804 if (rollback == null) {
805 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
806 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
810 // Get the elements of the VnfRollback object for easier access
811 String cloudSiteId = rollback.getCloudSiteId ();
812 String tenantId = rollback.getTenantId ();
813 String vnfId = rollback.getVnfId ();
815 MsoLogger.setLogContext (rollback.getMsoRequest());
817 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
819 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
821 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
822 // The possible outcomes of deleteStack are a StackInfo object with status
823 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
825 long subStartTime = System.currentTimeMillis ();
827 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
828 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
829 } catch (MsoException me) {
830 // Failed to rollback the Stack due to an openstack exception.
831 // Convert to a generic VnfException
832 me.addContext ("RollbackVNF");
833 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
834 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
835 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
836 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
837 throw new VnfException (me);
839 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
843 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
844 switch (stackStatus) {
846 return VnfStatus.ACTIVE;
848 return VnfStatus.ACTIVE;
850 return VnfStatus.FAILED;
852 return VnfStatus.UNKNOWN;
856 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
857 Map <String, String> stringOutputs = new HashMap <String, String> ();
858 for (String key : stackOutputs.keySet ()) {
859 if (stackOutputs.get (key) instanceof String) {
860 stringOutputs.put (key, (String) stackOutputs.get (key));
863 return stringOutputs;
866 private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
867 return new HashMap <String, Object> (stringInputs);
871 * a helper method to make sure that any resource_registry entry of the format
872 * "xx::xx" : yyy.yaml (or yyy.template)
873 * has the file name prepended with "file:///"
874 * Return a String of the environment body that's passed in.
875 * Have to be careful not to mess up the original formatting.
877 private String parseEnvironment (String environment) {
878 StringBuilder sb = new StringBuilder ();
879 try (Scanner scanner = new Scanner (environment)) {
880 scanner.useDelimiter ("\n");
882 Pattern resource = Pattern.compile ("\\s*\"\\w+::\\S+\"\\s*:");
883 LOGGER.debug ("regex pattern for finding a resource_registry: \\s*\"\\w+::\\S+\"\\s*:");
884 while (scanner.hasNextLine ()) {
885 line = scanner.nextLine ();
886 if (line.toLowerCase ().contains ("resource_registry")) {
887 sb.append (line + "\n");
888 boolean done = false;
889 // basically keep scanning until EOF or parameters: section
890 while (scanner.hasNextLine () && !done) {
891 line = scanner.nextLine ();
892 if ("parameters:".equalsIgnoreCase (line.trim ())) {
893 sb.append (line + "\n");
897 Matcher m = resource.matcher (line);
899 sb.append (m.group ());
900 String secondPart = line.substring (m.end ()).trim ();
901 String output = secondPart;
902 if (secondPart.endsWith (".yaml")
903 || secondPart.endsWith (".template") && !secondPart.startsWith ("file:///")) {
904 output = "file:///" + secondPart;
905 LOGGER.debug ("changed " + secondPart + " to " + output);
906 } // don't do anything if it's not .yaml or .template
907 sb.append (" " + output + "\n");
909 sb.append (line + "\n");
913 sb.append (line + "\n");
918 } catch (Exception e) {
919 LOGGER.debug ("Error trying to scan " + environment, e);
922 return sb.toString ();
926 * helper class to add file:/// to the Provider_Resource_File entry in HEAT_NESTED_TEMPLATE
927 * and the File_Name entry in HEAT_FILES if the file:/// part is missing.
929 private String enforceFilePrefix (String string) {
930 if (string.trim ().startsWith ("file:///")) {
934 if (string.trim ().endsWith (".yaml") || string.trim ().endsWith (".template")) {
935 // only .yaml or .template are valid anyway - otherwise don't bother
936 return "file:///" + string.trim ();
938 LOGGER.debug (string + " is NOT a .yaml or .template file");
943 private void sendMapToDebug(Map<String, String> inputs) {
945 StringBuilder sb = new StringBuilder("inputs:");
946 if (inputs == null) {
949 else if (inputs.size() < 1) {
950 sb.append("\tEMPTY");
952 for (String str : inputs.keySet()) {
953 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
956 LOGGER.debug(sb.toString());
960 private String convertNode(final JsonNode node) {
962 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
963 final String json = JSON_MAPPER.writeValueAsString(obj);
965 } catch (JsonParseException jpe) {
966 LOGGER.debug("Error converting json to string " + jpe.getMessage());
967 } catch (Exception e) {
968 LOGGER.debug("Error converting json to string " + e.getMessage());
970 return "[Error converting json to string]";
973 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
974 if (objectMap == null) {
977 Map<String, String> stringMap = new HashMap<String, String>();
978 for (String key : objectMap.keySet()) {
979 if (!stringMap.containsKey(key)) {
980 Object obj = objectMap.get(key);
981 if (obj instanceof String) {
982 stringMap.put(key, (String) objectMap.get(key));
983 } else if (obj instanceof JsonNode ){
984 // This is a bit of mess - but I think it's the least impacting
985 // let's convert it BACK to a string - then it will get converted back later
987 String str = this.convertNode((JsonNode) obj);
988 stringMap.put(key, str);
989 } catch (Exception e) {
990 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for "+ key);
991 //okay in this instance - only string values (fqdn) are expected to be needed
993 } else if (obj instanceof java.util.LinkedHashMap) {
994 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
996 String str = JSON_MAPPER.writeValueAsString(obj);
997 stringMap.put(key, str);
998 } catch (Exception e) {
999 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for "+ key);
1002 // just try to cast it - could be an integer or some such
1004 String str = (String) obj;
1005 stringMap.put(key, str);
1006 } catch (Exception e) {
1007 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for "+ key);
1008 //okay here - only expecting fqdn's
1017 public void createVfModule(String cloudSiteId,
1023 String volumeGroupHeatStackId,
1024 String baseVfHeatStackId,
1025 String modelCustomizationUuid,
1026 Map <String, String> inputs,
1027 Boolean failIfExists,
1029 MsoRequest msoRequest,
1030 Holder <String> vnfId,
1031 Holder <Map <String, String>> outputs,
1032 Holder <VnfRollback> rollback) throws VnfException {
1033 String vfModuleName = vnfName;
1034 String vfModuleType = vnfType;
1035 String vfVersion = vnfVersion;
1036 String mcu = modelCustomizationUuid;
1037 boolean useMCUuid = false;
1038 if (mcu != null && !mcu.isEmpty()) {
1039 if (mcu.equalsIgnoreCase("null")) {
1040 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1044 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1048 MsoLogger.setLogContext (msoRequest);
1049 MsoLogger.setServiceName ("CreateVfModule");
1050 String requestTypeString = "";
1051 if (requestType != null && !requestType.equals("")) {
1052 requestTypeString = requestType;
1054 String nestedStackId = null;
1055 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1056 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1057 nestedStackId = volumeGroupHeatStackId;
1060 String nestedBaseStackId = null;
1061 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1062 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1063 nestedBaseStackId = baseVfHeatStackId;
1067 if (inputs == null) {
1068 // Create an empty set of inputs
1069 inputs = new HashMap<String,String>();
1070 LOGGER.debug("inputs == null - setting to empty");
1072 this.sendMapToDebug(inputs);
1074 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
1075 boolean oldWay = false;
1076 if (requestTypeString.startsWith("X")) {
1078 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
1079 requestTypeString = requestTypeString.substring(1);
1082 // 1607 - let's parse out the request type we're being sent
1083 boolean isBaseRequest = false;
1084 boolean isVolumeRequest = false;
1085 if (requestTypeString.startsWith("VOLUME")) {
1086 isVolumeRequest = true;
1089 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1090 // Will capture execution time for metrics
1091 long startTime = System.currentTimeMillis ();
1093 // Build a default rollback object (no actions performed)
1094 VnfRollback vfRollback = new VnfRollback();
1095 vfRollback.setCloudSiteId(cloudSiteId);
1096 vfRollback.setTenantId(tenantId);
1097 vfRollback.setMsoRequest(msoRequest);
1098 vfRollback.setRequestType(requestTypeString);
1099 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1100 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1101 vfRollback.setIsBase(isBaseRequest);
1102 vfRollback.setModelCustomizationUuid(mcu);
1104 // First, look up to see if the VF already exists.
1105 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1107 StackInfo heatStack = null;
1108 long subStartTime1 = System.currentTimeMillis ();
1110 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1111 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
1112 } catch (MsoException me) {
1113 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1114 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
1115 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
1116 // Failed to query the Stack due to an openstack exception.
1117 // Convert to a generic VnfException
1118 me.addContext ("CreateVFModule");
1119 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1120 throw new VnfException (me);
1122 // New with 1607 - more precise handling/messaging if the stack already exists
1123 if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
1124 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
1125 HeatStatus status = heatStack.getStatus();
1126 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
1127 // fail - it's in progress - return meaningful error
1128 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
1129 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
1130 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
1131 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
1133 if (status == HeatStatus.FAILED) {
1134 // fail - it exists and is in a FAILED state
1135 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
1136 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
1137 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
1138 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
1140 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
1141 // fail - it exists and is in a FAILED state
1142 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
1143 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in UPDATED or UNKNOWN state");
1144 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
1145 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
1147 if (status == HeatStatus.CREATED) {
1149 if (failIfExists != null && failIfExists) {
1150 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
1151 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
1152 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
1153 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
1155 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1156 // Populate the outputs from the existing stack.
1157 vnfId.value = heatStack.getCanonicalName ();
1158 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1159 rollback.value = vfRollback; // Default rollback - no updates performed
1162 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1167 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
1168 StackInfo nestedHeatStack = null;
1169 long subStartTime2 = System.currentTimeMillis ();
1170 if (nestedStackId != null) {
1172 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1173 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1174 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
1175 } catch (MsoException me) {
1176 // Failed to query the Stack due to an openstack exception.
1177 // Convert to a generic VnfException
1178 me.addContext ("CreateVFModule");
1179 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1180 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
1181 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
1182 LOGGER.debug("ERROR trying to query nested stack= " + error);
1183 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1184 throw new VnfException (me);
1186 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1187 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1188 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
1189 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
1190 LOGGER.debug(error);
1191 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1193 LOGGER.debug("Found nested volume heat stack - copying values to inputs");
1194 this.sendMapToDebug(inputs);
1195 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1196 this.sendMapToDebug(inputs);
1200 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
1201 StackInfo nestedBaseHeatStack = null;
1202 long subStartTime3 = System.currentTimeMillis ();
1203 if (nestedBaseStackId != null) {
1205 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1206 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1207 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
1208 } catch (MsoException me) {
1209 // Failed to query the Stack due to an openstack exception.
1210 // Convert to a generic VnfException
1211 me.addContext ("CreateVFModule");
1212 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1213 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
1214 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
1215 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1216 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1217 throw new VnfException (me);
1219 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1220 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1221 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached base heatStack ID DOES NOT EXIST");
1222 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
1223 LOGGER.debug(error);
1224 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1226 LOGGER.debug("Found nested base heat stack - copying values to inputs");
1227 this.sendMapToDebug(inputs);
1228 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1229 this.sendMapToDebug(inputs);
1233 // Ready to deploy the new VNF
1235 CatalogDatabase db = new CatalogDatabase();
1240 VnfResource vnfResource = null;
1241 LOGGER.debug("version: " + vfVersion);
1243 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
1244 vf = db.getVfModuleByModelCustomizationUuid(mcu);
1246 LOGGER.debug("Unable to find vfModule with modelCustomizationUuid=" + mcu);
1247 String error = "Create vfModule error: Unable to find vfModule with modelCustomizationUuid=" + mcu;
1248 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1249 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
1250 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1251 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1253 LOGGER.debug("Found vfModule entry in table! " + vf.toString());
1256 isBaseRequest = true;
1257 LOGGER.debug("This is a BASE VF request!");
1259 LOGGER.debug("This is *not* a BASE VF request!");
1260 if (!isVolumeRequest && nestedBaseStackId == null) {
1261 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1264 } else if (!oldWay) {
1265 // Need to handle old and new schema methods - for a time. Try the new way first.
1266 if (vfVersion != null && !vfVersion.isEmpty()) {
1267 vf = db.getVfModuleType(vfModuleType, vfVersion);
1269 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME");
1270 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
1272 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
1276 vf = db.getVfModuleType(vfModuleType);
1278 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
1279 vf = db.getVfModuleModelName(vfModuleType);
1281 LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
1286 String error = "Create VF Module: Unable to determine specific VF Module Type: "
1288 if (vfVersion != null && !vfVersion.isEmpty()) {
1289 error += " with version = " + vfVersion;
1291 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1292 "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type");
1293 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1294 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1296 LOGGER.debug("Got VF module definition from Catalog: "
1300 isBaseRequest = true;
1301 LOGGER.debug("This is a BASE VF request!");
1303 LOGGER.debug("This is *not* a BASE VF request!");
1304 if (!isVolumeRequest && nestedBaseStackId == null) {
1305 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1309 if (vfVersion != null && !vfVersion.isEmpty()) {
1310 vnfResource = db.getVnfResource(vnfType, vnfVersion);
1312 vnfResource = db.getVnfResource(vnfType);
1314 if (vnfResource == null) {
1315 String error = "Create VNF: Unknown VNF Type: " + vnfType;
1316 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
1317 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
1318 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1319 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1321 LOGGER.debug("Got VNF module definition from Catalog: "
1322 + vnfResource.toString());
1324 // By here - we have either a vf or vnfResource
1326 //1607 - Add version check
1327 // First - see if it's in the VnfResource record
1328 // if we have a vf Module - then we have to query to get the VnfResource record.
1330 if (vf.getVnfResourceId() != null) {
1331 int vnfResourceId = vf.getVnfResourceId();
1332 vnfResource = db.getVnfResourceById(vnfResourceId);
1333 if (vnfResource == null) {
1334 LOGGER.debug("Unable to find vnfResource at " + vnfResourceId + " will not error for now...");
1338 String minVersionVnf = null;
1339 String maxVersionVnf = null;
1340 if (vnfResource != null) {
1342 minVersionVnf = vnfResource.getAicVersionMin();
1343 maxVersionVnf = vnfResource.getAicVersionMax();
1344 } catch (Exception e) {
1345 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry");
1346 minVersionVnf = null;
1347 maxVersionVnf = null;
1349 if (minVersionVnf != null && minVersionVnf.equals("")) {
1350 minVersionVnf = null;
1352 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1353 maxVersionVnf = null;
1356 if (minVersionVnf != null && maxVersionVnf != null) {
1357 MavenLikeVersioning aicV = new MavenLikeVersioning();
1358 CloudSite cloudSite = null;
1359 String aicVersion = "";
1360 if (this.cloudConfig == null) {
1361 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1364 if (this.cloudConfig != null) {
1365 cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1366 if (cloudSite != null) {
1367 aicV.setVersion(cloudSite.getAic_version());
1368 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1369 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV.isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1370 LOGGER.debug("VNF Resource " + vnfResource.getVnfType() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1373 String error = "VNF Resource type: " + vnfResource.getVnfType() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1374 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1375 LOGGER.debug(error);
1376 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1378 } // let this error out downstream to avoid introducing uncertainty at this stage
1380 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1384 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1386 // End Version check 1607
1388 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
1389 // with VNF_RESOURCE - we use the old methods.
1390 Integer heatTemplateId = null;
1391 Integer heatEnvtId = null;
1394 if (isVolumeRequest) {
1395 heatTemplateId = vf.getVolTemplateId();
1396 heatEnvtId = vf.getVolEnvironmentId();
1398 heatTemplateId = vf.getTemplateId();
1399 heatEnvtId = vf.getEnvironmentId();
1402 if (isVolumeRequest) {
1403 VnfComponent vnfComponent = null;
1404 vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME");
1405 if (vnfComponent == null) {
1406 String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME";
1407 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry");
1408 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1409 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1411 heatTemplateId = vnfComponent.getHeatTemplateId();
1412 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1415 heatTemplateId = vnfResource.getTemplateId();
1416 heatEnvtId = vnfResource.getEnvironmentId();
1419 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1420 HeatTemplate heatTemplate = null;
1421 if (heatTemplateId == null) {
1422 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1423 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1424 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1425 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1426 MsoAlarmLogger.CRITICAL, error);
1427 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1429 heatTemplate = db.getHeatTemplate(heatTemplateId);
1431 if (heatTemplate == null) {
1432 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateId;
1433 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1435 String.valueOf(heatTemplateId), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateId);
1436 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1437 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1438 MsoAlarmLogger.CRITICAL, error);
1439 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1441 LOGGER.debug("Got HEAT Template from DB");
1443 HeatEnvironment heatEnvironment = null;
1444 String heatEnvironmentString = null;
1446 if (heatEnvtId != null && heatEnvtId != 0) {
1447 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvtId + ":");
1448 heatEnvironment = db.getHeatEnvironment (heatEnvtId);
1449 if (heatEnvironment == null) {
1450 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1451 + ", Environment ID="
1453 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvtId), "OpenStack", "getHeatEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1454 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1455 // Alarm on this error, configuration must be fixed
1456 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1458 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1460 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1461 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1462 LOGGER.debug ("after parsing: " + heatEnvironmentString);
1465 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
1468 // 1510 - Add the files: for nested templates *if* there are any
1469 LOGGER.debug ("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1470 + heatTemplate.getId ());
1471 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getId ());
1472 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1473 if (nestedTemplates != null) {
1474 // for debugging print them out
1475 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1476 for (String providerResourceFile : nestedTemplates.keySet ()) {
1477 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1478 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1479 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1480 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1483 LOGGER.debug ("No nested templates found - nothing to do here");
1484 nestedTemplatesChecked = null; // just to make sure
1487 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1488 // *if* there are any
1489 Map<String, HeatFiles> heatFiles = null;
1490 Map<String, Object> heatFilesObjects = new HashMap<String, Object>();
1492 // Add ability to turn on adding get_files with volume requests (by property).
1493 boolean addGetFilesOnVolumeReq = false;
1495 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1496 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1497 addGetFilesOnVolumeReq = true;
1498 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1500 } catch (Exception e) {
1501 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1504 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1506 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFiles avec vnfResourceId="
1507 + vnfResource.getId());
1508 heatFiles = db.getHeatFiles(vnfResource.getId());
1510 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1511 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1514 .getHeatFilesForVfModule(vf.getId());
1516 if (heatFiles != null) {
1517 // add these to stack - to be done in createStack
1518 // here, we will map them to Map<String, Object> from
1519 // Map<String, HeatFiles>
1520 // this will match the nested templates format
1521 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1523 for (String heatFileName : heatFiles.keySet()) {
1524 if (heatFileName.startsWith("_ERROR|")) {
1525 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1526 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1527 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1528 LOGGER.debug(error);
1529 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1530 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1531 // Alarm on this error, configuration must be fixed
1532 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1533 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1535 String heatFileBody = heatFiles.get(heatFileName)
1537 String heatFileNameChecked = heatFileName;
1538 LOGGER.debug(heatFileNameChecked + " -> "
1540 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1543 LOGGER.debug("No heat files found -nothing to do here");
1544 heatFilesObjects = null;
1547 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1550 // Check that required parameters have been supplied
1551 String missingParams = null;
1552 List <String> paramList = new ArrayList <String> ();
1554 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1555 // supplied an alias. Only check if we don't find it initially.
1556 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1557 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1559 boolean haveEnvironmentParameters = false;
1560 boolean checkRequiredParameters = true;
1562 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1563 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1564 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1565 checkRequiredParameters = false;
1566 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1567 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1569 } catch (Exception e) {
1570 // No problem - default is true
1571 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1573 // 1604 - Add enhanced environment & parameter checking
1574 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1575 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1576 // Note this also removes any comments
1577 MsoHeatEnvironmentEntry mhee = null;
1578 if (heatEnvironmentString != null && heatEnvironmentString.contains ("parameters:")) {
1579 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1580 LOGGER.debug("Enhanced environment checking enabled - 1604");
1581 haveEnvironmentParameters = true;
1582 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1583 //LOGGER.debug("About to create MHEE with " + sb);
1584 mhee = new MsoHeatEnvironmentEntry(sb);
1585 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1586 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1587 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1589 if (!mhee.isValid()) {
1590 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1592 sb2.append("\nEnvironment:");
1593 sb2.append(mhee.toFullString());
1595 LOGGER.debug(sb2.toString());
1597 LOGGER.debug("NO ENVIRONMENT for this entry");
1599 // This is kind of a mess. inputs is a Map<String, String> --
1600 // if one of the parameters is json - we need to pass String, JsonNode -
1601 // so we will store off the parameters that are json in its own HashMap
1602 // if there are any json params - then we convert inputs to a Map<String, Object>
1603 // and pass that to createStack
1604 HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
1605 boolean hasJson = false;
1607 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1608 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1610 + parm.isRequired ()
1612 + parm.getParamAlias ());
1613 // New 1607 - support json type
1614 String parameterType = parm.getParamType();
1615 if (parameterType == null || parameterType.trim().equals("")) {
1616 parameterType = "String";
1618 JsonNode jsonNode = null;
1619 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
1620 if (inputs.containsKey(parm.getParamName()) ) {
1622 String jsonString = null;
1624 jsonString = inputs.get(parm.getParamName());
1625 jsonNode = new ObjectMapper().readTree(jsonString);
1626 } catch (JsonParseException jpe) {
1627 //TODO - what to do here?
1628 //for now - send the error to debug, but just leave it as a String
1629 String errorMessage = jpe.getMessage();
1630 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage);
1633 } catch (Exception e) {
1635 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
1639 if (jsonNode != null) {
1640 jsonParams.put(parm.getParamName(), jsonNode);
1642 } else if (inputs.containsKey(parm.getParamAlias())) {
1644 String jsonString = null;
1646 jsonString = inputs.get(parm.getParamAlias());
1647 jsonNode = new ObjectMapper().readTree(jsonString);
1648 } catch (JsonParseException jpe) {
1649 //TODO - what to do here?
1650 //for now - send the error to debug, but just leave it as a String
1651 String errorMessage = jpe.getMessage();
1652 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage);
1655 } catch (Exception e) {
1657 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
1661 if (jsonNode != null) {
1662 // Notice here - we add it to the jsonParams hashMap with the actual name -
1663 // then manipulate the inputs so when we check for aliases below - it will not
1665 jsonParams.put(parm.getParamName(), jsonNode);
1666 inputs.remove(parm.getParamAlias());
1667 inputs.put(parm.getParamName(), jsonString);
1669 } //TODO add a check for the parameter in the env file
1671 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
1672 // Check if they have an alias
1673 LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...");
1674 if (inputs.containsKey (parm.getParamAlias ())) {
1675 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1676 String realParamName = parm.getParamName ();
1677 String alias = parm.getParamAlias ();
1678 String value = inputs.get (alias);
1679 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
1684 inputs.remove (alias);
1685 inputs.put (realParamName, value);
1686 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
1688 // enhanced - check if it's in the Environment (note: that method
1689 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1691 LOGGER.debug ("Required parameter " + parm.getParamName ()
1692 + " appears to be in environment - do not count as missing");
1694 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1695 if (missingParams == null) {
1696 missingParams = parm.getParamName ();
1698 missingParams += "," + parm.getParamName ();
1702 paramList.add (parm.getParamName ());
1704 if (missingParams != null) {
1705 if (checkRequiredParameters) {
1706 // Problem - missing one or more required parameters
1707 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1708 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1709 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1710 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1712 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1715 LOGGER.debug ("No missing parameters found - ok to proceed");
1718 // Here - modify heatEnvironmentString
1719 StringBuilder parsedEnvironmentString = null;
1720 String newEnvironmentString = null;
1722 LOGGER.debug("Environment before:\n" + heatEnvironmentString);
1723 parsedEnvironmentString = mhee.toFullStringExcludeNonParams(heatTemplate.getParameters());
1724 LOGGER.debug("Environment after:\n" + parsedEnvironmentString.toString());
1725 newEnvironmentString = parsedEnvironmentString.toString();
1728 // Remove any extraneous parameters (don't throw an error)
1729 if (inputs != null) {
1730 List <String> extraParams = new ArrayList <String> ();
1731 extraParams.addAll (inputs.keySet ());
1732 extraParams.removeAll (paramList);
1733 if (!extraParams.isEmpty ()) {
1734 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
1735 inputs.keySet ().removeAll (extraParams);
1738 // 1607 - when we get here - we have clean inputs. Check if we have
1739 Map<String, Object> inputsTwo = null;
1740 if (hasJson && jsonParams.size() > 0) {
1741 inputsTwo = new HashMap<String, Object>();
1742 for (String keyParamName : inputs.keySet()) {
1743 if (jsonParams.containsKey(keyParamName)) {
1744 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
1746 inputsTwo.put(keyParamName, inputs.get(keyParamName));
1751 // "Fix" the template if it has CR/LF (getting this from Oracle)
1752 String template = heatTemplate.getHeatTemplate ();
1753 template = template.replaceAll ("\r\n", "\n");
1755 // Have the tenant. Now deploy the stack itself
1756 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1757 // because we already checked for those.
1758 long createStackStarttime = System.currentTimeMillis ();
1760 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1761 // heatTemplate.getTimeoutMinutes());
1762 if (backout == null) {
1766 LOGGER.debug("heat is not null!!");
1770 heatStack = heat.createStack (cloudSiteId,
1776 heatTemplate.getTimeoutMinutes (),
1777 newEnvironmentString,
1778 //heatEnvironmentString,
1779 nestedTemplatesChecked,
1781 backout.booleanValue());
1782 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1784 heatStack = heat.createStack (cloudSiteId,
1790 heatTemplate.getTimeoutMinutes (),
1791 newEnvironmentString,
1792 //heatEnvironmentString,
1793 nestedTemplatesChecked,
1795 backout.booleanValue());
1798 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1799 } catch (MsoException me) {
1800 me.addContext ("CreateVFModule");
1801 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1802 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1803 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1804 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1805 throw new VnfException (me);
1806 } catch (NullPointerException npe) {
1807 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1808 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1809 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1810 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1811 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1812 //npe.addContext ("CreateVNF");
1813 throw new VnfException ("NullPointerException during heat.createStack");
1814 } catch (Exception e) {
1815 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1816 LOGGER.debug("unhandled exception at heat.createStack");
1817 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1818 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1820 } catch (Exception e) {
1821 LOGGER.debug("unhandled exception in create VF");
1822 throw new VnfException("Exception during create VF " + e.getMessage());
1825 // Make sure DB session is closed
1829 // Reach this point if createStack is successful.
1830 // Populate remaining rollback info and response parameters.
1831 vfRollback.setVnfId (heatStack.getCanonicalName ());
1832 vfRollback.setVnfCreated (true);
1834 vnfId.value = heatStack.getCanonicalName ();
1835 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1836 rollback.value = vfRollback;
1838 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1839 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1845 public void deleteVfModule (String cloudSiteId,
1848 MsoRequest msoRequest,
1849 Holder <Map <String, String>> outputs) throws VnfException {
1850 MsoLogger.setLogContext (msoRequest);
1851 MsoLogger.setServiceName ("DeleteVf");
1852 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1853 // Will capture execution time for metrics
1854 long startTime = System.currentTimeMillis ();
1856 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1858 // 1702 capture the output parameters on a delete
1859 // so we'll need to query first
1860 Map<String, Object> stackOutputs = null;
1862 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1863 } catch (MsoException me) {
1864 // Failed to query the Stack due to an openstack exception.
1865 // Convert to a generic VnfException
1866 me.addContext ("DeleteVFModule");
1867 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1868 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1869 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1870 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1871 throw new VnfException (me);
1873 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1874 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1876 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1877 // The possible outcomes of deleteStack are a StackInfo object with status
1878 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1880 long subStartTime = System.currentTimeMillis ();
1882 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1883 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1884 } catch (MsoException me) {
1885 me.addContext ("DeleteVNF");
1886 // Failed to query the Stack due to an openstack exception.
1887 // Convert to a generic VnfException
1888 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1889 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1890 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1891 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1892 throw new VnfException (me);
1895 // On success, nothing is returned.
1896 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1901 public void updateVfModule (String cloudSiteId,
1907 String volumeGroupHeatStackId,
1908 String baseVfHeatStackId,
1909 String vfModuleStackId,
1910 String modelCustomizationUuid,
1911 Map <String, String> inputs,
1912 MsoRequest msoRequest,
1913 Holder <Map <String, String>> outputs,
1914 Holder <VnfRollback> rollback) throws VnfException {
1915 String vfModuleName = vnfName;
1916 String vfModuleType = vnfType;
1917 String vfVersion = vnfVersion;
1918 String methodName = "updateVfModule";
1919 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1920 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1921 MsoLogger.setServiceName (serviceName);
1923 String mcu = modelCustomizationUuid;
1924 boolean useMCUuid = false;
1925 if (mcu != null && !mcu.isEmpty()) {
1926 if (mcu.equalsIgnoreCase("null")) {
1927 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1931 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1936 String requestTypeString = "";
1937 if (requestType != null && !requestType.equals("")) {
1938 requestTypeString = requestType;
1940 String nestedStackId = null;
1941 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1942 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1943 nestedStackId = volumeGroupHeatStackId;
1946 String nestedBaseStackId = null;
1947 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1948 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1949 nestedBaseStackId = baseVfHeatStackId;
1953 if (inputs == null) {
1954 // Create an empty set of inputs
1955 inputs = new HashMap<String,String>();
1956 LOGGER.debug("inputs == null - setting to empty");
1958 this.sendMapToDebug(inputs);
1960 boolean isBaseRequest = false;
1961 boolean isVolumeRequest = false;
1962 if (requestTypeString.startsWith("VOLUME")) {
1963 isVolumeRequest = true;
1965 if (vfModuleName == null || vfModuleName.trim().equals("")) {
1966 if (vfModuleStackId != null) {
1967 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1971 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1972 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1974 // Will capture execution time for metrics
1975 long startTime = System.currentTimeMillis ();
1977 // Build a default rollback object (no actions performed)
1978 VnfRollback vfRollback = new VnfRollback ();
1979 vfRollback.setCloudSiteId (cloudSiteId);
1980 vfRollback.setTenantId (tenantId);
1981 vfRollback.setMsoRequest (msoRequest);
1982 vfRollback.setRequestType(requestTypeString);
1983 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1984 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1985 vfRollback.setIsBase(isBaseRequest);
1986 vfRollback.setVfModuleStackId(vfModuleStackId);
1987 vfRollback.setModelCustomizationUuid(mcu);
1989 // First, look up to see if the VNF already exists.
1990 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1991 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1993 StackInfo heatStack = null;
1994 long queryStackStarttime = System.currentTimeMillis ();
1995 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1997 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1998 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1999 } catch (MsoException me) {
2000 // Failed to query the Stack due to an openstack exception.
2001 // Convert to a generic VnfException
2002 me.addContext ("UpdateVFModule");
2003 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2004 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
2005 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
2006 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2007 throw new VnfException (me);
2010 //TODO - do we need to check for the other status possibilities?
2011 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
2013 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
2014 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
2015 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
2016 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
2018 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
2019 // Populate the outputs from the existing stack.
2020 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2021 rollback.value = vfRollback; // Default rollback - no updates performed
2024 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
2025 StackInfo nestedHeatStack = null;
2026 long queryStackStarttime2 = System.currentTimeMillis ();
2027 if (nestedStackId != null) {
2029 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
2030 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
2031 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
2032 } catch (MsoException me) {
2033 // Failed to query the Stack due to an openstack exception.
2034 // Convert to a generic VnfException
2035 me.addContext ("UpdateVFModule");
2036 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
2037 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
2038 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2039 LOGGER.debug("ERROR trying to query nested stack= " + error);
2040 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2041 throw new VnfException (me);
2043 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
2044 MsoLogger.setServiceName (serviceName);
2045 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
2046 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
2047 LOGGER.debug(error);
2048 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
2049 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2051 LOGGER.debug("Found nested heat stack - copying values to inputs");
2052 this.sendMapToDebug(inputs);
2053 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
2054 this.sendMapToDebug(inputs);
2057 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
2058 StackInfo nestedBaseHeatStack = null;
2059 if (nestedBaseStackId != null) {
2060 long queryStackStarttime3 = System.currentTimeMillis ();
2062 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
2063 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
2064 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
2065 } catch (MsoException me) {
2066 // Failed to query the Stack due to an openstack exception.
2067 // Convert to a generic VnfException
2068 me.addContext ("UpdateVfModule");
2069 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
2070 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
2071 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2072 LOGGER.debug("ERROR trying to query nested base stack= " + error);
2073 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2074 throw new VnfException (me);
2076 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
2077 MsoLogger.setServiceName (serviceName);
2078 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
2079 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
2080 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
2081 LOGGER.debug(error);
2082 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2084 LOGGER.debug("Found nested base heat stack - copying values to inputs");
2085 this.sendMapToDebug(inputs);
2086 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
2087 this.sendMapToDebug(inputs);
2091 // Ready to deploy the new VNF
2092 // Get a handle to the Catalog Database
2093 CatalogDatabase db = new CatalogDatabase ();
2095 // Make sure DB session is closed
2097 // Retrieve the VF definition
2101 vf = db.getVfModuleByModelCustomizationUuid(mcu);
2103 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
2106 else if (vfVersion != null && !vfVersion.isEmpty ()) {
2107 vf = db.getVfModuleType(vfModuleType, vfVersion);
2109 LOGGER.debug("Unable to find " + vfModuleType + " and version = " + vfVersion + " in the TYPE column - will try in MODEL_NAME");
2110 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
2112 LOGGER.debug("Unable to find " + vfModuleType + " and version = " + vfVersion + " in the MODEL_NAME field either - ERROR");
2116 vf = db.getVfModuleType(vfModuleType);
2118 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
2119 vf = db.getVfModuleModelName(vfModuleType);
2121 LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
2128 error = "Update VFModule: Unknown VF Module Type: " + vfModuleType;
2129 if (vfVersion != null && !vfVersion.isEmpty()) {
2130 error += " with version = " + vfVersion;
2133 error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
2135 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2136 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
2137 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2139 LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
2141 HeatTemplate heatTemplate = null;
2142 Integer heatTemplateId = null;
2143 Integer heatEnvtId = null;
2144 if (!isVolumeRequest) {
2145 heatTemplateId = vf.getTemplateId();
2146 heatEnvtId = vf.getEnvironmentId();
2148 heatTemplateId = vf.getVolTemplateId();
2149 heatEnvtId = vf.getVolEnvironmentId();
2151 if (heatTemplateId == null) {
2152 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
2153 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2154 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
2155 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
2156 MsoAlarmLogger.CRITICAL, error);
2157 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
2159 heatTemplate = db.getHeatTemplate(heatTemplateId);
2162 if (heatTemplate == null) {
2163 String error = "Update VNF: undefined Heat Template. VF="
2164 + vfModuleType + ", heat template id = " + heatTemplateId;
2165 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
2167 String.valueOf(heatTemplateId), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2168 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
2169 // Alarm on this error, configuration must be fixed
2170 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
2171 MsoAlarmLogger.CRITICAL, error);
2173 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
2176 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
2178 // Add check for any Environment variable
2179 HeatEnvironment heatEnvironment = null;
2180 String heatEnvironmentString = null;
2182 if (heatEnvtId != null) {
2183 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvtId + ":");
2184 heatEnvironment = db.getHeatEnvironment (heatEnvtId);
2185 if (heatEnvironment == null) {
2187 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
2188 + ", Environment ID="
2190 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvtId), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2191 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
2192 // Alarm on this error, configuration must be fixed
2193 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
2195 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
2197 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
2198 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
2199 LOGGER.debug ("After parsing: " + heatEnvironmentString);
2202 LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType);
2206 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
2207 + heatTemplate.getId ());
2208 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getId ());
2209 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
2210 if (nestedTemplates != null) {
2211 // for debugging print them out
2212 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
2213 for (String providerResourceFile : nestedTemplates.keySet ()) {
2214 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
2215 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
2216 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
2217 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
2220 LOGGER.debug ("No nested templates found - nothing to do here");
2221 nestedTemplatesChecked = null;
2224 // Also add the files: for any get_files associated with this VfModule
2225 // *if* there are any
2226 LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
2229 Map <String, HeatFiles> heatFiles = null;
2230 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
2231 Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
2233 // Add ability to turn on adding get_files with volume requests (by property).
2234 boolean addGetFilesOnVolumeReq = false;
2236 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
2237 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
2238 addGetFilesOnVolumeReq = true;
2239 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
2241 } catch (Exception e) {
2242 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
2244 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
2245 heatFiles = db.getHeatFilesForVfModule(vf.getId());
2246 if (heatFiles != null) {
2247 // add these to stack - to be done in createStack
2248 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
2249 // this will match the nested templates format
2250 LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
2252 for (String heatFileName : heatFiles.keySet ()) {
2253 if (heatFileName.startsWith("_ERROR|")) {
2254 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
2255 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
2256 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
2257 LOGGER.debug(error);
2258 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2259 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
2260 // Alarm on this error, configuration must be fixed
2261 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
2262 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
2264 String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
2265 LOGGER.debug (heatFileName + " -> " + heatFileBody);
2266 heatFilesObjects.put (heatFileName, heatFileBody);
2269 LOGGER.debug ("No heat files found -nothing to do here");
2270 heatFilesObjects = null;
2274 // Check that required parameters have been supplied
2275 String missingParams = null;
2276 List <String> paramList = new ArrayList <String> ();
2278 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
2279 // supplied an alias. Only check if we don't find it initially.
2280 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
2281 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
2283 boolean haveEnvironmentParameters = false;
2284 boolean checkRequiredParameters = true;
2286 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
2287 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
2288 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
2289 checkRequiredParameters = false;
2290 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
2291 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
2293 } catch (Exception e) {
2294 // No problem - default is true
2295 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
2297 // 1604 - Add enhanced environment & parameter checking
2298 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
2299 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
2300 // Note this also removes any comments
2301 MsoHeatEnvironmentEntry mhee = null;
2302 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) {
2303 LOGGER.debug("Enhanced environment checking enabled - 1604");
2304 haveEnvironmentParameters = true;
2305 StringBuilder sb = new StringBuilder(heatEnvironmentString);
2306 //LOGGER.debug("About to create MHEE with " + sb);
2307 mhee = new MsoHeatEnvironmentEntry(sb);
2308 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
2309 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
2310 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
2312 if (!mhee.isValid()) {
2313 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
2315 sb2.append("\nEnvironment:");
2316 sb2.append(mhee.toFullString());
2318 LOGGER.debug(sb2.toString());
2320 LOGGER.debug("NO ENVIRONMENT for this entry");
2323 // New for 1607 - support params of json type
2324 HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
2325 boolean hasJson = false;
2327 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
2328 LOGGER.debug ("Parameter:'" + parm.getParamName ()
2330 + parm.isRequired ()
2332 + parm.getParamAlias ());
2334 String parameterType = parm.getParamType();
2335 if (parameterType == null || parameterType.trim().equals("")) {
2336 parameterType = "String";
2338 JsonNode jsonNode = null;
2339 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
2340 if (inputs.containsKey(parm.getParamName()) ) {
2342 String jsonString = null;
2344 jsonString = inputs.get(parm.getParamName());
2345 jsonNode = new ObjectMapper().readTree(jsonString);
2346 } catch (JsonParseException jpe) {
2347 //TODO - what to do here?
2348 //for now - send the error to debug, but just leave it as a String
2349 String errorMessage = jpe.getMessage();
2350 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage);
2353 } catch (Exception e) {
2355 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
2359 if (jsonNode != null) {
2360 jsonParams.put(parm.getParamName(), jsonNode);
2362 } else if (inputs.containsKey(parm.getParamAlias())) {
2364 String jsonString = null;
2366 jsonString = inputs.get(parm.getParamAlias());
2367 jsonNode = new ObjectMapper().readTree(jsonString);
2368 } catch (JsonParseException jpe) {
2369 //TODO - what to do here?
2370 //for now - send the error to debug, but just leave it as a String
2371 String errorMessage = jpe.getMessage();
2372 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage);
2375 } catch (Exception e) {
2377 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
2381 if (jsonNode != null) {
2382 // Notice here - we add it to the jsonParams hashMap with the actual name -
2383 // then manipulate the inputs so when we check for aliases below - it will not
2385 jsonParams.put(parm.getParamName(), jsonNode);
2386 inputs.remove(parm.getParamAlias());
2387 inputs.put(parm.getParamName(), jsonString);
2389 } //TODO add a check for the parameter in the env file
2392 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
2393 if (inputs.containsKey (parm.getParamAlias ())) {
2394 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2395 String realParamName = parm.getParamName ();
2396 String alias = parm.getParamAlias ();
2397 String value = inputs.get (alias);
2398 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
2403 inputs.remove (alias);
2404 inputs.put (realParamName, value);
2405 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
2407 // enhanced - check if it's in the Environment (note: that method
2408 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2410 LOGGER.debug ("Required parameter " + parm.getParamName ()
2411 + " appears to be in environment - do not count as missing");
2414 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
2415 if (missingParams == null) {
2416 missingParams = parm.getParamName ();
2418 missingParams += "," + parm.getParamName ();
2422 paramList.add (parm.getParamName ());
2424 if (missingParams != null) {
2425 // Problem - missing one or more required parameters
2426 if (checkRequiredParameters) {
2427 String error = "Update VNF: Missing Required inputs: " + missingParams;
2428 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2429 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
2430 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2432 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
2435 LOGGER.debug ("No missing parameters found - ok to proceed");
2438 // Here - modify heatEnvironmentString
2439 StringBuilder parsedEnvironmentString = null;
2440 String newEnvironmentString = null;
2442 LOGGER.debug("Environment before:\n" + heatEnvironmentString);
2443 parsedEnvironmentString = mhee.toFullStringExcludeNonParams(heatTemplate.getParameters());
2444 LOGGER.debug("Environment after:\n" + parsedEnvironmentString.toString());
2445 newEnvironmentString = parsedEnvironmentString.toString();
2448 // Remove any extraneous parameters (don't throw an error)
2449 if (inputs != null) {
2450 List <String> extraParams = new ArrayList <String> ();
2451 extraParams.addAll (inputs.keySet ());
2452 // This is not a valid parameter for this template
2453 extraParams.removeAll (paramList);
2454 if (!extraParams.isEmpty ()) {
2455 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
2456 inputs.keySet ().removeAll (extraParams);
2459 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2460 Map<String, Object> inputsTwo = null;
2461 if (hasJson && jsonParams.size() > 0) {
2462 inputsTwo = new HashMap<String, Object>();
2463 for (String keyParamName : inputs.keySet()) {
2464 if (jsonParams.containsKey(keyParamName)) {
2465 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2467 inputsTwo.put(keyParamName, inputs.get(keyParamName));
2472 // "Fix" the template if it has CR/LF (getting this from Oracle)
2473 String template = heatTemplate.getHeatTemplate ();
2474 template = template.replaceAll ("\r\n", "\n");
2476 // Have the tenant. Now deploy the stack itself
2477 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2478 // because we already checked for those.
2479 long updateStackStarttime = System.currentTimeMillis ();
2482 heatStack = heatU.updateStack (cloudSiteId,
2486 copyStringInputs (inputs),
2488 heatTemplate.getTimeoutMinutes (),
2489 newEnvironmentString,
2490 //heatEnvironmentString,
2491 nestedTemplatesChecked,
2493 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2495 heatStack = heatU.updateStack (cloudSiteId,
2501 heatTemplate.getTimeoutMinutes (),
2502 newEnvironmentString,
2503 //heatEnvironmentString,
2504 nestedTemplatesChecked,
2506 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2509 } catch (MsoException me) {
2510 me.addContext ("UpdateVFModule");
2511 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2512 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2513 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2514 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2515 throw new VnfException (me);
2518 // Make sure DB session is closed
2522 // Reach this point if updateStack is successful.
2523 // Populate remaining rollback info and response parameters.
2524 vfRollback.setVnfId (heatStack.getCanonicalName ());
2525 vfRollback.setVnfCreated (true);
2527 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2528 rollback.value = vfRollback;
2529 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2533 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2534 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2535 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2536 if (vfModuleStackId == null)
2538 int index = vfModuleStackId.lastIndexOf('/');
2541 String vfModuleName = null;
2543 vfModuleName = vfModuleStackId.substring(0, index);
2544 } catch (Exception e) {
2545 vfModuleName = null;
2547 return vfModuleName;