e998fe8afea4b825a9ad6b927da5762100a7c0b4
[so.git] / adapters / mso-vnf-adapter / src / main / java / org / openecomp / mso / adapters / vnf / MsoVnfAdapterImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * OPENECOMP - MSO
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.openecomp.mso.adapters.vnf;
22
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Scanner;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31
32 import javax.jws.WebService;
33 import javax.xml.ws.Holder;
34
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;
64
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;
70
71 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
72 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
73
74         CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
75         protected CloudConfig cloudConfig = null;
76
77         MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
78
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();
88
89     /**
90      * Health Check web method. Does nothing but return to show the adapter is deployed.
91      */
92     @Override
93     public void healthCheck () {
94         LOGGER.debug ("Health check call in VNF Adapter");
95     }
96
97     /**
98      * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
99      * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
100      */
101     public MsoVnfAdapterImpl() {
102
103     }
104
105     /**
106      * This constructor MUST be used if this class is called with the new operator.
107      * @param msoPropFactory
108      */
109     public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
110         this.msoPropertiesFactory = msoPropFactory;
111         this.cloudConfigFactory = cloudConfigFact;
112     }
113
114     /**
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.
118      *
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.
121      *
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.)
126      * to the cloud.
127      *
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.
131      *
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.
137      *
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
150      */
151     @Override
152     public void createVnf (String cloudSiteId,
153                            String tenantId,
154                            String vnfType,
155                            String vnfVersion,
156                            String vnfName,
157                            String requestType,
158                            String volumeGroupHeatStackId,
159                            Map <String, String> inputs,
160                            Boolean failIfExists,
161                            Boolean backout,
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 = "";
173                         try {
174                                 if (volumeGroupHeatStackId != null) {
175                                         vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
176                                         vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
177                                 }
178                         } catch (Exception e) {
179                                 // might be ok - both are just blank
180                                 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId);
181                         }
182                         this.createVfModule(cloudSiteId,
183                                         tenantId,
184                                         vnfType,
185                                         vnfVersion,
186                                         vnfName,
187                                         newRequestType,
188                                         vfVolGroupHeatStackId,
189                                         vfBaseHeatStackId,
190                         null,
191                                         inputs,
192                                         failIfExists,
193                                         backout,
194                                         msoRequest,
195                                         vnfId,
196                                         outputs,
197                                         rollback);
198                         return;
199                 }
200         }
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);
207         }
208                 this.createVfModule(cloudSiteId,
209                                 tenantId,
210                                 vnfType,
211                                 vnfVersion,
212                                 vnfName,
213                                 newRequestTypeSb.toString(),
214                                 vfVolGroupHeatStackId,
215                                 vfBaseHeatStackId,
216                 null,
217                                 inputs,
218                                 failIfExists,
219                                 backout,
220                                 msoRequest,
221                                 vnfId,
222                                 outputs,
223                                 rollback);
224         return;
225         // End createVf shortcut
226     }
227
228     @Override
229     public void updateVnf (String cloudSiteId,
230                            String tenantId,
231                            String vnfType,
232                            String vnfVersion,
233                            String vnfName,
234                            String requestType,
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;
245         }
246         String nestedStackId = null;
247         if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
248                 nestedStackId = volumeGroupHeatStackId;
249         }
250
251         LOGGER.debug ("Updating VNF: " + vnfName + " of type " + vnfType + "in " + cloudSiteId + "/" + tenantId);
252         LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId);
253
254         // Will capture execution time for metrics
255         long startTime = System.currentTimeMillis ();
256
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);
263
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);
267
268         StackInfo heatStack = null;
269         long queryStackStarttime1 = System.currentTimeMillis ();
270         try {
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);
282         }
283
284         if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
285             // Not Found
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);
290         } else {
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
295         }
296
297         // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
298         StackInfo nestedHeatStack = null;
299         long queryStackStarttime2 = System.currentTimeMillis ();
300         if (nestedStackId != null) {
301                 try {
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);
315                 }
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);
320                     LOGGER.debug(error);
321                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
322                 } else {
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);
327                 }
328         }
329
330         // Ready to deploy the new VNF
331
332         // Get a handle to the Catalog Database
333         CatalogDatabase db = new CatalogDatabase ();
334
335         // Make sure DB session is closed
336         try {
337             // Retrieve the VNF definition
338             VnfResource vnf;
339             if (vnfVersion != null && !vnfVersion.isEmpty ()) {
340                 vnf = db.getVnfResource (vnfType, vnfVersion);
341             } else {
342                 vnf = db.getVnfResource (vnfType);
343             }
344             if (vnf == null) {
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);
349             }
350             LOGGER.debug ("Got VNF definition from Catalog: " + vnf.toString ());
351
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);
360             }
361
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);
372                 }
373                 LOGGER.debug("FOUND VnfComponent: " + vnfComponent.toString());
374             }
375
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);
383
384                 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
385             }
386
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="
396                                                         + vnfType;
397                                         LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
398                                                         "Heat Template ID",
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);
404                                 }
405                         }
406
407             LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
408
409             // Add check for any Environment variable
410             HeatEnvironment heatEnvironment = null;
411             String heatEnvironmentString = null;
412
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) {
417
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);
425
426                     throw new VnfException (error, MsoExceptionCategory.INTERNAL);
427                 } else {
428                     LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
429                     heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
430                     LOGGER.debug ("After parsing: " + heatEnvironmentString);
431                 }
432             } else {
433                 LOGGER.debug ("no environment parameter for this VNF " + vnfType);
434             }
435
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);
449
450                         throw new VnfException (error, MsoExceptionCategory.INTERNAL);
451                     } else {
452                         LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
453                         heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
454                         LOGGER.debug ("after parsing: " + heatEnvironmentString);
455                     }
456                 } else {
457                     LOGGER.debug ("no environment parameter for this VNF VOLUME component " + vnfType);
458                 }
459             }
460             // End 1604
461
462
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);
475                 }
476             } else {
477                 LOGGER.debug ("No nested templates found - nothing to do here");
478                 nestedTemplatesChecked = null;
479             }
480
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="
484                           + vnf.getId ());
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:");
492
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);
500                 }
501             } else {
502                 LOGGER.debug ("No heat files found -nothing to do here");
503                 heatFilesObjects = null;
504             }
505
506             // Check that required parameters have been supplied
507             String missingParams = null;
508             List <String> paramList = new ArrayList <String> ();
509
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
514             // shouldn't
515             boolean haveEnvironmentParameters = false;
516             boolean checkRequiredParameters = true;
517             try {
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);
524                 }
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);
528             }
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());
543                 }
544                 if (!mhee.isValid()) {
545                         sb2.append("Environment says it's not valid! " + mhee.getErrorString());
546                 } else {
547                         sb2.append("\nEnvironment:");
548                         sb2.append(mhee.toFullString());
549                 }
550                 LOGGER.debug(sb2.toString());
551             } else {
552                 LOGGER.debug("NO ENVIRONMENT for this entry");
553             }
554
555             for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
556                 LOGGER.debug ("Parameter:'" + parm.getParamName ()
557                               + "', isRequired="
558                               + parm.isRequired ()
559                               + ", alias="
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
568                                       + ",alias="
569                                       + alias
570                                       + ",value="
571                                       + value);
572                         inputs.remove (alias);
573                         inputs.put (realParamName, value);
574                         LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
575                     }
576                     // enhanced - check if it's in the Environment (note: that method
577                     else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
578
579                         LOGGER.debug ("Required parameter " + parm.getParamName ()
580                                       + " appears to be in environment - do not count as missing");
581                     }
582                     else {
583                         LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
584                         if (missingParams == null) {
585                             missingParams = parm.getParamName ();
586                         } else {
587                             missingParams += "," + parm.getParamName ();
588                         }
589                     }
590                 }
591                 paramList.add (parm.getParamName ());
592             }
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);
600                 } else {
601                         LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
602                 }
603             } else {
604                 LOGGER.debug ("No missing parameters found - ok to proceed");
605             }
606
607             // Here - modify heatEnvironmentString
608             StringBuilder parsedEnvironmentString = null;
609             String newEnvironmentString = null;
610             if (mhee != 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();
615             }
616
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);
626                 }
627             }
628
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");
632
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 ();
637             try {
638                 heatStack = heatU.updateStack (cloudSiteId,
639                                                tenantId,
640                                                vnfName,
641                                                template,
642                                                copyStringInputs (inputs),
643                                                true,
644                                                heatTemplate.getTimeoutMinutes (),
645                                                newEnvironmentString,
646                                                //heatEnvironmentString,
647                                                nestedTemplatesChecked,
648                                                heatFilesObjects);
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);
657             }
658         } finally {
659             // Make sure DB session is closed
660             db.close ();
661         }
662
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);
667
668         outputs.value = copyStringOutputs (heatStack.getOutputs ());
669         rollback.value = vnfRollback;
670         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VNF");
671         return;
672     }
673
674     /**
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.
677      *
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).
680      *
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)
688      */
689     @Override
690     public void queryVnf (String cloudSiteId,
691                           String tenantId,
692                           String vnfName,
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);
701
702         // Will capture execution time for metrics
703         long startTime = System.currentTimeMillis ();
704
705         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
706
707         StackInfo heatStack = null;
708         long subStartTime = System.currentTimeMillis ();
709         try {
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);
721         }
722
723         // Populate the outputs based on the returned Stack information
724         //
725         if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
726             // Not Found
727             vnfExists.value = Boolean.FALSE;
728             status.value = VnfStatus.NOTFOUND;
729             vnfId.value = null;
730             outputs.value = new HashMap <String, String> (); // Return as an empty map
731
732             LOGGER.debug ("VNF " + vnfName + " not found");
733         } else {
734             vnfExists.value = Boolean.TRUE;
735             status.value = stackStatusToVnfStatus (heatStack.getStatus ());
736             vnfId.value = heatStack.getCanonicalName ();
737             outputs.value = copyStringOutputs (heatStack.getOutputs ());
738
739             LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
740         }
741         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
742         return;
743     }
744
745     /**
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.
748      *
749      * The method has no outputs.
750      *
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
755      */
756     @Override
757     public void deleteVnf (String cloudSiteId,
758                            String tenantId,
759                            String vnfName,
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 ();
766
767         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
768
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
772         // could be thrown.
773         long subStartTime = System.currentTimeMillis ();
774         try {
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);
786         }
787
788         // On success, nothing is returned.
789         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
790         return;
791     }
792
793     /**
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.
798      */
799     @Override
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");
807             return;
808         }
809
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 ();
814
815         MsoLogger.setLogContext (rollback.getMsoRequest());
816
817         LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
818
819         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
820
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
824         // could be thrown.
825         long subStartTime = System.currentTimeMillis ();
826         try {
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);
838         }
839         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
840         return;
841     }
842
843     private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
844         switch (stackStatus) {
845             case CREATED:
846                 return VnfStatus.ACTIVE;
847             case UPDATED:
848                 return VnfStatus.ACTIVE;
849             case FAILED:
850                 return VnfStatus.FAILED;
851             default:
852                 return VnfStatus.UNKNOWN;
853         }
854     }
855
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));
861             }
862         }
863         return stringOutputs;
864     }
865
866     private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
867         return new HashMap <String, Object> (stringInputs);
868     }
869
870     /*
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.
876      */
877     private String parseEnvironment (String environment) {
878         StringBuilder sb = new StringBuilder ();
879         try (Scanner scanner = new Scanner (environment)) {
880             scanner.useDelimiter ("\n");
881             String line = null;
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");
894                             done = true;
895                             break;
896                         }
897                         Matcher m = resource.matcher (line);
898                         if (m.find ()) {
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");
908                         } else {
909                             sb.append (line + "\n");
910                         }
911                     }
912                 } else {
913                     sb.append (line + "\n");
914                     continue;
915                 }
916             }
917             scanner.close ();
918         } catch (Exception e) {
919             LOGGER.debug ("Error trying to scan " + environment, e);
920             return environment;
921         }
922         return sb.toString ();
923     }
924
925     /*
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.
928      */
929     private String enforceFilePrefix (String string) {
930         if (string.trim ().startsWith ("file:///")) {
931             // just leave it
932             return string;
933         }
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 ();
937         } else {
938             LOGGER.debug (string + " is NOT a .yaml or .template file");
939         }
940         return string;
941     }
942
943     private void sendMapToDebug(Map<String, String> inputs) {
944         int i = 0;
945         StringBuilder sb = new StringBuilder("inputs:");
946         if (inputs == null) {
947                 sb.append("\tNULL");
948         }
949         else if (inputs.size() < 1) {
950                 sb.append("\tEMPTY");
951         } else {
952                 for (String str : inputs.keySet()) {
953                         sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
954                 }
955         }
956         LOGGER.debug(sb.toString());
957         return;
958     }
959
960     private String convertNode(final JsonNode node) {
961         try {
962             final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
963             final String json = JSON_MAPPER.writeValueAsString(obj);
964             return json;
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());
969         }
970         return "[Error converting json to string]";
971     }
972
973     private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
974         if (objectMap == null) {
975             return null;
976         }
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
986                     try {
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
992                     }
993                 } else if (obj instanceof java.util.LinkedHashMap) {
994                     LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
995                     try {
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);
1000                     }
1001                 } else {
1002                     // just try to cast it - could be an integer or some such
1003                     try {
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
1009                     }
1010                 }
1011             }
1012         }
1013
1014         return stringMap;
1015     }
1016
1017     public void createVfModule(String cloudSiteId,
1018             String tenantId,
1019             String vnfType,
1020             String vnfVersion,
1021             String vnfName,
1022             String requestType,
1023             String volumeGroupHeatStackId,
1024             String baseVfHeatStackId,
1025             String modelCustomizationUuid,
1026             Map <String, String> inputs,
1027             Boolean failIfExists,
1028             Boolean backout,
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);
1041                 useMCUuid = false;
1042                 mcu = "";
1043             } else {
1044                 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1045                 useMCUuid = true;
1046             }
1047         }
1048         MsoLogger.setLogContext (msoRequest);
1049         MsoLogger.setServiceName ("CreateVfModule");
1050         String requestTypeString = "";
1051         if (requestType != null && !requestType.equals("")) {
1052                 requestTypeString = requestType;
1053         }
1054         String nestedStackId = null;
1055         if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1056                 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1057                         nestedStackId = volumeGroupHeatStackId;
1058                 }
1059         }
1060         String nestedBaseStackId = null;
1061         if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1062                 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1063                         nestedBaseStackId = baseVfHeatStackId;
1064                 }
1065         }
1066
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");
1071         } else {
1072                 this.sendMapToDebug(inputs);
1073         }
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")) {
1077                 oldWay = true;
1078                 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
1079                 requestTypeString = requestTypeString.substring(1);
1080         }
1081
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;
1087         }
1088
1089         LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1090         // Will capture execution time for metrics
1091         long startTime = System.currentTimeMillis ();
1092
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);
1103
1104         // First, look up to see if the VF already exists.
1105         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1106
1107         StackInfo heatStack = null;
1108         long subStartTime1 = System.currentTimeMillis ();
1109         try {
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);
1121         }
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 ());
1132                 }
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 ());
1139                 }
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 ());
1146                 }
1147                 if (status == HeatStatus.CREATED) {
1148                         // fail - it exists
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 ());
1154                         } else {
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
1160                         }
1161                 }
1162             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1163             return;
1164
1165         }
1166
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) {
1171                 try {
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);
1185                 }
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);
1192                 } else {
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);
1197                 }
1198         }
1199
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) {
1204                 try {
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);
1218                 }
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);
1225                 } else {
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);
1230                 }
1231         }
1232
1233         // Ready to deploy the new VNF
1234
1235         CatalogDatabase db = new CatalogDatabase();
1236
1237         try {
1238             // Retrieve the VF
1239                 VfModule vf = null;
1240                 VnfResource vnfResource = null;
1241                 LOGGER.debug("version: " + vfVersion);
1242             if (useMCUuid) {
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);
1245                 if (vf == null) {
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);
1252                 } else {
1253                     LOGGER.debug("Found vfModule entry in table! " + vf.toString());
1254                 }
1255                 if (vf.isBase()) {
1256                     isBaseRequest = true;
1257                     LOGGER.debug("This is a BASE VF request!");
1258                 } else {
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");
1262                     }
1263                 }
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);
1268                                         if (vf == null) {
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);
1271                                                 if (vf == null) {
1272                                                         LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
1273                                                 }
1274                                         }
1275                                 } else {
1276                                         vf = db.getVfModuleType(vfModuleType);
1277                                         if (vf == null) {
1278                                                 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
1279                                                 vf = db.getVfModuleModelName(vfModuleType);
1280                                                 if (vf == null) {
1281                                                         LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
1282                                                 }
1283                                         }
1284                                 }
1285                                 if (vf == null) {
1286                                         String error = "Create VF Module: Unable to determine specific VF Module Type: "
1287                                                         + vfModuleType;
1288                                         if (vfVersion != null && !vfVersion.isEmpty()) {
1289                                                 error += " with version = " + vfVersion;
1290                                         }
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);
1295                                 }
1296                                 LOGGER.debug("Got VF module definition from Catalog: "
1297                                                 + vf.toString());
1298
1299                                 if (vf.isBase()) {
1300                                         isBaseRequest = true;
1301                                         LOGGER.debug("This is a BASE VF request!");
1302                                 } else {
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");
1306                                         }
1307                                 }
1308                         } else {
1309                                 if (vfVersion != null && !vfVersion.isEmpty()) {
1310                                         vnfResource = db.getVnfResource(vnfType, vnfVersion);
1311                                 } else {
1312                                         vnfResource = db.getVnfResource(vnfType);
1313                                 }
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);
1320                                 }
1321                                 LOGGER.debug("Got VNF module definition from Catalog: "
1322                                                 + vnfResource.toString());
1323                         }
1324                         // By here - we have either a vf or vnfResource
1325
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.
1329             if (!oldWay) {
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...");
1335                         }
1336                 }
1337             }
1338             String minVersionVnf = null;
1339             String maxVersionVnf = null;
1340             if (vnfResource != null) {
1341                 try {
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;
1348                 }
1349                 if (minVersionVnf != null && minVersionVnf.equals("")) {
1350                         minVersionVnf = null;
1351                 }
1352                 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1353                         maxVersionVnf = null;
1354                 }
1355             }
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();
1362                                 }
1363                                 // double check
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());
1371                                                 } else {
1372                                                         // ERROR
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);
1377                                                 }
1378                                         } // let this error out downstream to avoid introducing uncertainty at this stage
1379                                 } else {
1380                                         LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1381                                 }
1382
1383                         } else {
1384                                 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1385                         }
1386                         // End Version check 1607
1387
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;
1392
1393                         if (!oldWay) {
1394                                 if (isVolumeRequest) {
1395                                         heatTemplateId = vf.getVolTemplateId();
1396                                         heatEnvtId = vf.getVolEnvironmentId();
1397                                 } else {
1398                                         heatTemplateId = vf.getTemplateId();
1399                                         heatEnvtId = vf.getEnvironmentId();
1400                                 }
1401                         } else {
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);
1410                         } else {
1411                                 heatTemplateId = vnfComponent.getHeatTemplateId();
1412                                 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1413                         }
1414                                 } else {
1415                                         heatTemplateId = vnfResource.getTemplateId();
1416                                         heatEnvtId = vnfResource.getEnvironmentId();
1417                                 }
1418                         }
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);
1428                         } else {
1429                                 heatTemplate = db.getHeatTemplate(heatTemplateId);
1430                         }
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,
1434                                                 "Heat Template ID",
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);
1440                         }
1441                         LOGGER.debug("Got HEAT Template from DB");
1442
1443             HeatEnvironment heatEnvironment = null;
1444             String heatEnvironmentString = null;
1445
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="
1452                                    + heatEnvtId;
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);
1457
1458                     throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1459                 } else {
1460                     LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1461                     heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1462                     LOGGER.debug ("after parsing: " + heatEnvironmentString);
1463                 }
1464             } else {
1465                 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
1466             }
1467
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);
1481                 }
1482             } else {
1483                 LOGGER.debug ("No nested templates found - nothing to do here");
1484                 nestedTemplatesChecked = null; // just to make sure
1485             }
1486
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>();
1491
1492             // Add ability to turn on adding get_files with volume requests (by property).
1493             boolean addGetFilesOnVolumeReq = false;
1494             try {
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);
1499                 }
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);
1502             }
1503
1504                         if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1505                                 if (oldWay) {
1506                                         LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFiles avec vnfResourceId="
1507                                                         + vnfResource.getId());
1508                                         heatFiles = db.getHeatFiles(vnfResource.getId());
1509                                 } else {
1510                                         // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1511                                         LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1512                                                         + vf.getId());
1513                                         heatFiles = db
1514                                                         .getHeatFilesForVfModule(vf.getId());
1515                                 }
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:");
1522
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);
1534                                                 }
1535                                                 String heatFileBody = heatFiles.get(heatFileName)
1536                                                                 .getFileBody();
1537                                                 String heatFileNameChecked = heatFileName;
1538                                                 LOGGER.debug(heatFileNameChecked + " -> "
1539                                                                 + heatFileBody);
1540                                                 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1541                                         }
1542                                 } else {
1543                                         LOGGER.debug("No heat files found -nothing to do here");
1544                                         heatFilesObjects = null;
1545                                 }
1546                         } else {
1547                                         LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1548                         }
1549
1550             // Check that required parameters have been supplied
1551             String missingParams = null;
1552             List <String> paramList = new ArrayList <String> ();
1553
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
1558             // shouldn't
1559             boolean haveEnvironmentParameters = false;
1560             boolean checkRequiredParameters = true;
1561             try {
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);
1568                 }
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);
1572             }
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());
1588                 }
1589                 if (!mhee.isValid()) {
1590                         sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1591                 } else {
1592                         sb2.append("\nEnvironment:");
1593                         sb2.append(mhee.toFullString());
1594                 }
1595                 LOGGER.debug(sb2.toString());
1596             } else {
1597                 LOGGER.debug("NO ENVIRONMENT for this entry");
1598             }
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;
1606
1607             for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1608                 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1609                               + "', isRequired="
1610                               + parm.isRequired ()
1611                               + ", alias="
1612                               + parm.getParamAlias ());
1613                 // New 1607 - support json type
1614                 String parameterType = parm.getParamType();
1615                 if (parameterType == null || parameterType.trim().equals("")) {
1616                         parameterType = "String";
1617                 }
1618                 JsonNode jsonNode = null;
1619                 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
1620                         if (inputs.containsKey(parm.getParamName()) ) {
1621                                 hasJson = true;
1622                                 String jsonString = null;
1623                                 try {
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);
1631                                         hasJson = false;
1632                                         jsonNode = null;
1633                                 } catch (Exception e) {
1634                                         // or here?
1635                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
1636                                         hasJson = false;
1637                                         jsonNode = null;
1638                                 }
1639                                 if (jsonNode != null) {
1640                                         jsonParams.put(parm.getParamName(), jsonNode);
1641                                 }
1642                         } else if (inputs.containsKey(parm.getParamAlias())) {
1643                                 hasJson = true;
1644                                 String jsonString = null;
1645                                 try {
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);
1653                                         hasJson = false;
1654                                         jsonNode = null;
1655                                 } catch (Exception e) {
1656                                         // or here?
1657                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
1658                                         hasJson = false;
1659                                         jsonNode = null;
1660                                 }
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
1664                                         // get flagged.
1665                                         jsonParams.put(parm.getParamName(), jsonNode);
1666                                         inputs.remove(parm.getParamAlias());
1667                                         inputs.put(parm.getParamName(), jsonString);
1668                                 }
1669                         } //TODO add a check for the parameter in the env file
1670                 }
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
1680                                       + ",alias="
1681                                       + alias
1682                                       + ",value="
1683                                       + value);
1684                         inputs.remove (alias);
1685                         inputs.put (realParamName, value);
1686                         LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
1687                     }
1688                     // enhanced - check if it's in the Environment (note: that method
1689                     else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1690
1691                         LOGGER.debug ("Required parameter " + parm.getParamName ()
1692                                       + " appears to be in environment - do not count as missing");
1693                     } else {
1694                         LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1695                         if (missingParams == null) {
1696                             missingParams = parm.getParamName ();
1697                         } else {
1698                             missingParams += "," + parm.getParamName ();
1699                         }
1700                     }
1701                 }
1702                 paramList.add (parm.getParamName ());
1703             }
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);
1711                 } else {
1712                         LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1713                 }
1714             } else {
1715                 LOGGER.debug ("No missing parameters found - ok to proceed");
1716             }
1717
1718             // Here - modify heatEnvironmentString
1719             StringBuilder parsedEnvironmentString = null;
1720             String newEnvironmentString = null;
1721             if (mhee != 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();
1726             }
1727
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);
1736                 }
1737             }
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));
1745                         } else {
1746                                 inputsTwo.put(keyParamName, inputs.get(keyParamName));
1747                         }
1748                 }
1749             }
1750
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");
1754
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 ();
1759             try {
1760                 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1761                 // heatTemplate.getTimeoutMinutes());
1762                 if (backout == null) {
1763                         backout = true;
1764                 }
1765                 if (heat != null) {
1766                         LOGGER.debug("heat is not null!!");
1767                 }
1768
1769                 if (!hasJson) {
1770                         heatStack = heat.createStack (cloudSiteId,
1771                                               tenantId,
1772                                               vfModuleName,
1773                                               template,
1774                                               inputs,
1775                                               true,
1776                                               heatTemplate.getTimeoutMinutes (),
1777                                               newEnvironmentString,
1778                                               //heatEnvironmentString,
1779                                               nestedTemplatesChecked,
1780                                               heatFilesObjects,
1781                                               backout.booleanValue());
1782                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1783                 } else {
1784                         heatStack = heat.createStack (cloudSiteId,
1785                                               tenantId,
1786                                               vfModuleName,
1787                                               template,
1788                                               inputsTwo,
1789                                               true,
1790                                               heatTemplate.getTimeoutMinutes (),
1791                                               newEnvironmentString,
1792                                               //heatEnvironmentString,
1793                                               nestedTemplatesChecked,
1794                                               heatFilesObjects,
1795                                               backout.booleanValue());
1796
1797                 }
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());
1819             }
1820         } catch (Exception e) {
1821                 LOGGER.debug("unhandled exception in create VF");
1822                 throw new VnfException("Exception during create VF " + e.getMessage());
1823
1824         } finally {
1825             // Make sure DB session is closed
1826             db.close ();
1827         }
1828
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);
1833
1834         vnfId.value = heatStack.getCanonicalName ();
1835         outputs.value = copyStringOutputs (heatStack.getOutputs ());
1836         rollback.value = vfRollback;
1837
1838         LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1839         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1840         return;
1841
1842
1843     }
1844
1845     public void deleteVfModule (String cloudSiteId,
1846                            String tenantId,
1847                            String vnfName,
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 ();
1855
1856         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1857
1858         // 1702 capture the output parameters on a delete
1859         // so we'll need to query first
1860         Map<String, Object> stackOutputs = null;
1861         try {
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);
1872         }
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);
1875
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
1879         // could be thrown.
1880         long subStartTime = System.currentTimeMillis ();
1881         try {
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);
1893         }
1894
1895         // On success, nothing is returned.
1896         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1897         return;
1898     }
1899
1900     @Override
1901     public void updateVfModule (String cloudSiteId,
1902                            String tenantId,
1903                            String vnfType,
1904                            String vnfVersion,
1905                            String vnfName,
1906                            String requestType,
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);
1922
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);
1928                 useMCUuid = false;
1929                 mcu = "";
1930             } else {
1931                 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1932                 useMCUuid = true;
1933             }
1934         }
1935
1936         String requestTypeString = "";
1937         if (requestType != null && !requestType.equals("")) {
1938                 requestTypeString = requestType;
1939         }
1940         String nestedStackId = null;
1941         if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1942                 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1943                         nestedStackId = volumeGroupHeatStackId;
1944                 }
1945         }
1946         String nestedBaseStackId = null;
1947         if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1948                 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1949                         nestedBaseStackId = baseVfHeatStackId;
1950                 }
1951         }
1952
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");
1957         } else {
1958                 this.sendMapToDebug(inputs);
1959         }
1960         boolean isBaseRequest = false;
1961         boolean isVolumeRequest = false;
1962         if (requestTypeString.startsWith("VOLUME")) {
1963                 isVolumeRequest = true;
1964         }
1965         if (vfModuleName == null || vfModuleName.trim().equals("")) {
1966                 if (vfModuleStackId != null) {
1967                         vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1968                 }
1969         }
1970
1971         LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1972         LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1973
1974         // Will capture execution time for metrics
1975         long startTime = System.currentTimeMillis ();
1976
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);
1988
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);
1992
1993         StackInfo heatStack = null;
1994         long queryStackStarttime = System.currentTimeMillis ();
1995         LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1996         try {
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);
2008         }
2009
2010         //TODO - do we need to check for the other status possibilities?
2011         if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
2012             // Not Found
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);
2017         } else {
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
2022         }
2023
2024         // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
2025         StackInfo nestedHeatStack = null;
2026         long queryStackStarttime2 = System.currentTimeMillis ();
2027         if (nestedStackId != null) {
2028                 try {
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);
2042                 }
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);
2050                 } else {
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);
2055                 }
2056         }
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 ();
2061                 try {
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);
2075                 }
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);
2083                 } else {
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);
2088                 }
2089         }
2090
2091         // Ready to deploy the new VNF
2092         // Get a handle to the Catalog Database
2093         CatalogDatabase db = new CatalogDatabase ();
2094
2095         // Make sure DB session is closed
2096         try {
2097             // Retrieve the VF definition
2098             //VnfResource vnf;
2099                 VfModule vf = null;
2100             if (useMCUuid) {
2101                 vf = db.getVfModuleByModelCustomizationUuid(mcu);
2102                 if (vf == null) {
2103                     LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
2104                 }
2105             }
2106             else if (vfVersion != null && !vfVersion.isEmpty ()) {
2107                 vf = db.getVfModuleType(vfModuleType, vfVersion);
2108                 if (vf == null) {
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);
2111                         if (vf == null) {
2112                                 LOGGER.debug("Unable to find " + vfModuleType + " and version = " + vfVersion + " in the MODEL_NAME field either - ERROR");
2113                         }
2114                 }
2115             } else {
2116                 vf = db.getVfModuleType(vfModuleType);
2117                 if (vf == null) {
2118                         LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
2119                         vf = db.getVfModuleModelName(vfModuleType);
2120                         if (vf == null) {
2121                                 LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
2122                         }
2123                 }
2124             }
2125             if (vf == null) {
2126                 String error;
2127                 if (!useMCUuid) {
2128                     error = "Update VFModule: Unknown VF Module Type: " + vfModuleType;
2129                     if (vfVersion != null && !vfVersion.isEmpty()) {
2130                         error += " with version = " + vfVersion;
2131                     }
2132                 } else {
2133                     error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
2134                 }
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);
2138             }
2139             LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
2140
2141             HeatTemplate heatTemplate = null;
2142             Integer heatTemplateId = null;
2143             Integer heatEnvtId = null;
2144                         if (!isVolumeRequest) {
2145                                 heatTemplateId = vf.getTemplateId();
2146                                 heatEnvtId = vf.getEnvironmentId();
2147                         } else {
2148                                 heatTemplateId = vf.getVolTemplateId();
2149                                 heatEnvtId = vf.getVolEnvironmentId();
2150                         }
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);
2158                         } else {
2159                                 heatTemplate = db.getHeatTemplate(heatTemplateId);
2160                         }
2161
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,
2166                                                 "Heat Template ID",
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);
2172
2173                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
2174                         }
2175
2176             LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
2177
2178             // Add check for any Environment variable
2179             HeatEnvironment heatEnvironment = null;
2180             String heatEnvironmentString = null;
2181
2182             if (heatEnvtId != null) {
2183                 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvtId + ":");
2184                 heatEnvironment = db.getHeatEnvironment (heatEnvtId);
2185                 if (heatEnvironment == null) {
2186
2187                     String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
2188                                    + ", Environment ID="
2189                                    + heatEnvtId;
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);
2194
2195                     throw new VnfException (error, MsoExceptionCategory.INTERNAL);
2196                 } else {
2197                     LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
2198                     heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
2199                     LOGGER.debug ("After parsing: " + heatEnvironmentString);
2200                 }
2201             } else {
2202                 LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType);
2203             }
2204
2205
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);
2218                 }
2219             } else {
2220                 LOGGER.debug ("No nested templates found - nothing to do here");
2221                 nestedTemplatesChecked = null;
2222             }
2223
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="
2227                           + vf.getId ());
2228
2229             Map <String, HeatFiles> heatFiles = null;
2230 //            Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
2231             Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
2232
2233             // Add ability to turn on adding get_files with volume requests (by property).
2234             boolean addGetFilesOnVolumeReq = false;
2235             try {
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);
2240                 }
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);
2243             }
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:");
2251
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);
2263                                                 }
2264                         String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
2265                         LOGGER.debug (heatFileName + " -> " + heatFileBody);
2266                         heatFilesObjects.put (heatFileName, heatFileBody);
2267                     }
2268                 } else {
2269                     LOGGER.debug ("No heat files found -nothing to do here");
2270                     heatFilesObjects = null;
2271                 }
2272             }
2273
2274             // Check that required parameters have been supplied
2275             String missingParams = null;
2276             List <String> paramList = new ArrayList <String> ();
2277
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
2282             // shouldn't
2283             boolean haveEnvironmentParameters = false;
2284             boolean checkRequiredParameters = true;
2285             try {
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);
2292                 }
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);
2296             }
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());
2311                 }
2312                 if (!mhee.isValid()) {
2313                         sb2.append("Environment says it's not valid! " + mhee.getErrorString());
2314                 } else {
2315                         sb2.append("\nEnvironment:");
2316                         sb2.append(mhee.toFullString());
2317                 }
2318                 LOGGER.debug(sb2.toString());
2319             } else {
2320                 LOGGER.debug("NO ENVIRONMENT for this entry");
2321             }
2322
2323             // New for 1607 - support params of json type
2324             HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
2325             boolean hasJson = false;
2326
2327             for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
2328                 LOGGER.debug ("Parameter:'" + parm.getParamName ()
2329                               + "', isRequired="
2330                               + parm.isRequired ()
2331                               + ", alias="
2332                               + parm.getParamAlias ());
2333                 // handle json
2334                 String parameterType = parm.getParamType();
2335                 if (parameterType == null || parameterType.trim().equals("")) {
2336                         parameterType = "String";
2337                 }
2338                 JsonNode jsonNode = null;
2339                 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
2340                         if (inputs.containsKey(parm.getParamName()) ) {
2341                                 hasJson = true;
2342                                 String jsonString = null;
2343                                 try {
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);
2351                                         hasJson = false;
2352                                         jsonNode = null;
2353                                 } catch (Exception e) {
2354                                         // or here?
2355                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
2356                                         hasJson = false;
2357                                         jsonNode = null;
2358                                 }
2359                                 if (jsonNode != null) {
2360                                         jsonParams.put(parm.getParamName(), jsonNode);
2361                                 }
2362                         } else if (inputs.containsKey(parm.getParamAlias())) {
2363                                 hasJson = true;
2364                                 String jsonString = null;
2365                                 try {
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);
2373                                         hasJson = false;
2374                                         jsonNode = null;
2375                                 } catch (Exception e) {
2376                                         // or here?
2377                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
2378                                         hasJson = false;
2379                                         jsonNode = null;
2380                                 }
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
2384                                         // get flagged.
2385                                         jsonParams.put(parm.getParamName(), jsonNode);
2386                                         inputs.remove(parm.getParamAlias());
2387                                         inputs.put(parm.getParamName(), jsonString);
2388                                 }
2389                         } //TODO add a check for the parameter in the env file
2390                 }
2391
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
2399                                       + ",alias="
2400                                       + alias
2401                                       + ",value="
2402                                       + value);
2403                         inputs.remove (alias);
2404                         inputs.put (realParamName, value);
2405                         LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
2406                     }
2407                     // enhanced - check if it's in the Environment (note: that method
2408                     else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2409
2410                         LOGGER.debug ("Required parameter " + parm.getParamName ()
2411                                       + " appears to be in environment - do not count as missing");
2412                     }
2413                     else {
2414                         LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
2415                         if (missingParams == null) {
2416                             missingParams = parm.getParamName ();
2417                         } else {
2418                             missingParams += "," + parm.getParamName ();
2419                         }
2420                     }
2421                 }
2422                 paramList.add (parm.getParamName ());
2423             }
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);
2431                 } else {
2432                         LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
2433                 }
2434             } else {
2435                 LOGGER.debug ("No missing parameters found - ok to proceed");
2436             }
2437
2438             // Here - modify heatEnvironmentString
2439             StringBuilder parsedEnvironmentString = null;
2440             String newEnvironmentString = null;
2441             if (mhee != 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();
2446             }
2447
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);
2457                 }
2458             }
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));
2466                         } else {
2467                                 inputsTwo.put(keyParamName, inputs.get(keyParamName));
2468                         }
2469                 }
2470             }
2471
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");
2475
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 ();
2480             try {
2481                 if (!hasJson) {
2482                         heatStack = heatU.updateStack (cloudSiteId,
2483                                                tenantId,
2484                                                vfModuleName,
2485                                                template,
2486                                                copyStringInputs (inputs),
2487                                                true,
2488                                                heatTemplate.getTimeoutMinutes (),
2489                                                newEnvironmentString,
2490                                                //heatEnvironmentString,
2491                                                nestedTemplatesChecked,
2492                                                heatFilesObjects);
2493                         LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2494                 } else {
2495                         heatStack = heatU.updateStack (cloudSiteId,
2496                                                tenantId,
2497                                                vfModuleName,
2498                                                template,
2499                                                inputsTwo,
2500                                                true,
2501                                                heatTemplate.getTimeoutMinutes (),
2502                                                newEnvironmentString,
2503                                                //heatEnvironmentString,
2504                                                nestedTemplatesChecked,
2505                                                heatFilesObjects);
2506                         LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2507
2508                 }
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);
2516             }
2517         } finally {
2518             // Make sure DB session is closed
2519             db.close ();
2520         }
2521
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);
2526
2527         outputs.value = copyStringOutputs (heatStack.getOutputs ());
2528         rollback.value = vfRollback;
2529         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2530         return;
2531     }
2532
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)
2537                 return null;
2538         int index = vfModuleStackId.lastIndexOf('/');
2539         if (index <= 0)
2540                 return null;
2541         String vfModuleName = null;
2542         try {
2543                 vfModuleName = vfModuleStackId.substring(0, index);
2544         } catch (Exception e) {
2545                 vfModuleName = null;
2546         }
2547         return vfModuleName;
2548     }
2549
2550 }