Merge "Fix the arquillian framework"
[so.git] / adapters / mso-vnf-adapter / src / main / java / org / openecomp / mso / adapters / vnf / MsoVnfAdapterImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.mso.adapters.vnf;
23
24
25 import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29
30 import java.util.Arrays;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.concurrent.TimeUnit;
36 import java.util.Scanner;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39
40 import javax.jws.WebService;
41 import javax.xml.ws.Holder;
42
43 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
44 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
45 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
46 import org.openecomp.mso.cloud.CloudConfigFactory;
47 import org.openecomp.mso.cloud.CloudConfig;
48 import org.openecomp.mso.cloud.CloudSite;
49 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
50 import org.openecomp.mso.db.catalog.CatalogDatabase;
51 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
52 import org.openecomp.mso.db.catalog.beans.HeatFiles;
53 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
54 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
55 import org.openecomp.mso.db.catalog.beans.VnfResource;
56 import org.openecomp.mso.db.catalog.beans.VfModule;
57 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
58 import org.openecomp.mso.db.catalog.beans.VnfComponent;
59 import org.openecomp.mso.entity.MsoRequest;
60 import org.openecomp.mso.logger.MessageEnum;
61 import org.openecomp.mso.logger.MsoAlarmLogger;
62 import org.openecomp.mso.logger.MsoLogger;
63 import org.openecomp.mso.openstack.beans.HeatStatus;
64 import org.openecomp.mso.openstack.beans.StackInfo;
65 import org.openecomp.mso.openstack.beans.VnfStatus;
66 import org.openecomp.mso.openstack.beans.VnfRollback;
67 import org.openecomp.mso.openstack.exceptions.MsoException;
68 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
69 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
70 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
71 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
72 import org.openecomp.mso.properties.MsoPropertiesFactory;
73
74 import org.codehaus.jackson.JsonNode;
75 import org.codehaus.jackson.JsonParseException;
76 import org.codehaus.jackson.map.ObjectMapper;
77
78 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
79 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
80
81         CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
82         protected CloudConfig cloudConfig = null;
83
84         MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
85
86         private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
87     private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
88     private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
89     private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN.";
90     private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
91     private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
92     private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
93     private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
94     private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
95
96     /**
97      * Health Check web method. Does nothing but return to show the adapter is deployed.
98      */
99     @Override
100     public void healthCheck () {
101         LOGGER.debug ("Health check call in VNF Adapter");
102     }
103
104     /**
105      * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
106      * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
107      */
108     public MsoVnfAdapterImpl() {
109
110     }
111
112     /**
113      * This constructor MUST be used if this class is called with the new operator.
114      * @param msoPropFactory
115      */
116     public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
117         this.msoPropertiesFactory = msoPropFactory;
118         this.cloudConfigFactory = cloudConfigFact;
119     }
120
121     /**
122      * This is the "Create VNF" web service implementation.
123      * It will create a new VNF of the requested type in the specified cloud
124      * and tenant. The tenant must exist before this service is called.
125      *
126      * If a VNF with the same name already exists, this can be considered a
127      * success or failure, depending on the value of the 'failIfExists' parameter.
128      *
129      * All VNF types will be defined in the MSO catalog. The caller must request
130      * one of these pre-defined types or an error will be returned. Within the
131      * catalog, each VNF type references (among other things) a Heat template
132      * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
133      * to the cloud.
134      *
135      * Depending on the Heat template, a variable set of input parameters will
136      * be defined, some of which are required. The caller is responsible to
137      * pass the necessary input data for the VNF or an error will be thrown.
138      *
139      * The method returns the vnfId (the canonical name), a Map of VNF output
140      * attributes, and a VnfRollback object. This last object can be passed
141      * as-is to the rollbackVnf operation to undo everything that was created
142      * for the VNF. This is useful if a VNF is successfully created but the
143      * orchestrator fails on a subsequent operation.
144      *
145      * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
146      * @param tenantId Openstack tenant identifier
147      * @param vnfType VNF type key, should match a VNF definition in catalog DB
148      * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
149      * @param vnfName Name to be assigned to the new VNF
150      * @param inputs Map of key=value inputs for VNF stack creation
151      * @param failIfExists Flag whether already existing VNF should be considered
152      *        a success or failure
153      * @param msoRequest Request tracking information for logs
154      * @param vnfId Holder for output VNF Openstack ID
155      * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
156      * @param rollback Holder for returning VnfRollback object
157      */
158     @Override
159     public void createVnf (String cloudSiteId,
160                            String tenantId,
161                            String vnfType,
162                            String vnfVersion,
163                            String vnfName,
164                            String requestType,
165                            String volumeGroupHeatStackId,
166                            Map <String, String> inputs,
167                            Boolean failIfExists,
168                            Boolean backout,
169                            MsoRequest msoRequest,
170                            Holder <String> vnfId,
171                            Holder <Map <String, String>> outputs,
172                            Holder <VnfRollback> rollback) throws VnfException {
173         // Create a hook here to catch shortcut createVf requests:
174         if (requestType != null) {
175                 if (requestType.startsWith("VFMOD")) {
176                         LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
177                         String newRequestType = requestType.substring(5);
178                         String vfVolGroupHeatStackId = "";
179                         String vfBaseHeatStackId = "";
180                         try {
181                                 if (volumeGroupHeatStackId != null) {
182                                         vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
183                                         vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
184                                 }
185                         } catch (Exception e) {
186                                 // might be ok - both are just blank
187                                 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
188                         }
189                         this.createVfModule(cloudSiteId,
190                                         tenantId,
191                                         vnfType,
192                                         vnfVersion,
193                                         vnfName,
194                                         newRequestType,
195                                         vfVolGroupHeatStackId,
196                                         vfBaseHeatStackId,
197                         null,
198                                         inputs,
199                                         failIfExists,
200                                         backout,
201                                         msoRequest,
202                                         vnfId,
203                                         outputs,
204                                         rollback);
205                         return;
206                 }
207         }
208         // createVf will know if the requestType starts with "X" that it's the "old" way
209         StringBuilder newRequestTypeSb = new StringBuilder("X");
210         String vfVolGroupHeatStackId = "";
211         String vfBaseHeatStackId = "";
212         if (requestType != null) {
213                 newRequestTypeSb.append(requestType);
214             }
215                 this.createVfModule(cloudSiteId, 
216                                                tenantId,
217                                 vnfType, 
218                                 vnfVersion, 
219                                                vnfName,
220                                 newRequestTypeSb.toString(), 
221                                 vfVolGroupHeatStackId, 
222                                 vfBaseHeatStackId, 
223                                 null,
224                                 inputs, 
225                                 failIfExists, 
226                                 backout, 
227                                 msoRequest, 
228                                 vnfId, 
229                                 outputs, 
230                                 rollback);
231         return;
232         // End createVf shortcut
233         }
234
235     @Override
236     public void updateVnf (String cloudSiteId,
237                            String tenantId,
238                            String vnfType,
239                            String vnfVersion,
240                            String vnfName,
241                            String requestType,
242                            String volumeGroupHeatStackId,
243                            Map <String, String> inputs,
244                            MsoRequest msoRequest,
245                            Holder <Map <String, String>> outputs,
246                            Holder <VnfRollback> rollback) throws VnfException {
247         // As of 1707 - this method should no longer be called
248         MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
249         MsoLogger.setServiceName ("UpdateVnf");
250         LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
251     }
252
253     /**
254      * This is the "Query VNF" web service implementation.
255      * It will look up a VNF by name or ID in the specified cloud and tenant.
256      *
257      * The method returns an indicator that the VNF exists, its Openstack internal
258      * ID, its status, and the set of outputs (from when the stack was created).
259      *
260      * @param cloudSiteId CLLI code of the cloud site in which to query
261      * @param tenantId Openstack tenant identifier
262      * @param vnfName VNF Name or Openstack ID
263      * @param msoRequest Request tracking information for logs
264      * @param vnfExists Flag reporting the result of the query
265      * @param vnfId Holder for output VNF Openstack ID
266      * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
267      */
268     @Override
269     public void queryVnf (String cloudSiteId,
270                           String tenantId,
271                           String vnfName,
272                           MsoRequest msoRequest,
273                           Holder <Boolean> vnfExists,
274                           Holder <String> vnfId,
275                           Holder <VnfStatus> status,
276                           Holder <Map <String, String>> outputs) throws VnfException {
277         MsoLogger.setLogContext (msoRequest);
278         MsoLogger.setServiceName ("QueryVnf");
279         LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
280
281         // Will capture execution time for metrics
282         long startTime = System.currentTimeMillis ();
283
284         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
285
286         StackInfo heatStack = null;
287         long subStartTime = System.currentTimeMillis ();
288         try {
289             heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
290             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
291         } catch (MsoException me) {
292             me.addContext ("QueryVNF");
293             // Failed to query the Stack due to an openstack exception.
294             // Convert to a generic VnfException
295             String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
296             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
297             LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
298             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
299             throw new VnfException (me);
300         }
301
302         // Populate the outputs based on the returned Stack information
303         //
304         if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
305             // Not Found
306             vnfExists.value = Boolean.FALSE;
307             status.value = VnfStatus.NOTFOUND;
308             vnfId.value = null;
309             outputs.value = new HashMap <String, String> (); // Return as an empty map
310
311             LOGGER.debug ("VNF " + vnfName + " not found");
312         } else {
313             vnfExists.value = Boolean.TRUE;
314             status.value = stackStatusToVnfStatus (heatStack.getStatus ());
315             vnfId.value = heatStack.getCanonicalName ();
316             outputs.value = copyStringOutputs (heatStack.getOutputs ());
317
318             LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
319         }
320         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
321         return;
322     }
323
324     /**
325      * This is the "Delete VNF" web service implementation.
326      * It will delete a VNF by name or ID in the specified cloud and tenant.
327      *
328      * The method has no outputs.
329      *
330      * @param cloudSiteId CLLI code of the cloud site in which to delete
331      * @param tenantId Openstack tenant identifier
332      * @param vnfName VNF Name or Openstack ID
333      * @param msoRequest Request tracking information for logs
334      */
335     @Override
336     public void deleteVnf (String cloudSiteId,
337                            String tenantId,
338                            String vnfName,
339                            MsoRequest msoRequest) throws VnfException {
340         MsoLogger.setLogContext (msoRequest);
341         MsoLogger.setServiceName ("DeleteVnf");
342         LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
343         // Will capture execution time for metrics
344         long startTime = System.currentTimeMillis ();
345
346         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
347
348         // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
349         // The possible outcomes of deleteStack are a StackInfo object with status
350         // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
351         // could be thrown.
352         long subStartTime = System.currentTimeMillis ();
353         try {
354             heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
355             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
356         } catch (MsoException me) {
357             me.addContext ("DeleteVNF");
358             // Failed to query the Stack due to an openstack exception.
359             // Convert to a generic VnfException
360             String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
361             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
362             LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
363             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
364             throw new VnfException (me);
365         }
366
367         // On success, nothing is returned.
368         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
369         return;
370     }
371
372     /**
373      * This web service endpoint will rollback a previous Create VNF operation.
374      * A rollback object is returned to the client in a successful creation
375      * response. The client can pass that object as-is back to the rollbackVnf
376      * operation to undo the creation.
377      */
378     @Override
379     public void rollbackVnf (VnfRollback rollback) throws VnfException {
380         long startTime = System.currentTimeMillis ();
381         MsoLogger.setServiceName ("RollbackVnf");
382         // rollback may be null (e.g. if stack already existed when Create was called)
383         if (rollback == null) {
384             LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
385             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
386             return;
387         }
388
389         // Get the elements of the VnfRollback object for easier access
390         String cloudSiteId = rollback.getCloudSiteId ();
391         String tenantId = rollback.getTenantId ();
392         String vnfId = rollback.getVnfId ();
393
394         MsoLogger.setLogContext (rollback.getMsoRequest());
395
396         LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
397
398         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
399
400         // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
401         // The possible outcomes of deleteStack are a StackInfo object with status
402         // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
403         // could be thrown.
404         long subStartTime = System.currentTimeMillis ();
405         try {
406             heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
407             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
408         } catch (MsoException me) {
409             // Failed to rollback the Stack due to an openstack exception.
410             // Convert to a generic VnfException
411             me.addContext ("RollbackVNF");
412             String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
413             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
414             LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
415             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
416             throw new VnfException (me);
417         }
418         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
419         return;
420     }
421
422     private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
423         switch (stackStatus) {
424             case CREATED:
425                 return VnfStatus.ACTIVE;
426             case UPDATED:
427                 return VnfStatus.ACTIVE;
428             case FAILED:
429                 return VnfStatus.FAILED;
430             default:
431                 return VnfStatus.UNKNOWN;
432         }
433     }
434
435     private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
436         Map <String, String> stringOutputs = new HashMap <String, String> ();
437         for (String key : stackOutputs.keySet ()) {
438             if (stackOutputs.get (key) instanceof String) {
439                 stringOutputs.put (key, (String) stackOutputs.get (key));
440             } else if (stackOutputs.get(key) instanceof Integer)  {
441                 try {
442                         String str = "" + stackOutputs.get(key);
443                         stringOutputs.put(key, str);
444                 } catch (Exception e) {
445                         LOGGER.debug("Unable to add " + key + " to outputs",e);
446                 }
447             } else if (stackOutputs.get(key) instanceof JsonNode) {
448                 try {
449                         String str = this.convertNode((JsonNode) stackOutputs.get(key));
450                         stringOutputs.put(key, str);
451                 } catch (Exception e) {
452                         LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode",e);
453                 }
454             } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
455                 try {
456                                         String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
457                         stringOutputs.put(key, str);
458                 } catch (Exception e) {
459                         LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap",e);
460                 }
461             } else {
462                 try {
463                         String str = stackOutputs.get(key).toString();
464                         stringOutputs.put(key, str);
465                 } catch (Exception e) {
466                         LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),e);
467                 }
468             }
469         }
470         return stringOutputs;
471     }
472
473     private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
474         return new HashMap <String, Object> (stringInputs);
475     }
476
477     /*
478      * a helper method to make sure that any resource_registry entry of the format
479      * "xx::xx" : yyy.yaml (or yyy.template)
480      * has the file name prepended with "file:///"
481      * Return a String of the environment body that's passed in.
482      * Have to be careful not to mess up the original formatting.
483      */
484     private String parseEnvironment (String environment) {
485         StringBuilder sb = new StringBuilder ();
486         try (Scanner scanner = new Scanner (environment)) {
487             scanner.useDelimiter ("\n");
488             String line = null;
489             Pattern resource = Pattern.compile ("\\s*\"\\w+::\\S+\"\\s*:");
490             LOGGER.debug ("regex pattern for finding a resource_registry: \\s*\"\\w+::\\S+\"\\s*:");
491             while (scanner.hasNextLine ()) {
492                 line = scanner.nextLine ();
493                 if (line.toLowerCase ().contains ("resource_registry")) {
494                     sb.append (line + "\n");
495                     boolean done = false;
496                     // basically keep scanning until EOF or parameters: section
497                     while (scanner.hasNextLine () && !done) {
498                         line = scanner.nextLine ();
499                         if ("parameters:".equalsIgnoreCase (line.trim ())) {
500                             sb.append (line + "\n");
501                             done = true;
502                             break;
503                         }
504                         Matcher m = resource.matcher (line);
505                         if (m.find ()) {
506                             sb.append (m.group ());
507                             String secondPart = line.substring (m.end ()).trim ();
508                             String output = secondPart;
509                             if (secondPart.endsWith (".yaml")
510                                 || secondPart.endsWith (".template") && !secondPart.startsWith ("file:///")) {
511                                 output = "file:///" + secondPart;
512                                 LOGGER.debug ("changed " + secondPart + " to " + output);
513                             } // don't do anything if it's not .yaml or .template
514                             sb.append (" " + output + "\n");
515                         } else {
516                             sb.append (line + "\n");
517                         }
518                     }
519                 } else {
520                     sb.append (line + "\n");
521                     continue;
522                 }
523             }
524             scanner.close ();
525         } catch (Exception e) {
526             LOGGER.debug ("Error trying to scan " + environment, e);
527             return environment;
528         }
529         return sb.toString ();
530     }
531
532     /*
533      * helper class to add file:/// to the Provider_Resource_File entry in HEAT_NESTED_TEMPLATE
534      * and the File_Name entry in HEAT_FILES if the file:/// part is missing.
535      */
536     private String enforceFilePrefix (String string) {
537         if (string.trim ().startsWith ("file:///")) {
538             // just leave it
539             return string;
540         }
541         if (string.trim ().endsWith (".yaml") || string.trim ().endsWith (".template")) {
542             // only .yaml or .template are valid anyway - otherwise don't bother
543             return "file:///" + string.trim ();
544         } else {
545             LOGGER.debug (string + " is NOT a .yaml or .template file");
546         }
547         return string;
548     }
549
550     private boolean callHeatbridge(String heatStackId) {
551         String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
552         String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
553         long waitTimeMs = 10000l;
554         try {
555                 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
556                 String[] envp = null;
557                 File dir = new File(executionDir);
558                 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
559                 Runtime r = Runtime.getRuntime();
560                 Process p = r.exec(cmdarray, envp, dir);
561                 /*                      
562                         BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
563                         String linein = stdout.readLine();
564                         while (linein!=null) {
565                                 System.out.println(linein);
566                                 linein = stdout.readLine();
567                         }
568                  */
569                 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
570
571                 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
572                 return (wait && p.exitValue()==0);
573         } catch (IOException e) {
574                 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
575                 return false;
576         } catch (InterruptedException e) {
577                 LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e);
578                 return false;
579         } catch (RuntimeException e) {
580                 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e);
581                 return false;
582         }
583     }
584
585     private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
586         int i = 0;
587         StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
588         if (inputs == null) {
589                 sb.append("\tNULL");
590         }
591         else if (inputs.size() < 1) {
592                 sb.append("\tEMPTY");
593         } else {
594                 for (String str : inputs.keySet()) {
595                         String outputString;
596                         try {
597                                 outputString = inputs.get(str).toString();
598                         } catch (Exception e) {
599                                 LOGGER.debug("Exception :",e);
600                                 outputString = "Unable to call toString() on the value for " + str;
601                         }
602                         sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
603                 }
604         }
605         LOGGER.debug(sb.toString());
606         return; 
607     }
608     
609     private void sendMapToDebug(Map<String, String> inputs) {
610         int i = 0;
611         StringBuilder sb = new StringBuilder("inputs:");
612         if (inputs == null) {
613                 sb.append("\tNULL");
614         }
615         else if (inputs.size() < 1) {
616                 sb.append("\tEMPTY");
617         } else {
618                 for (String str : inputs.keySet()) {
619                         sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
620                 }
621         }
622         LOGGER.debug(sb.toString());
623         return;
624     }
625
626     private String convertNode(final JsonNode node) {
627         try {
628             final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
629             final String json = JSON_MAPPER.writeValueAsString(obj);
630             return json;
631         } catch (JsonParseException jpe) {
632             LOGGER.debug("Error converting json to string " + jpe.getMessage(),jpe);
633         } catch (Exception e) {
634             LOGGER.debug("Error converting json to string " + e.getMessage(),e);
635         }
636         return "[Error converting json to string]";
637     }
638
639     private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
640         if (objectMap == null) {
641             return null;
642         }
643         Map<String, String> stringMap = new HashMap<String, String>();
644         for (String key : objectMap.keySet()) {
645             if (!stringMap.containsKey(key)) {
646                 Object obj = objectMap.get(key);
647                 if (obj instanceof String) {
648                     stringMap.put(key, (String) objectMap.get(key));
649                 } else if (obj instanceof JsonNode ){
650                     // This is a bit of mess - but I think it's the least impacting
651                     // let's convert it BACK to a string - then it will get converted back later
652                     try {
653                         String str = this.convertNode((JsonNode) obj);
654                         stringMap.put(key, str);
655                     } catch (Exception e) {
656                                                 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
657                         //okay in this instance - only string values (fqdn) are expected to be needed
658                     }
659                 } else if (obj instanceof java.util.LinkedHashMap) {
660                     LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
661                     try {
662                         String str = JSON_MAPPER.writeValueAsString(obj);
663                         stringMap.put(key, str);
664                     } catch (Exception e) {
665                                                 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
666                                         }
667                                 }  else if (obj instanceof Integer) {
668                                         try {
669                                                 String str = "" + obj;
670                                                 stringMap.put(key, str);
671                                         } catch (Exception e) {
672                                                 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
673                     }
674                 } else {
675                     try {
676                                                 String str = obj.toString();
677                         stringMap.put(key, str);
678                     } catch (Exception e) {
679                                                 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
680                     }
681                 }
682             }
683         }
684
685         return stringMap;
686     }
687
688     @Override
689     public void createVfModule(String cloudSiteId,
690             String tenantId,
691             String vnfType,
692             String vnfVersion,
693             String vnfName,
694             String requestType,
695             String volumeGroupHeatStackId,
696             String baseVfHeatStackId,
697             String modelCustomizationUuid,
698             Map <String, String> inputs,
699             Boolean failIfExists,
700             Boolean backout,
701             MsoRequest msoRequest,
702             Holder <String> vnfId,
703             Holder <Map <String, String>> outputs,
704             Holder <VnfRollback> rollback) throws VnfException {
705         String vfModuleName = vnfName;
706         String vfModuleType = vnfType;
707         String vfVersion = vnfVersion;
708         String mcu = modelCustomizationUuid;
709         boolean useMCUuid = false;
710         if (mcu != null && !mcu.isEmpty()) {
711             if (mcu.equalsIgnoreCase("null")) {
712                 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
713                 useMCUuid = false;
714                 mcu = "";
715             } else {
716                 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
717                 useMCUuid = true;
718             }
719         }
720         MsoLogger.setLogContext (msoRequest);
721         MsoLogger.setServiceName ("CreateVfModule");
722         String requestTypeString = "";
723         if (requestType != null && !requestType.equals("")) {
724                 requestTypeString = requestType;
725         }
726         String nestedStackId = null;
727         if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
728                 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
729                         nestedStackId = volumeGroupHeatStackId;
730                 }
731         }
732         String nestedBaseStackId = null;
733         if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
734                 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
735                         nestedBaseStackId = baseVfHeatStackId;
736                 }
737         }
738
739         if (inputs == null) {
740                 // Create an empty set of inputs
741                 inputs = new HashMap<String,String>();
742                 LOGGER.debug("inputs == null - setting to empty");
743         } else {
744                 this.sendMapToDebug(inputs);
745         }
746         //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
747         boolean oldWay = false;
748         if (requestTypeString.startsWith("X")) {
749                 oldWay = true;
750                 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
751                 requestTypeString = requestTypeString.substring(1);
752         }
753
754         // 1607 - let's parse out the request type we're being sent
755         boolean isBaseRequest = false;
756         boolean isVolumeRequest = false;
757         if (requestTypeString.startsWith("VOLUME")) {
758                 isVolumeRequest = true;
759         }
760
761         LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
762         // Will capture execution time for metrics
763         long startTime = System.currentTimeMillis ();
764
765         // Build a default rollback object (no actions performed)
766         VnfRollback vfRollback = new VnfRollback();
767         vfRollback.setCloudSiteId(cloudSiteId);
768         vfRollback.setTenantId(tenantId);
769         vfRollback.setMsoRequest(msoRequest);
770         vfRollback.setRequestType(requestTypeString);
771         vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
772         vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
773         vfRollback.setIsBase(isBaseRequest);
774         vfRollback.setModelCustomizationUuid(mcu);
775
776         // Put data into A&AI through Heatstack
777         boolean heatStackCallSuccess = callHeatbridge(baseVfHeatStackId);
778
779         // First, look up to see if the VF already exists.
780         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
781
782         StackInfo heatStack = null;
783         long subStartTime1 = System.currentTimeMillis ();
784         try {
785             heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
786             LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
787         } catch (MsoException me) {
788             String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
789             LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
790             LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
791             // Failed to query the Stack due to an openstack exception.
792             // Convert to a generic VnfException
793             me.addContext ("CreateVFModule");
794             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
795             throw new VnfException (me);
796         }
797         // New with 1607 - more precise handling/messaging if the stack already exists
798         if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
799                 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
800                 HeatStatus status = heatStack.getStatus();
801                 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
802                         // fail - it's in progress - return meaningful error
803                 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.";
804                 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
805                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
806                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
807                 }
808                 if (status == HeatStatus.FAILED) {
809                         // fail - it exists and is in a FAILED state
810                 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
811                 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
812                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
813                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
814                 }
815                 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
816                         // fail - it exists and is in a FAILED state
817                 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
818                 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");
819                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
820                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
821                 }
822                 if (status == HeatStatus.CREATED) {
823                         // fail - it exists
824                         if (failIfExists != null && failIfExists) {
825                                 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
826                                 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
827                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
828                                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
829                         } else {
830                                 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
831                                 // Populate the outputs from the existing stack.
832                                 vnfId.value = heatStack.getCanonicalName ();
833                                 outputs.value = copyStringOutputs (heatStack.getOutputs ());
834                                 rollback.value = vfRollback; // Default rollback - no updates performed
835                         }
836                 }
837             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
838             return;
839
840         }
841
842         // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
843         StackInfo nestedHeatStack = null;
844         long subStartTime2 = System.currentTimeMillis ();
845         Map<String, Object> nestedVolumeOutputs = null;
846         if (nestedStackId != null) {
847                 try {
848                         LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
849                         nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
850                 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
851                 } catch (MsoException me) {
852                     // Failed to query the Stack due to an openstack exception.
853                     // Convert to a generic VnfException
854                     me.addContext ("CreateVFModule");
855                     String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
856                 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
857                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
858                         LOGGER.debug("ERROR trying to query nested stack= " + error);
859                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
860                     throw new VnfException (me);
861                 }
862                 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
863                     String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
864                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
865                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
866                     LOGGER.debug(error);
867                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
868                 } else {
869                         LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
870                         //this.sendMapToDebug(inputs);
871                         nestedVolumeOutputs = nestedHeatStack.getOutputs();
872                         this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
873                         //TODO
874                         //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);      
875                         //this.sendMapToDebug(inputs);
876                 }
877         }
878
879         // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
880         StackInfo nestedBaseHeatStack = null;
881         long subStartTime3 = System.currentTimeMillis ();
882         Map<String, Object> baseStackOutputs = null;
883         if (nestedBaseStackId != null) {
884                 try {
885                         LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
886                         nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
887                 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
888                 } catch (MsoException me) {
889                     // Failed to query the Stack due to an openstack exception.
890                     // Convert to a generic VnfException
891                     me.addContext ("CreateVFModule");
892                     String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
893                 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
894                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
895                         LOGGER.debug("ERROR trying to query nested base stack= " + error);
896                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
897                     throw new VnfException (me);
898                 }
899                 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
900                     String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
901                     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");
902                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
903                     LOGGER.debug(error);
904                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
905                 } else {
906                         LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
907                         //this.sendMapToDebug(inputs);
908                         baseStackOutputs = nestedBaseHeatStack.getOutputs();
909                         this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
910                         //TODO
911                         //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);      
912                         //this.sendMapToDebug(inputs);
913                 }
914         }
915
916         // Ready to deploy the new VNF
917
918         CatalogDatabase db = CatalogDatabase.getInstance();
919
920         try {
921             // Retrieve the VF
922                 VfModule vf = null;
923                 VnfResource vnfResource = null;
924                 VfModuleCustomization vfmc = null;
925                 LOGGER.debug("version: " + vfVersion);
926             if (useMCUuid) {
927                         // 1707 - db refactoring
928                         vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
929                         vf = vfmc != null ? vfmc.getVfModule() : null;
930                 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
931                         //vf = db.getVfModuleByModelCustomizationUuid(mcu);
932                 if (vf == null) {
933                                 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
934                                 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
935                     LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
936                             "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
937                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
938                     throw new VnfException(error, MsoExceptionCategory.USERDATA);
939                 } else {
940                                 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
941                 }
942                 if (vf.isBase()) {
943                     isBaseRequest = true;
944                     LOGGER.debug("This is a BASE VF request!");
945                 } else {
946                     LOGGER.debug("This is *not* a BASE VF request!");
947                     if (!isVolumeRequest && nestedBaseStackId == null) {
948                         LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
949                     }
950                 }
951                 }
952                 /*
953                 else if (!oldWay) {
954                                 // Need to handle old and new schema methods - for a time. Try the new way first.
955                                 if (vfVersion != null && !vfVersion.isEmpty()) {
956                                         vf = db.getVfModuleType(vfModuleType, vfVersion);
957                                         if (vf == null) {
958                                                 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME");
959                                                 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
960                                                 if (vf == null) {
961                                                         LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
962                                                 }
963                                         }
964                                 } else {
965                                         vf = db.getVfModuleType(vfModuleType);
966                                         if (vf == null) {
967                                                 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
968                                                 vf = db.getVfModuleModelName(vfModuleType);
969                                                 if (vf == null) {
970                                                         LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
971                                                 }
972                                         }
973                                 }
974                                 if (vf == null) {
975                                         String error = "Create VF Module: Unable to determine specific VF Module Type: "
976                                                         + vfModuleType;
977                                         if (vfVersion != null && !vfVersion.isEmpty()) {
978                                                 error += " with version = " + vfVersion;
979                                         }
980                                         LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
981                                                         "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type");
982                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
983                                         throw new VnfException(error, MsoExceptionCategory.USERDATA);
984                                 }
985                                 LOGGER.debug("Got VF module definition from Catalog: "
986                                                 + vf.toString());
987
988                                 if (vf.isBase()) {
989                                         isBaseRequest = true;
990                                         LOGGER.debug("This is a BASE VF request!");
991                                 } else {
992                                         LOGGER.debug("This is *not* a BASE VF request!");
993                                         if (!isVolumeRequest && nestedBaseStackId == null) {
994                                                 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
995                                         }
996                                 }
997                         } */ 
998                 else { // This is to support gamma only - get info from vnf_resource table
999                                 if (vfVersion != null && !vfVersion.isEmpty()) {
1000                                         vnfResource = db.getVnfResource(vnfType, vnfVersion);
1001                                 } else {
1002                                         vnfResource = db.getVnfResource(vnfType);
1003                                 }
1004                                 if (vnfResource == null) {
1005                                         String error = "Create VNF: Unknown VNF Type: " + vnfType;
1006                                         LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
1007                                                         vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
1008                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1009                                         throw new VnfException(error, MsoExceptionCategory.USERDATA);
1010                                 }
1011                                 LOGGER.debug("Got VNF module definition from Catalog: "
1012                                                 + vnfResource.toString());
1013                         }
1014                         // By here - we have either a vf or vnfResource
1015
1016             //1607 - Add version check
1017             // First - see if it's in the VnfResource record
1018             // if we have a vf Module - then we have to query to get the VnfResource record.
1019             if (!oldWay) {
1020                 if (vf.getVnfResourceModelUUId() != null) { 
1021                         String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1022                         //vnfResource = db.getVnfResourceById(vnfResourceId);
1023                         vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1024                         if (vnfResource == null) {
1025                                 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1026                         }
1027                 }
1028             }
1029             String minVersionVnf = null;
1030             String maxVersionVnf = null;
1031             if (vnfResource != null) {
1032                 try {
1033                         minVersionVnf = vnfResource.getAicVersionMin();
1034                         maxVersionVnf = vnfResource.getAicVersionMax();
1035                 } catch (Exception e) {
1036                         LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1037                         minVersionVnf = null;
1038                         maxVersionVnf = null;
1039                 }
1040                 if (minVersionVnf != null && minVersionVnf.equals("")) {
1041                         minVersionVnf = null;
1042                 }
1043                 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1044                         maxVersionVnf = null;
1045                 }
1046             }
1047                         if (minVersionVnf != null && maxVersionVnf != null) {
1048                                 MavenLikeVersioning aicV = new MavenLikeVersioning();
1049                                 CloudSite cloudSite = null;
1050                                 String aicVersion = "";
1051                                 if (this.cloudConfig == null) {
1052                                         this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1053                                 }
1054                                 // double check
1055                                 if (this.cloudConfig != null) {
1056                                         cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1057                                         if (cloudSite != null) {
1058                                                 aicV.setVersion(cloudSite.getAic_version());
1059                                                 // Add code to handle unexpected values in here
1060                                                 boolean moreThanMin = true;
1061                                                 boolean equalToMin = true;
1062                                                 boolean moreThanMax = true;
1063                                                 boolean equalToMax = true;
1064                                                 boolean doNotTest = false;
1065                                                 try {
1066                                                         moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1067                                                         equalToMin = aicV.isTheSameVersion(minVersionVnf);
1068                                                         moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1069                                                         equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1070                                                 } catch (Exception e) {
1071                                                         LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e);
1072                                                         doNotTest = true;
1073                                                 }                                               
1074                                                 if (!doNotTest) {
1075                                                         if ((moreThanMin || equalToMin) // aic >= min
1076                                                                         && (equalToMax || !(moreThanMax))) { //aic <= max
1077                                                                 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1078                                                         } else {
1079                                                                 // ERROR
1080                                                                 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1081                                                                 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1082                                                                 LOGGER.debug(error);
1083                                                                 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1084                                                         }
1085                                                 } else {
1086                                                         LOGGER.debug("bypassing testing AIC version...");
1087                                                 }
1088                                         } // let this error out downstream to avoid introducing uncertainty at this stage
1089                                 } else {
1090                                         LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1091                                 }
1092                         } else {
1093                                 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1094                         }
1095                         // End Version check 1607
1096
1097             // with VF_MODULE - we have both the non-vol and vol template/envs in that object
1098             // with VNF_RESOURCE - we use the old methods.
1099             //Integer heatTemplateId = null;
1100             //Integer heatEnvtId = null;
1101             
1102             String heatTemplateArtifactUuid = null;
1103             String heatEnvironmentArtifactUuid = null;
1104
1105                         if (!oldWay) {
1106                                 if (isVolumeRequest) {
1107                                         heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1108                                         heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1109                                 } else {
1110                                         heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1111                                         heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1112                                 }
1113                         } else {
1114                                 if (isVolumeRequest) {
1115                                         LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
1116                                         /*
1117                                         VnfComponent vnfComponent = null;
1118                                         vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME");
1119                         if (vnfComponent == null) {
1120                                 String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME";
1121                                 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry");
1122                         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1123                                 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1124                         } else {
1125                                 heatTemplateId = vnfComponent.getHeatTemplateId();
1126                                 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1127                         }
1128                         */
1129                                 } else {
1130                                         heatTemplateArtifactUuid = vnfResource.getTemplateId();
1131                                         heatEnvironmentArtifactUuid = null;
1132                                 }
1133                         }
1134                         // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1135                         HeatTemplate heatTemplate = null;
1136                         if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) {
1137                                 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1138                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1139                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1140                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1141                                                 MsoAlarmLogger.CRITICAL, error);
1142                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1143                         } else {
1144                                 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1145                         }
1146                         if (heatTemplate == null) {
1147                                 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1148                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1149                                                 "Heat Template ID",
1150                                                 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1151                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1152                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1153                                                 MsoAlarmLogger.CRITICAL, error);
1154                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1155                         }
1156                         LOGGER.debug("Got HEAT Template from DB");
1157
1158             HeatEnvironment heatEnvironment = null;
1159             String heatEnvironmentString = null;
1160
1161             if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals("")) {
1162                 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1163                 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1164                 if (heatEnvironment == null) {
1165                     String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1166                                    + ", Environment ID="
1167                                    + heatEnvironmentArtifactUuid;
1168                     LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1169                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1170                     // Alarm on this error, configuration must be fixed
1171                     alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1172
1173                     throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1174                 } else {
1175                     LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1176                     heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1177                     LOGGER.debug ("after parsing: " + heatEnvironmentString);
1178                 }
1179             } else {
1180                 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
1181             }
1182
1183             // 1510 - Add the files: for nested templates *if* there are any
1184             LOGGER.debug ("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1185                           + heatTemplate.getArtifactUuid());
1186             Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid());
1187             Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1188             if (nestedTemplates != null) {
1189                 // for debugging print them out
1190                 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1191                 for (String providerResourceFile : nestedTemplates.keySet ()) {
1192                     String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1193                     String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1194                     LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1195                     nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1196                 }
1197             } else {
1198                 LOGGER.debug ("No nested templates found - nothing to do here");
1199                 nestedTemplatesChecked = null; // just to make sure
1200             }
1201
1202             // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1203             // *if* there are any
1204             Map<String, HeatFiles> heatFiles = null;
1205                         Map<String, Object> heatFilesObjects = new HashMap<String, Object>();
1206
1207             // Add ability to turn on adding get_files with volume requests (by property).
1208             boolean addGetFilesOnVolumeReq = false;
1209             try {
1210                 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1211                 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1212                         addGetFilesOnVolumeReq = true;
1213                         LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1214                 }
1215             } catch (Exception e) {
1216                 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1217             }
1218
1219                         if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1220                                 if (oldWay) {
1221                                         LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1222                                         //heatFiles = db.getHeatFiles(vnfResource.getId());
1223                                 } else {
1224                                         // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1225                                         LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1226                                                         + vf.getModelUUID());
1227                                         heatFiles = db
1228                                                         .getHeatFilesForVfModule(vf.getModelUUID());
1229                                 }
1230                                 if (heatFiles != null) {
1231                                         // add these to stack - to be done in createStack
1232                                         // here, we will map them to Map<String, Object> from
1233                                         // Map<String, HeatFiles>
1234                                         // this will match the nested templates format
1235                                         LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1236
1237                                         for (String heatFileName : heatFiles.keySet()) {
1238                                                 if (heatFileName.startsWith("_ERROR|")) {
1239                                                         // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1240                                                         String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1241                                                         String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1242                                                         LOGGER.debug(error);
1243                                                         LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1244                             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1245                                                         // Alarm on this error, configuration must be fixed
1246                                                         alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1247                                                         throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1248                                                 }
1249                                                 String heatFileBody = heatFiles.get(heatFileName)
1250                                                                 .getFileBody();
1251                                                 String heatFileNameChecked = heatFileName;
1252                                                 LOGGER.debug(heatFileNameChecked + " -> "
1253                                                                 + heatFileBody);
1254                                                 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1255                                         }
1256                                 } else {
1257                                         LOGGER.debug("No heat files found -nothing to do here");
1258                                         heatFilesObjects = null;
1259                                 }
1260                         } else {
1261                                         LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1262                         }
1263
1264             // Check that required parameters have been supplied
1265             String missingParams = null;
1266             List <String> paramList = new ArrayList <String> ();
1267
1268             // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1269             // supplied an alias. Only check if we don't find it initially.
1270             // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1271             // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1272             // shouldn't
1273             boolean haveEnvironmentParameters = false;
1274             boolean checkRequiredParameters = true;
1275             try {
1276                 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1277                                                      .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1278                 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1279                     checkRequiredParameters = false;
1280                     LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1281                                   + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1282                 }
1283             } catch (Exception e) {
1284                 // No problem - default is true
1285                 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1286             }
1287             // 1604 - Add enhanced environment & parameter checking
1288             // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1289             // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1290             // Note this also removes any comments
1291             MsoHeatEnvironmentEntry mhee = null;
1292             if (heatEnvironmentString != null && heatEnvironmentString.contains ("parameters:")) {
1293                 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1294                 LOGGER.debug("Enhanced environment checking enabled - 1604");
1295                 haveEnvironmentParameters = true;
1296                 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1297                 //LOGGER.debug("About to create MHEE with " + sb);
1298                 mhee = new MsoHeatEnvironmentEntry(sb);
1299                 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1300                 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1301                         sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1302                 }
1303                 if (!mhee.isValid()) {
1304                         sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1305                 } else {
1306                         sb2.append("\nEnvironment:");
1307                         sb2.append(mhee.toFullString());
1308                 }
1309                 LOGGER.debug(sb2.toString());
1310             } else {
1311                 LOGGER.debug("NO ENVIRONMENT for this entry");
1312             }
1313             // New with 1707 - all variables converted to their native object types
1314             HashMap<String, Object> goldenInputs = null;
1315             
1316             LOGGER.debug("Now handle the inputs....first convert");
1317             ArrayList<String> parameterNames = new ArrayList<String>();
1318             HashMap<String, String> aliasToParam = new HashMap<String, String>();
1319             StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1320             int cntr = 0;
1321             try { 
1322                 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1323                         sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1324                         parameterNames.add(htp.getParamName());
1325                         if (htp.getParamAlias() != null && !htp.getParamAlias().equals("")) {
1326                                 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1327                                 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1328                         }
1329                         sb.append("\n");
1330                 }
1331                 LOGGER.debug(sb.toString());
1332             } catch (Exception e) {
1333                 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e);
1334             }
1335             // Step 1 - convert what we got as inputs (Map<String, String>) to a 
1336             // Map<String, Object> - where the object matches the param type identified in the template
1337             // This will also not copy over params that aren't identified in the template
1338             goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1339             // Step 2 - now simply add the outputs as we received them - no need to convert to string
1340             LOGGER.debug("Now add in the base stack outputs if applicable");
1341             heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1342             // Step 3 - add the volume inputs if any
1343             LOGGER.debug("Now add in the volume stack outputs if applicable");
1344             heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1345             this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1346             
1347             for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1348                 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1349                               + "', isRequired="
1350                               + parm.isRequired ()
1351                               + ", alias="
1352                               + parm.getParamAlias ());
1353
1354                 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1355                         // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1356                         LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment");
1357                     if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1358                         LOGGER.debug ("Required parameter " + parm.getParamName ()
1359                                       + " appears to be in environment - do not count as missing");
1360                     } else {
1361                         LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1362                         if (missingParams == null) {
1363                             missingParams = parm.getParamName ();
1364                         } else {
1365                             missingParams += "," + parm.getParamName ();
1366                         }
1367                     }
1368                 }
1369                 paramList.add (parm.getParamName ());
1370             }
1371             if (missingParams != null) {
1372                 if (checkRequiredParameters) {
1373                         // Problem - missing one or more required parameters
1374                         String error = "Create VFModule: Missing Required inputs: " + missingParams;
1375                         LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1376                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1377                         throw new VnfException (error, MsoExceptionCategory.USERDATA);
1378                 } else {
1379                         LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1380                 }
1381             } else {
1382                 LOGGER.debug ("No missing parameters found - ok to proceed");
1383             }
1384             // We can now remove the recreating of the ENV with only legit params - that check is done for us, 
1385             // and it causes problems with json that has arrays
1386             String newEnvironmentString = null;
1387             if (mhee != null) {
1388                 newEnvironmentString = mhee.getRawEntry().toString();
1389             }
1390             
1391             // "Fix" the template if it has CR/LF (getting this from Oracle)
1392             String template = heatTemplate.getHeatTemplate ();
1393             template = template.replaceAll ("\r\n", "\n");
1394
1395             // Have the tenant. Now deploy the stack itself
1396             // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1397             // because we already checked for those.
1398             long createStackStarttime = System.currentTimeMillis ();
1399             try {
1400                 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1401                 // heatTemplate.getTimeoutMinutes());
1402                 if (backout == null) {
1403                         backout = true;
1404                 }
1405                 if (heat != null) {
1406                         LOGGER.debug("heat is not null!!");
1407                 }
1408                         heatStack = heat.createStack (cloudSiteId,
1409                                               tenantId,
1410                                               vfModuleName,
1411                                               template,
1412                         goldenInputs,
1413                                               true,
1414                                               heatTemplate.getTimeoutMinutes (),
1415                                               newEnvironmentString,
1416                                               nestedTemplatesChecked,
1417                                               heatFilesObjects,
1418                                               backout.booleanValue());
1419                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1420             } catch (MsoException me) {
1421                 me.addContext ("CreateVFModule");
1422                 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1423                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1424                 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1425                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1426                 throw new VnfException (me);
1427             } catch (NullPointerException npe) {
1428                 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1429                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1430                 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1431                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1432                 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1433                 //npe.addContext ("CreateVNF");
1434                 throw new VnfException ("NullPointerException during heat.createStack");
1435             } catch (Exception e) {
1436                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1437                 LOGGER.debug("unhandled exception at heat.createStack",e);
1438                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1439                 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1440             }
1441         } catch (Exception e) {
1442                 LOGGER.debug("unhandled exception in create VF",e);
1443                 throw new VnfException("Exception during create VF " + e.getMessage());
1444
1445         } finally {
1446             // Make sure DB session is closed
1447             db.close ();
1448         }
1449
1450         // Reach this point if createStack is successful.
1451         // Populate remaining rollback info and response parameters.
1452         vfRollback.setVnfId (heatStack.getCanonicalName ());
1453         vfRollback.setVnfCreated (true);
1454
1455         vnfId.value = heatStack.getCanonicalName ();
1456         outputs.value = copyStringOutputs (heatStack.getOutputs ());
1457         rollback.value = vfRollback;
1458
1459         LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1460         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1461         return;
1462     }
1463
1464     @Override
1465     public void deleteVfModule (String cloudSiteId,
1466                            String tenantId,
1467                            String vnfName,
1468                            MsoRequest msoRequest,
1469                            Holder <Map <String, String>> outputs) throws VnfException {
1470         MsoLogger.setLogContext (msoRequest);
1471         MsoLogger.setServiceName ("DeleteVf");
1472         LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1473         // Will capture execution time for metrics
1474         long startTime = System.currentTimeMillis ();
1475
1476         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1477
1478         // 1702 capture the output parameters on a delete
1479         // so we'll need to query first
1480         Map<String, Object> stackOutputs = null;
1481         try {
1482             stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1483         } catch (MsoException me) {
1484             // Failed to query the Stack due to an openstack exception.
1485             // Convert to a generic VnfException
1486             me.addContext ("DeleteVFModule");
1487             String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1488             LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1489             LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1490             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1491             throw new VnfException (me);
1492         }
1493         // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1494         outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1495
1496         // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1497         // The possible outcomes of deleteStack are a StackInfo object with status
1498         // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1499         // could be thrown.
1500         long subStartTime = System.currentTimeMillis ();
1501         try {
1502             heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1503             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1504         } catch (MsoException me) {
1505             me.addContext ("DeleteVNF");
1506             // Failed to query the Stack due to an openstack exception.
1507             // Convert to a generic VnfException
1508             String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1509             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1510             LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1511             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1512             throw new VnfException (me);
1513         }
1514
1515         // On success, nothing is returned.
1516         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1517         return;
1518     }
1519
1520     @Override
1521     public void updateVfModule (String cloudSiteId,
1522                            String tenantId,
1523                            String vnfType,
1524                            String vnfVersion,
1525                            String vnfName,
1526                            String requestType,
1527                            String volumeGroupHeatStackId,
1528                            String baseVfHeatStackId,
1529                            String vfModuleStackId,
1530                            String modelCustomizationUuid,
1531                            Map <String, String> inputs,
1532                            MsoRequest msoRequest,
1533                            Holder <Map <String, String>> outputs,
1534                            Holder <VnfRollback> rollback) throws VnfException {
1535         String vfModuleName = vnfName;
1536         String vfModuleType = vnfType;
1537         String vfVersion = vnfVersion;
1538         String methodName = "updateVfModule";
1539         MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1540         String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1541         MsoLogger.setServiceName (serviceName);
1542         
1543         StringBuilder sbInit = new StringBuilder();
1544         sbInit.append("updateVfModule: \n");
1545         sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1546         sbInit.append("tenantId=" + tenantId + "\n");
1547         sbInit.append("vnfType=" + vnfType + "\n");
1548         sbInit.append("vnfVersion=" + vnfVersion + "\n");
1549         sbInit.append("vnfName=" + vnfName + "\n");
1550         sbInit.append("requestType=" + requestType + "\n");
1551         sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1552         sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1553         sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1554         sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1555         LOGGER.debug(sbInit.toString());
1556
1557         String mcu = modelCustomizationUuid;
1558         boolean useMCUuid = false;
1559         if (mcu != null && !mcu.isEmpty()) {
1560             if (mcu.equalsIgnoreCase("null")) {
1561                 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1562                 useMCUuid = false;
1563                 mcu = "";
1564             } else {
1565                 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1566                 useMCUuid = true;
1567             }
1568         }
1569
1570         String requestTypeString = "";
1571         if (requestType != null && !requestType.equals("")) {
1572                 requestTypeString = requestType;
1573         }
1574         String nestedStackId = null;
1575         if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1576                 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1577                         nestedStackId = volumeGroupHeatStackId;
1578                 }
1579         }
1580         String nestedBaseStackId = null;
1581         if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1582                 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1583                         nestedBaseStackId = baseVfHeatStackId;
1584                 }
1585         }
1586
1587         if (inputs == null) {
1588                 // Create an empty set of inputs
1589                 inputs = new HashMap<String,String>();
1590                 LOGGER.debug("inputs == null - setting to empty");
1591         } else {
1592                 this.sendMapToDebug(inputs);
1593         }
1594         boolean isBaseRequest = false;
1595         boolean isVolumeRequest = false;
1596         if (requestTypeString.startsWith("VOLUME")) {
1597                 isVolumeRequest = true;
1598         }
1599         if (vfModuleName == null || vfModuleName.trim().equals("")) {
1600                 if (vfModuleStackId != null) {
1601                         vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1602                 }
1603         }
1604
1605         LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1606         LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1607
1608         // Will capture execution time for metrics
1609         long startTime = System.currentTimeMillis ();
1610
1611         // Build a default rollback object (no actions performed)
1612         VnfRollback vfRollback = new VnfRollback ();
1613         vfRollback.setCloudSiteId (cloudSiteId);
1614         vfRollback.setTenantId (tenantId);
1615         vfRollback.setMsoRequest (msoRequest);
1616         vfRollback.setRequestType(requestTypeString);
1617         vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1618         vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1619         vfRollback.setIsBase(isBaseRequest);
1620         vfRollback.setVfModuleStackId(vfModuleStackId);
1621         vfRollback.setModelCustomizationUuid(mcu);
1622
1623         // First, look up to see if the VNF already exists.
1624         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1625         MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1626
1627         StackInfo heatStack = null;
1628         long queryStackStarttime = System.currentTimeMillis ();
1629         LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1630         try {
1631             heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1632             LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1633         } catch (MsoException me) {
1634             // Failed to query the Stack due to an openstack exception.
1635             // Convert to a generic VnfException
1636             me.addContext ("UpdateVFModule");
1637             String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1638             LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1639             LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1640             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1641             throw new VnfException (me);
1642         }
1643
1644         //TODO - do we need to check for the other status possibilities?
1645         if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1646             // Not Found
1647             String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1648             LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1649             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1650             throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1651         } else {
1652             LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1653             // Populate the outputs from the existing stack.
1654             outputs.value = copyStringOutputs (heatStack.getOutputs ());
1655             rollback.value = vfRollback; // Default rollback - no updates performed
1656         }
1657
1658         // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1659         StackInfo nestedHeatStack = null;
1660         long queryStackStarttime2 = System.currentTimeMillis ();
1661         Map<String, Object> nestedVolumeOutputs = null;
1662         if (nestedStackId != null) {
1663                 try {
1664                         LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1665                         nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1666                 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1667                 } catch (MsoException me) {
1668                     // Failed to query the Stack due to an openstack exception.
1669                     // Convert to a generic VnfException
1670                     me.addContext ("UpdateVFModule");
1671                     String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1672                 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1673                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1674                         LOGGER.debug("ERROR trying to query nested stack= " + error);
1675                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1676                     throw new VnfException (me);
1677                 }
1678                 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1679                         MsoLogger.setServiceName (serviceName);
1680                     String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
1681                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1682                     LOGGER.debug(error);
1683                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1684                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
1685                 } else {
1686                         LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1687                         nestedVolumeOutputs = nestedHeatStack.getOutputs();
1688                         //this.sendMapToDebug(inputs);
1689                         this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1690                         //TODO
1691                         heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1692                         //this.sendMapToDebug(inputs);
1693                 }
1694         }
1695         // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1696         StackInfo nestedBaseHeatStack = null;
1697         Map<String, Object> baseStackOutputs = null;
1698         if (nestedBaseStackId != null) {
1699             long queryStackStarttime3 = System.currentTimeMillis ();
1700                 try {
1701                         LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1702                         nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1703                 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1704                 } catch (MsoException me) {
1705                     // Failed to query the Stack due to an openstack exception.
1706                     // Convert to a generic VnfException
1707                     me.addContext ("UpdateVfModule");
1708                     String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1709                 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1710                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1711                         LOGGER.debug("ERROR trying to query nested base stack= " + error);
1712                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1713                     throw new VnfException (me);
1714                 }
1715                 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1716                         MsoLogger.setServiceName (serviceName);
1717                     String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
1718                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1719                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1720                     LOGGER.debug(error);
1721                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
1722                 } else {
1723                         LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1724                         baseStackOutputs = nestedBaseHeatStack.getOutputs();
1725                         //this.sendMapToDebug(inputs);
1726                         this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1727                         //TODO
1728                         heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1729                         //this.sendMapToDebug(inputs);
1730                 }
1731         }
1732
1733         // Ready to deploy the new VNF
1734
1735         // Get a handle to the Catalog Database
1736         CatalogDatabase db = CatalogDatabase.getInstance();
1737
1738         // Make sure DB session is closed
1739         try {
1740             // Retrieve the VF definition
1741             VnfResource vnfResource = null;
1742                 VfModule vf = null;
1743                 VfModuleCustomization vfmc = null;
1744             if (useMCUuid) {
1745                         //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1746                         vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1747                         vf = vfmc != null ? vfmc.getVfModule() : null;
1748                 if (vf == null) {
1749                     LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1750                 }
1751                 } else {
1752                         LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1753             }
1754                 if (vf == null) {
1755                 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1756                 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1757                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1758                 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1759             }
1760             LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
1761             if (vf.isBase()) {
1762                 isBaseRequest = true;
1763                 LOGGER.debug("This a BASE update request");
1764             } else {
1765                 LOGGER.debug("This is *not* a BASE VF update request");
1766                 if (!isVolumeRequest && nestedBaseStackId == null) {
1767                         LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1768                 }
1769             }
1770             
1771             //1607 - Add version check
1772             // First - see if it's in the VnfResource record
1773             // if we have a vf Module - then we have to query to get the VnfResource record.
1774             if (vf.getVnfResourceModelUUId() != null) { 
1775                 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1776                 //vnfResource = db.getVnfResourceById(vnfResourceId);
1777                 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1778                 if (vnfResource == null) {
1779                         LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1780                 }
1781             }
1782             String minVersionVnf = null;
1783             String maxVersionVnf = null;
1784             if (vnfResource != null) {
1785                 try {
1786                         minVersionVnf = vnfResource.getAicVersionMin();
1787                         maxVersionVnf = vnfResource.getAicVersionMax();
1788                 } catch (Exception e) {
1789                         LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1790                         minVersionVnf = null;
1791                         maxVersionVnf = null;
1792                         }
1793                 if (minVersionVnf != null && minVersionVnf.equals("")) {
1794                         minVersionVnf = null;
1795                 }
1796                 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1797                         maxVersionVnf = null;
1798                         }
1799                 }
1800                         if (minVersionVnf != null && maxVersionVnf != null) {
1801                                 MavenLikeVersioning aicV = new MavenLikeVersioning();
1802                                 CloudSite cloudSite = null;
1803                                 //String aicVersion = "";
1804                                 if (this.cloudConfig == null) {
1805                                         this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1806             }
1807                                 // double check
1808                                 if (this.cloudConfig != null) {
1809                                         cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1810                                         if (cloudSite != null) {
1811                                                 aicV.setVersion(cloudSite.getAic_version());
1812                                                 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1813                                                                 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV.isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1814                                                         LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1815                                                 } else {
1816                                                         // ERROR
1817                                                         String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1818                                                         LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1819                                                         LOGGER.debug(error);
1820                                                         throw new VnfException(error, MsoExceptionCategory.USERDATA);
1821                     }
1822                                         } // let this error out downstream to avoid introducing uncertainty at this stage
1823                 } else {
1824                                         LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1825                 }
1826
1827                         } else {
1828                                 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1829             }
1830                         // End Version check 1607
1831             
1832                         String heatTemplateArtifactUuid = null;
1833                         String heatEnvironmentArtifactUuid = null;
1834
1835             HeatTemplate heatTemplate = null;
1836                         if (isVolumeRequest) {
1837                                 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1838                                 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1839                         } else {
1840                                 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1841                                 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1842                         }
1843                         if (heatTemplateArtifactUuid == null) {
1844                                 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1845                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1846                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1847                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1848                                                 MsoAlarmLogger.CRITICAL, error);
1849                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1850                         } else {
1851                                 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1852                         }
1853
1854                         if (heatTemplate == null) {
1855                                 String error = "Update VNF: undefined Heat Template. VF="
1856                                                 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1857                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1858                                                 "Heat Template ID",
1859                                                 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1860                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1861                                 // Alarm on this error, configuration must be fixed
1862                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1863                                                 MsoAlarmLogger.CRITICAL, error);
1864
1865                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1866                         }
1867
1868             LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
1869
1870             // Add check for any Environment variable
1871             HeatEnvironment heatEnvironment = null;
1872             String heatEnvironmentString = null;
1873
1874             if (heatEnvironmentArtifactUuid != null) {
1875                 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1876                 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1877                 if (heatEnvironment == null) {
1878
1879                     String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1880                                    + ", Environment ID="
1881                                    + heatEnvironmentArtifactUuid;
1882                     LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1883                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1884                     // Alarm on this error, configuration must be fixed
1885                     alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1886
1887                     throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1888                 } else {
1889                     LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1890                     heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1891                     LOGGER.debug ("After parsing: " + heatEnvironmentString);
1892                 }
1893             } else {
1894                 LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType);
1895             }
1896
1897
1898             LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1899                           + heatTemplate.getArtifactUuid ());
1900             Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid ());
1901             Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1902             if (nestedTemplates != null) {
1903                 // for debugging print them out
1904                 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1905                 for (String providerResourceFile : nestedTemplates.keySet ()) {
1906                     String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1907                     String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1908                     nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1909                     LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1910                 }
1911             } else {
1912                 LOGGER.debug ("No nested templates found - nothing to do here");
1913                 nestedTemplatesChecked = null;
1914             }
1915
1916             // Also add the files: for any get_files associated with this VfModule
1917             // *if* there are any
1918             LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1919                           + vf.getModelUUID());
1920
1921             Map <String, HeatFiles> heatFiles = null;
1922 //            Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1923             Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
1924
1925             // Add ability to turn on adding get_files with volume requests (by property).
1926             boolean addGetFilesOnVolumeReq = false;
1927             try {
1928                 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1929                 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1930                         addGetFilesOnVolumeReq = true;
1931                         LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1932                 }
1933             } catch (Exception e) {
1934                 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1935             }
1936             if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1937                 LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1938                                                 + vf.getModelUUID());
1939
1940                 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1941                 if (heatFiles != null) {
1942                     // add these to stack - to be done in createStack
1943                     // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1944                     // this will match the nested templates format
1945                     LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
1946
1947                     for (String heatFileName : heatFiles.keySet ()) {
1948                                                 if (heatFileName.startsWith("_ERROR|")) {
1949                                                         // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1950                                                         String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1951                                                         String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1952                                                         LOGGER.debug(error);
1953                                                         LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1954                             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1955                                                         // Alarm on this error, configuration must be fixed
1956                                                         alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1957                                                         throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1958                                                 }
1959                         String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
1960                         LOGGER.debug (heatFileName + " -> " + heatFileBody);
1961                         heatFilesObjects.put (heatFileName, heatFileBody);
1962                     }
1963                 } else {
1964                     LOGGER.debug ("No heat files found -nothing to do here");
1965                     heatFilesObjects = null;
1966                 }
1967             }
1968
1969             // Check that required parameters have been supplied
1970             String missingParams = null;
1971             List <String> paramList = new ArrayList <String> ();
1972
1973             // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1974             // supplied an alias. Only check if we don't find it initially.
1975             // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1976             // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1977             // shouldn't
1978             boolean haveEnvironmentParameters = false;
1979             boolean checkRequiredParameters = true;
1980             try {
1981                 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1982                                                      .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1983                 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1984                     checkRequiredParameters = false;
1985                     LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1986                                   + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1987                 }
1988             } catch (Exception e) {
1989                 // No problem - default is true
1990                 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1991             }
1992             // 1604 - Add enhanced environment & parameter checking
1993             // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1994             // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1995             // Note this also removes any comments
1996             MsoHeatEnvironmentEntry mhee = null;
1997             if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) {
1998                 LOGGER.debug("Enhanced environment checking enabled - 1604");
1999                 haveEnvironmentParameters = true;
2000                 StringBuilder sb = new StringBuilder(heatEnvironmentString);
2001                 //LOGGER.debug("About to create MHEE with " + sb);
2002                 mhee = new MsoHeatEnvironmentEntry(sb);
2003                 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
2004                 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
2005                         sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
2006                 }
2007                 if (!mhee.isValid()) {
2008                         sb2.append("Environment says it's not valid! " + mhee.getErrorString());
2009                 } else {
2010                         sb2.append("\nEnvironment:");
2011                         sb2.append(mhee.toFullString());
2012                 }
2013                 LOGGER.debug(sb2.toString());
2014             } else {
2015                 LOGGER.debug("NO ENVIRONMENT for this entry");
2016             }
2017
2018             // New for 1607 - support params of json type
2019             HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
2020             boolean hasJson = false;
2021
2022             for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
2023                 LOGGER.debug ("Parameter:'" + parm.getParamName ()
2024                               + "', isRequired="
2025                               + parm.isRequired ()
2026                               + ", alias="
2027                               + parm.getParamAlias ());
2028                 // handle json
2029                 String parameterType = parm.getParamType();
2030                 if (parameterType == null || parameterType.trim().equals("")) {
2031                         parameterType = "String";
2032                 }
2033                 JsonNode jsonNode = null;
2034                 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
2035                         if (inputs.containsKey(parm.getParamName()) ) {
2036                                 hasJson = true;
2037                                 String jsonString = null;
2038                                 try {
2039                                         jsonString = inputs.get(parm.getParamName());
2040                                         jsonNode = new ObjectMapper().readTree(jsonString);
2041                                 } catch (JsonParseException jpe) {
2042                                         //TODO - what to do here?
2043                                         //for now - send the error to debug, but just leave it as a String
2044                                         String errorMessage = jpe.getMessage();
2045                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
2046                                         hasJson = false;
2047                                         jsonNode = null;
2048                                 } catch (Exception e) {
2049                                         // or here?
2050                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2051                                         hasJson = false;
2052                                         jsonNode = null;
2053                                 }
2054                                 if (jsonNode != null) {
2055                                         jsonParams.put(parm.getParamName(), jsonNode);
2056                                 }
2057                         } else if (inputs.containsKey(parm.getParamAlias())) {
2058                                 hasJson = true;
2059                                 String jsonString = null;
2060                                 try {
2061                                         jsonString = inputs.get(parm.getParamAlias());
2062                                         jsonNode = new ObjectMapper().readTree(jsonString);
2063                                 } catch (JsonParseException jpe) {
2064                                         //TODO - what to do here?
2065                                         //for now - send the error to debug, but just leave it as a String
2066                                         String errorMessage = jpe.getMessage();
2067                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
2068                                         hasJson = false;
2069                                         jsonNode = null;
2070                                 } catch (Exception e) {
2071                                         // or here?
2072                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2073                                         hasJson = false;
2074                                         jsonNode = null;
2075                                 }
2076                                 if (jsonNode != null) {
2077                                         // Notice here - we add it to the jsonParams hashMap with the actual name -
2078                                         // then manipulate the inputs so when we check for aliases below - it will not
2079                                         // get flagged.
2080                                         jsonParams.put(parm.getParamName(), jsonNode);
2081                                         inputs.remove(parm.getParamAlias());
2082                                         inputs.put(parm.getParamName(), jsonString);
2083                                 }
2084                         } //TODO add a check for the parameter in the env file
2085                 }
2086
2087                 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
2088                     if (inputs.containsKey (parm.getParamAlias ())) {
2089                         // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2090                         String realParamName = parm.getParamName ();
2091                         String alias = parm.getParamAlias ();
2092                         String value = inputs.get (alias);
2093                         LOGGER.debug ("*Found an Alias: paramName=" + realParamName
2094                                       + ",alias="
2095                                       + alias
2096                                       + ",value="
2097                                       + value);
2098                         inputs.remove (alias);
2099                         inputs.put (realParamName, value);
2100                         LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
2101                     }
2102                     // enhanced - check if it's in the Environment (note: that method
2103                     else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2104
2105                         LOGGER.debug ("Required parameter " + parm.getParamName ()
2106                                       + " appears to be in environment - do not count as missing");
2107                     }
2108                     else {
2109                         LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
2110                         if (missingParams == null) {
2111                             missingParams = parm.getParamName ();
2112                         } else {
2113                             missingParams += "," + parm.getParamName ();
2114                         }
2115                     }
2116                 }
2117                 paramList.add (parm.getParamName ());
2118             }
2119             if (missingParams != null) {
2120                 // Problem - missing one or more required parameters
2121                 if (checkRequiredParameters) {
2122                 String error = "Update VNF: Missing Required inputs: " + missingParams;
2123                 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2124                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
2125                 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2126                 } else {
2127                         LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
2128                 }
2129             } else {
2130                 LOGGER.debug ("No missing parameters found - ok to proceed");
2131             }
2132
2133             // Just submit the envt entry as received from the database
2134             String newEnvironmentString = null;
2135             if (mhee != null) {
2136                 newEnvironmentString = mhee.getRawEntry().toString();
2137             }
2138
2139             // Remove any extraneous parameters (don't throw an error)
2140             if (inputs != null) {
2141                 List <String> extraParams = new ArrayList <String> ();
2142                 extraParams.addAll (inputs.keySet ());
2143                 // This is not a valid parameter for this template
2144                 extraParams.removeAll (paramList);
2145                 if (!extraParams.isEmpty ()) {
2146                         LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
2147                     inputs.keySet ().removeAll (extraParams);
2148                 }
2149             }
2150             // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2151             Map<String, Object> inputsTwo = null;
2152             if (hasJson && jsonParams.size() > 0) {
2153                 inputsTwo = new HashMap<String, Object>();
2154                 for (String keyParamName : inputs.keySet()) {
2155                         if (jsonParams.containsKey(keyParamName)) {
2156                                 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2157                         } else {
2158                                 inputsTwo.put(keyParamName, inputs.get(keyParamName));
2159                         }
2160                 }
2161             }
2162
2163             // "Fix" the template if it has CR/LF (getting this from Oracle)
2164             String template = heatTemplate.getHeatTemplate ();
2165             template = template.replaceAll ("\r\n", "\n");
2166
2167             // Have the tenant. Now deploy the stack itself
2168             // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2169             // because we already checked for those.
2170             long updateStackStarttime = System.currentTimeMillis ();
2171             try {
2172                 if (!hasJson) {
2173                         heatStack = heatU.updateStack (cloudSiteId,
2174                                                tenantId,
2175                                                vfModuleName,
2176                                                template,
2177                                                copyStringInputs (inputs),
2178                                                true,
2179                                                heatTemplate.getTimeoutMinutes (),
2180                                                newEnvironmentString,
2181                                                //heatEnvironmentString,
2182                                                nestedTemplatesChecked,
2183                                                heatFilesObjects);
2184                         LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2185                 } else {
2186                         heatStack = heatU.updateStack (cloudSiteId,
2187                                                tenantId,
2188                                                vfModuleName,
2189                                                template,
2190                                                inputsTwo,
2191                                                true,
2192                                                heatTemplate.getTimeoutMinutes (),
2193                                                newEnvironmentString,
2194                                                //heatEnvironmentString,
2195                                                nestedTemplatesChecked,
2196                                                heatFilesObjects);
2197                         LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2198
2199                 }
2200             } catch (MsoException me) {
2201                 me.addContext ("UpdateVFModule");
2202                 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2203                 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2204                 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2205                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2206                 throw new VnfException (me);
2207             }
2208         } finally {
2209             // Make sure DB session is closed
2210             db.close ();
2211         }
2212
2213         // Reach this point if updateStack is successful.
2214         // Populate remaining rollback info and response parameters.
2215         vfRollback.setVnfId (heatStack.getCanonicalName ());
2216         vfRollback.setVnfCreated (true);
2217
2218         outputs.value = copyStringOutputs (heatStack.getOutputs ());
2219         rollback.value = vfRollback;
2220         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2221         return;
2222     }
2223
2224     private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2225         // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2226         // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2227         if (vfModuleStackId == null)
2228                 return null;
2229         int index = vfModuleStackId.lastIndexOf('/');
2230         if (index <= 0)
2231                 return null;
2232         String vfModuleName = null;
2233         try {
2234                 vfModuleName = vfModuleStackId.substring(0, index);
2235         } catch (Exception e) {
2236                 LOGGER.debug("Exception", e);
2237                 vfModuleName = null;
2238         }
2239         return vfModuleName;
2240     }
2241
2242 }