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