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