44922a7a8aa9b768539b5004e4499cbbe6fcc9a2
[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     public void createVfModule(String cloudSiteId,
647             String tenantId,
648             String vnfType,
649             String vnfVersion,
650             String vnfName,
651             String requestType,
652             String volumeGroupHeatStackId,
653             String baseVfHeatStackId,
654             String modelCustomizationUuid,
655             Map <String, String> inputs,
656             Boolean failIfExists,
657             Boolean backout,
658             MsoRequest msoRequest,
659             Holder <String> vnfId,
660             Holder <Map <String, String>> outputs,
661             Holder <VnfRollback> rollback) throws VnfException {
662         String vfModuleName = vnfName;
663         String vfModuleType = vnfType;
664         String vfVersion = vnfVersion;
665         String mcu = modelCustomizationUuid;
666         boolean useMCUuid = false;
667         if (mcu != null && !mcu.isEmpty()) {
668             if (mcu.equalsIgnoreCase("null")) {
669                 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
670                 useMCUuid = false;
671                 mcu = "";
672             } else {
673                 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
674                 useMCUuid = true;
675             }
676         }
677         MsoLogger.setLogContext (msoRequest);
678         MsoLogger.setServiceName ("CreateVfModule");
679         String requestTypeString = "";
680         if (requestType != null && !requestType.equals("")) {
681                 requestTypeString = requestType;
682         }
683         String nestedStackId = null;
684         if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
685                 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
686                         nestedStackId = volumeGroupHeatStackId;
687                 }
688         }
689         String nestedBaseStackId = null;
690         if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
691                 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
692                         nestedBaseStackId = baseVfHeatStackId;
693                 }
694         }
695
696         if (inputs == null) {
697                 // Create an empty set of inputs
698                 inputs = new HashMap<String,String>();
699                 LOGGER.debug("inputs == null - setting to empty");
700         } else {
701                 this.sendMapToDebug(inputs);
702         }
703         //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
704         boolean oldWay = false;
705         if (requestTypeString.startsWith("X")) {
706                 oldWay = true;
707                 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
708                 requestTypeString = requestTypeString.substring(1);
709         }
710
711         // 1607 - let's parse out the request type we're being sent
712         boolean isBaseRequest = false;
713         boolean isVolumeRequest = false;
714         if (requestTypeString.startsWith("VOLUME")) {
715                 isVolumeRequest = true;
716         }
717
718         LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
719         // Will capture execution time for metrics
720         long startTime = System.currentTimeMillis ();
721
722         // Build a default rollback object (no actions performed)
723         VnfRollback vfRollback = new VnfRollback();
724         vfRollback.setCloudSiteId(cloudSiteId);
725         vfRollback.setTenantId(tenantId);
726         vfRollback.setMsoRequest(msoRequest);
727         vfRollback.setRequestType(requestTypeString);
728         vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
729         vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
730         vfRollback.setIsBase(isBaseRequest);
731         vfRollback.setModelCustomizationUuid(mcu);
732
733         // First, look up to see if the VF already exists.
734         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
735
736         StackInfo heatStack = null;
737         long subStartTime1 = System.currentTimeMillis ();
738         try {
739             heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
740             LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
741         } catch (MsoException me) {
742             String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
743             LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
744             LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
745             // Failed to query the Stack due to an openstack exception.
746             // Convert to a generic VnfException
747             me.addContext ("CreateVFModule");
748             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
749             throw new VnfException (me);
750         }
751         // New with 1607 - more precise handling/messaging if the stack already exists
752         if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
753                 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
754                 HeatStatus status = heatStack.getStatus();
755                 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
756                         // fail - it's in progress - return meaningful error
757                 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.";
758                 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
759                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
760                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
761                 }
762                 if (status == HeatStatus.FAILED) {
763                         // fail - it exists and is in a FAILED state
764                 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
765                 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
766                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
767                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
768                 }
769                 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
770                         // fail - it exists and is in a FAILED state
771                 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
772                 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");
773                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
774                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
775                 }
776                 if (status == HeatStatus.CREATED) {
777                         // fail - it exists
778                         if (failIfExists != null && failIfExists) {
779                                 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
780                                 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
781                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
782                                 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
783                         } else {
784                                 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
785                                 // Populate the outputs from the existing stack.
786                                 vnfId.value = heatStack.getCanonicalName ();
787                                 outputs.value = copyStringOutputs (heatStack.getOutputs ());
788                                 rollback.value = vfRollback; // Default rollback - no updates performed
789                         }
790                 }
791             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
792             return;
793
794         }
795
796         // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
797         StackInfo nestedHeatStack = null;
798         long subStartTime2 = System.currentTimeMillis ();
799         Map<String, Object> nestedVolumeOutputs = null;
800         if (nestedStackId != null) {
801                 try {
802                         LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
803                         nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
804                 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
805                 } catch (MsoException me) {
806                     // Failed to query the Stack due to an openstack exception.
807                     // Convert to a generic VnfException
808                     me.addContext ("CreateVFModule");
809                     String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
810                 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
811                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
812                         LOGGER.debug("ERROR trying to query nested stack= " + error);
813                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
814                     throw new VnfException (me);
815                 }
816                 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
817                     String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
818                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
819                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
820                     LOGGER.debug(error);
821                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
822                 } else {
823                         LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
824                         //this.sendMapToDebug(inputs);
825                         nestedVolumeOutputs = nestedHeatStack.getOutputs();
826                         this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
827                         //TODO
828                         //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);      
829                         //this.sendMapToDebug(inputs);
830                 }
831         }
832
833         // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
834         StackInfo nestedBaseHeatStack = null;
835         long subStartTime3 = System.currentTimeMillis ();
836         Map<String, Object> baseStackOutputs = null;
837         if (nestedBaseStackId != null) {
838                 try {
839                         LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
840                         nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
841                 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
842                 } catch (MsoException me) {
843                     // Failed to query the Stack due to an openstack exception.
844                     // Convert to a generic VnfException
845                     me.addContext ("CreateVFModule");
846                     String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
847                 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
848                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
849                         LOGGER.debug("ERROR trying to query nested base stack= " + error);
850                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
851                     throw new VnfException (me);
852                 }
853                 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
854                     String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
855                     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");
856                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
857                     LOGGER.debug(error);
858                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
859                 } else {
860                         LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
861                         //this.sendMapToDebug(inputs);
862                         baseStackOutputs = nestedBaseHeatStack.getOutputs();
863                         this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
864                         //TODO
865                         //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);      
866                         //this.sendMapToDebug(inputs);
867                 }
868         }
869
870         // Ready to deploy the new VNF
871
872         CatalogDatabase db = CatalogDatabase.getInstance();
873
874         try {
875             // Retrieve the VF
876                 VfModule vf = null;
877                 VnfResource vnfResource = null;
878                 VfModuleCustomization vfmc = null;
879                 LOGGER.debug("version: " + vfVersion);
880             if (useMCUuid) {
881                         // 1707 - db refactoring
882                         vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
883                         vf = vfmc != null ? vfmc.getVfModule() : null;
884                 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
885                         //vf = db.getVfModuleByModelCustomizationUuid(mcu);
886                 if (vf == null) {
887                                 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
888                                 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
889                     LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
890                             "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
891                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
892                     throw new VnfException(error, MsoExceptionCategory.USERDATA);
893                 } else {
894                                 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
895                 }
896                 if (vf.isBase()) {
897                     isBaseRequest = true;
898                     LOGGER.debug("This is a BASE VF request!");
899                 } else {
900                     LOGGER.debug("This is *not* a BASE VF request!");
901                     if (!isVolumeRequest && nestedBaseStackId == null) {
902                         LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
903                     }
904                 }
905                 }
906                 /*
907                 else if (!oldWay) {
908                                 // Need to handle old and new schema methods - for a time. Try the new way first.
909                                 if (vfVersion != null && !vfVersion.isEmpty()) {
910                                         vf = db.getVfModuleType(vfModuleType, vfVersion);
911                                         if (vf == null) {
912                                                 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME");
913                                                 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
914                                                 if (vf == null) {
915                                                         LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
916                                                 }
917                                         }
918                                 } else {
919                                         vf = db.getVfModuleType(vfModuleType);
920                                         if (vf == null) {
921                                                 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
922                                                 vf = db.getVfModuleModelName(vfModuleType);
923                                                 if (vf == null) {
924                                                         LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
925                                                 }
926                                         }
927                                 }
928                                 if (vf == null) {
929                                         String error = "Create VF Module: Unable to determine specific VF Module Type: "
930                                                         + vfModuleType;
931                                         if (vfVersion != null && !vfVersion.isEmpty()) {
932                                                 error += " with version = " + vfVersion;
933                                         }
934                                         LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
935                                                         "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type");
936                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
937                                         throw new VnfException(error, MsoExceptionCategory.USERDATA);
938                                 }
939                                 LOGGER.debug("Got VF module definition from Catalog: "
940                                                 + vf.toString());
941
942                                 if (vf.isBase()) {
943                                         isBaseRequest = true;
944                                         LOGGER.debug("This is a BASE VF request!");
945                                 } else {
946                                         LOGGER.debug("This is *not* a BASE VF request!");
947                                         if (!isVolumeRequest && nestedBaseStackId == null) {
948                                                 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
949                                         }
950                                 }
951                         } */ 
952                 else { // This is to support gamma only - get info from vnf_resource table
953                                 if (vfVersion != null && !vfVersion.isEmpty()) {
954                                         vnfResource = db.getVnfResource(vnfType, vnfVersion);
955                                 } else {
956                                         vnfResource = db.getVnfResource(vnfType);
957                                 }
958                                 if (vnfResource == null) {
959                                         String error = "Create VNF: Unknown VNF Type: " + vnfType;
960                                         LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
961                                                         vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
962                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
963                                         throw new VnfException(error, MsoExceptionCategory.USERDATA);
964                                 }
965                                 LOGGER.debug("Got VNF module definition from Catalog: "
966                                                 + vnfResource.toString());
967                         }
968                         // By here - we have either a vf or vnfResource
969
970             //1607 - Add version check
971             // First - see if it's in the VnfResource record
972             // if we have a vf Module - then we have to query to get the VnfResource record.
973             if (!oldWay) {
974                 if (vf.getVnfResourceModelUUId() != null) { 
975                         String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
976                         //vnfResource = db.getVnfResourceById(vnfResourceId);
977                         vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
978                         if (vnfResource == null) {
979                                 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
980                         }
981                 }
982             }
983             String minVersionVnf = null;
984             String maxVersionVnf = null;
985             if (vnfResource != null) {
986                 try {
987                         minVersionVnf = vnfResource.getAicVersionMin();
988                         maxVersionVnf = vnfResource.getAicVersionMax();
989                 } catch (Exception e) {
990                         LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
991                         minVersionVnf = null;
992                         maxVersionVnf = null;
993                 }
994                 if (minVersionVnf != null && minVersionVnf.equals("")) {
995                         minVersionVnf = null;
996                 }
997                 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
998                         maxVersionVnf = null;
999                 }
1000             }
1001                         if (minVersionVnf != null && maxVersionVnf != null) {
1002                                 MavenLikeVersioning aicV = new MavenLikeVersioning();
1003                                 CloudSite cloudSite = null;
1004                                 String aicVersion = "";
1005                                 if (this.cloudConfig == null) {
1006                                         this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1007                                 }
1008                                 // double check
1009                                 if (this.cloudConfig != null) {
1010                                         cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1011                                         if (cloudSite != null) {
1012                                                 aicV.setVersion(cloudSite.getAic_version());
1013                                                 // Add code to handle unexpected values in here
1014                                                 boolean moreThanMin = true;
1015                                                 boolean equalToMin = true;
1016                                                 boolean moreThanMax = true;
1017                                                 boolean equalToMax = true;
1018                                                 boolean doNotTest = false;
1019                                                 try {
1020                                                         moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1021                                                         equalToMin = aicV.isTheSameVersion(minVersionVnf);
1022                                                         moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1023                                                         equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1024                                                 } catch (Exception e) {
1025                                                         LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e);
1026                                                         doNotTest = true;
1027                                                 }                                               
1028                                                 if (!doNotTest) {
1029                                                         if ((moreThanMin || equalToMin) // aic >= min
1030                                                                         && (equalToMax || !(moreThanMax))) { //aic <= max
1031                                                                 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1032                                                         } else {
1033                                                                 // ERROR
1034                                                                 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();
1035                                                                 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1036                                                                 LOGGER.debug(error);
1037                                                                 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1038                                                         }
1039                                                 } else {
1040                                                         LOGGER.debug("bypassing testing AIC version...");
1041                                                 }
1042                                         } // let this error out downstream to avoid introducing uncertainty at this stage
1043                                 } else {
1044                                         LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1045                                 }
1046                         } else {
1047                                 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1048                         }
1049                         // End Version check 1607
1050
1051             // with VF_MODULE - we have both the non-vol and vol template/envs in that object
1052             // with VNF_RESOURCE - we use the old methods.
1053             //Integer heatTemplateId = null;
1054             //Integer heatEnvtId = null;
1055             
1056             String heatTemplateArtifactUuid = null;
1057             String heatEnvironmentArtifactUuid = null;
1058
1059                         if (!oldWay) {
1060                                 if (isVolumeRequest) {
1061                                         heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1062                                         heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1063                                 } else {
1064                                         heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1065                                         heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1066                                 }
1067                         } else {
1068                                 if (isVolumeRequest) {
1069                                         LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
1070                                         /*
1071                                         VnfComponent vnfComponent = null;
1072                                         vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME");
1073                         if (vnfComponent == null) {
1074                                 String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME";
1075                                 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry");
1076                         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1077                                 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1078                         } else {
1079                                 heatTemplateId = vnfComponent.getHeatTemplateId();
1080                                 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1081                         }
1082                         */
1083                                 } else {
1084                                         heatTemplateArtifactUuid = vnfResource.getTemplateId();
1085                                         heatEnvironmentArtifactUuid = null;
1086                                 }
1087                         }
1088                         // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1089                         HeatTemplate heatTemplate = null;
1090                         if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) {
1091                                 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1092                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1093                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1094                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1095                                                 MsoAlarmLogger.CRITICAL, error);
1096                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1097                         } else {
1098                                 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1099                         }
1100                         if (heatTemplate == null) {
1101                                 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1102                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1103                                                 "Heat Template ID",
1104                                                 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1105                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1106                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1107                                                 MsoAlarmLogger.CRITICAL, error);
1108                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1109                         }
1110                         LOGGER.debug("Got HEAT Template from DB");
1111
1112             HeatEnvironment heatEnvironment = null;
1113             String heatEnvironmentString = null;
1114
1115             if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals("")) {
1116                 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1117                 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1118                 if (heatEnvironment == null) {
1119                     String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1120                                    + ", Environment ID="
1121                                    + heatEnvironmentArtifactUuid;
1122                     LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1123                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1124                     // Alarm on this error, configuration must be fixed
1125                     alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1126
1127                     throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1128                 } else {
1129                     LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1130                     heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1131                     LOGGER.debug ("after parsing: " + heatEnvironmentString);
1132                 }
1133             } else {
1134                 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
1135             }
1136
1137             // 1510 - Add the files: for nested templates *if* there are any
1138             LOGGER.debug ("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1139                           + heatTemplate.getArtifactUuid());
1140             Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid());
1141             Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1142             if (nestedTemplates != null) {
1143                 // for debugging print them out
1144                 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1145                 for (String providerResourceFile : nestedTemplates.keySet ()) {
1146                     String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1147                     String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1148                     LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1149                     nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1150                 }
1151             } else {
1152                 LOGGER.debug ("No nested templates found - nothing to do here");
1153                 nestedTemplatesChecked = null; // just to make sure
1154             }
1155
1156             // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1157             // *if* there are any
1158             Map<String, HeatFiles> heatFiles = null;
1159                         Map<String, Object> heatFilesObjects = new HashMap<String, Object>();
1160
1161             // Add ability to turn on adding get_files with volume requests (by property).
1162             boolean addGetFilesOnVolumeReq = false;
1163             try {
1164                 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1165                 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1166                         addGetFilesOnVolumeReq = true;
1167                         LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1168                 }
1169             } catch (Exception e) {
1170                 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1171             }
1172
1173                         if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1174                                 if (oldWay) {
1175                                         LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1176                                         //heatFiles = db.getHeatFiles(vnfResource.getId());
1177                                 } else {
1178                                         // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1179                                         LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1180                                                         + vf.getModelUUID());
1181                                         heatFiles = db
1182                                                         .getHeatFilesForVfModule(vf.getModelUUID());
1183                                 }
1184                                 if (heatFiles != null) {
1185                                         // add these to stack - to be done in createStack
1186                                         // here, we will map them to Map<String, Object> from
1187                                         // Map<String, HeatFiles>
1188                                         // this will match the nested templates format
1189                                         LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1190
1191                                         for (String heatFileName : heatFiles.keySet()) {
1192                                                 if (heatFileName.startsWith("_ERROR|")) {
1193                                                         // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1194                                                         String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1195                                                         String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1196                                                         LOGGER.debug(error);
1197                                                         LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1198                             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1199                                                         // Alarm on this error, configuration must be fixed
1200                                                         alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1201                                                         throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1202                                                 }
1203                                                 String heatFileBody = heatFiles.get(heatFileName)
1204                                                                 .getFileBody();
1205                                                 String heatFileNameChecked = heatFileName;
1206                                                 LOGGER.debug(heatFileNameChecked + " -> "
1207                                                                 + heatFileBody);
1208                                                 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1209                                         }
1210                                 } else {
1211                                         LOGGER.debug("No heat files found -nothing to do here");
1212                                         heatFilesObjects = null;
1213                                 }
1214                         } else {
1215                                         LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1216                         }
1217
1218             // Check that required parameters have been supplied
1219             String missingParams = null;
1220             List <String> paramList = new ArrayList <String> ();
1221
1222             // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1223             // supplied an alias. Only check if we don't find it initially.
1224             // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1225             // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1226             // shouldn't
1227             boolean haveEnvironmentParameters = false;
1228             boolean checkRequiredParameters = true;
1229             try {
1230                 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1231                                                      .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1232                 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1233                     checkRequiredParameters = false;
1234                     LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1235                                   + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1236                 }
1237             } catch (Exception e) {
1238                 // No problem - default is true
1239                 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1240             }
1241             // 1604 - Add enhanced environment & parameter checking
1242             // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1243             // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1244             // Note this also removes any comments
1245             MsoHeatEnvironmentEntry mhee = null;
1246             if (heatEnvironmentString != null && heatEnvironmentString.contains ("parameters:")) {
1247                 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1248                 LOGGER.debug("Enhanced environment checking enabled - 1604");
1249                 haveEnvironmentParameters = true;
1250                 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1251                 //LOGGER.debug("About to create MHEE with " + sb);
1252                 mhee = new MsoHeatEnvironmentEntry(sb);
1253                 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1254                 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1255                         sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1256                 }
1257                 if (!mhee.isValid()) {
1258                         sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1259                 } else {
1260                         sb2.append("\nEnvironment:");
1261                         sb2.append(mhee.toFullString());
1262                 }
1263                 LOGGER.debug(sb2.toString());
1264             } else {
1265                 LOGGER.debug("NO ENVIRONMENT for this entry");
1266             }
1267             // New with 1707 - all variables converted to their native object types
1268             HashMap<String, Object> goldenInputs = null;
1269             
1270             LOGGER.debug("Now handle the inputs....first convert");
1271             ArrayList<String> parameterNames = new ArrayList<String>();
1272             HashMap<String, String> aliasToParam = new HashMap<String, String>();
1273             StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1274             int cntr = 0;
1275             try { 
1276                 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1277                         sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1278                         parameterNames.add(htp.getParamName());
1279                         if (htp.getParamAlias() != null && !htp.getParamAlias().equals("")) {
1280                                 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1281                                 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1282                         }
1283                         sb.append("\n");
1284                 }
1285                 LOGGER.debug(sb.toString());
1286             } catch (Exception e) {
1287                 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e);
1288             }
1289             // Step 1 - convert what we got as inputs (Map<String, String>) to a 
1290             // Map<String, Object> - where the object matches the param type identified in the template
1291             // This will also not copy over params that aren't identified in the template
1292             goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1293             // Step 2 - now simply add the outputs as we received them - no need to convert to string
1294             LOGGER.debug("Now add in the base stack outputs if applicable");
1295             heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1296             // Step 3 - add the volume inputs if any
1297             LOGGER.debug("Now add in the volume stack outputs if applicable");
1298             heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1299             this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1300             
1301             for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1302                 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1303                               + "', isRequired="
1304                               + parm.isRequired ()
1305                               + ", alias="
1306                               + parm.getParamAlias ());
1307
1308                 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1309                         // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1310                         LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment");
1311                     if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1312                         LOGGER.debug ("Required parameter " + parm.getParamName ()
1313                                       + " appears to be in environment - do not count as missing");
1314                     } else {
1315                         LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1316                         if (missingParams == null) {
1317                             missingParams = parm.getParamName ();
1318                         } else {
1319                             missingParams += "," + parm.getParamName ();
1320                         }
1321                     }
1322                 }
1323                 paramList.add (parm.getParamName ());
1324             }
1325             if (missingParams != null) {
1326                 if (checkRequiredParameters) {
1327                         // Problem - missing one or more required parameters
1328                         String error = "Create VFModule: Missing Required inputs: " + missingParams;
1329                         LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1330                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1331                         throw new VnfException (error, MsoExceptionCategory.USERDATA);
1332                 } else {
1333                         LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1334                 }
1335             } else {
1336                 LOGGER.debug ("No missing parameters found - ok to proceed");
1337             }
1338             // We can now remove the recreating of the ENV with only legit params - that check is done for us, 
1339             // and it causes problems with json that has arrays
1340             String newEnvironmentString = null;
1341             if (mhee != null) {
1342                 newEnvironmentString = mhee.getRawEntry().toString();
1343             }
1344             
1345             // "Fix" the template if it has CR/LF (getting this from Oracle)
1346             String template = heatTemplate.getHeatTemplate ();
1347             template = template.replaceAll ("\r\n", "\n");
1348
1349             // Have the tenant. Now deploy the stack itself
1350             // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1351             // because we already checked for those.
1352             long createStackStarttime = System.currentTimeMillis ();
1353             try {
1354                 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1355                 // heatTemplate.getTimeoutMinutes());
1356                 if (backout == null) {
1357                         backout = true;
1358                 }
1359                 if (heat != null) {
1360                         LOGGER.debug("heat is not null!!");
1361                 }
1362                         heatStack = heat.createStack (cloudSiteId,
1363                                               tenantId,
1364                                               vfModuleName,
1365                                               template,
1366                         goldenInputs,
1367                                               true,
1368                                               heatTemplate.getTimeoutMinutes (),
1369                                               newEnvironmentString,
1370                                               nestedTemplatesChecked,
1371                                               heatFilesObjects,
1372                                               backout.booleanValue());
1373                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1374             } catch (MsoException me) {
1375                 me.addContext ("CreateVFModule");
1376                 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1377                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1378                 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1379                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1380                 throw new VnfException (me);
1381             } catch (NullPointerException npe) {
1382                 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1383                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1384                 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1385                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1386                 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1387                 //npe.addContext ("CreateVNF");
1388                 throw new VnfException ("NullPointerException during heat.createStack");
1389             } catch (Exception e) {
1390                 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1391                 LOGGER.debug("unhandled exception at heat.createStack",e);
1392                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1393                 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1394             }
1395         } catch (Exception e) {
1396                 LOGGER.debug("unhandled exception in create VF",e);
1397                 throw new VnfException("Exception during create VF " + e.getMessage());
1398
1399         } finally {
1400             // Make sure DB session is closed
1401             db.close ();
1402         }
1403
1404         // Reach this point if createStack is successful.
1405         // Populate remaining rollback info and response parameters.
1406         vfRollback.setVnfId (heatStack.getCanonicalName ());
1407         vfRollback.setVnfCreated (true);
1408
1409         vnfId.value = heatStack.getCanonicalName ();
1410         outputs.value = copyStringOutputs (heatStack.getOutputs ());
1411         rollback.value = vfRollback;
1412
1413         LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1414         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1415         return;
1416     }
1417
1418     public void deleteVfModule (String cloudSiteId,
1419                            String tenantId,
1420                            String vnfName,
1421                            MsoRequest msoRequest,
1422                            Holder <Map <String, String>> outputs) throws VnfException {
1423         MsoLogger.setLogContext (msoRequest);
1424         MsoLogger.setServiceName ("DeleteVf");
1425         LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1426         // Will capture execution time for metrics
1427         long startTime = System.currentTimeMillis ();
1428
1429         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1430
1431         // 1702 capture the output parameters on a delete
1432         // so we'll need to query first
1433         Map<String, Object> stackOutputs = null;
1434         try {
1435             stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1436         } catch (MsoException me) {
1437             // Failed to query the Stack due to an openstack exception.
1438             // Convert to a generic VnfException
1439             me.addContext ("DeleteVFModule");
1440             String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1441             LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1442             LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1443             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1444             throw new VnfException (me);
1445         }
1446         // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1447         outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1448
1449         // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1450         // The possible outcomes of deleteStack are a StackInfo object with status
1451         // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1452         // could be thrown.
1453         long subStartTime = System.currentTimeMillis ();
1454         try {
1455             heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1456             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1457         } catch (MsoException me) {
1458             me.addContext ("DeleteVNF");
1459             // Failed to query the Stack due to an openstack exception.
1460             // Convert to a generic VnfException
1461             String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1462             LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1463             LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1464             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1465             throw new VnfException (me);
1466         }
1467
1468         // On success, nothing is returned.
1469         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1470         return;
1471     }
1472
1473     @Override
1474     public void updateVfModule (String cloudSiteId,
1475                            String tenantId,
1476                            String vnfType,
1477                            String vnfVersion,
1478                            String vnfName,
1479                            String requestType,
1480                            String volumeGroupHeatStackId,
1481                            String baseVfHeatStackId,
1482                            String vfModuleStackId,
1483                            String modelCustomizationUuid,
1484                            Map <String, String> inputs,
1485                            MsoRequest msoRequest,
1486                            Holder <Map <String, String>> outputs,
1487                            Holder <VnfRollback> rollback) throws VnfException {
1488         String vfModuleName = vnfName;
1489         String vfModuleType = vnfType;
1490         String vfVersion = vnfVersion;
1491         String methodName = "updateVfModule";
1492         MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1493         String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1494         MsoLogger.setServiceName (serviceName);
1495         
1496         StringBuilder sbInit = new StringBuilder();
1497         sbInit.append("updateVfModule: \n");
1498         sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1499         sbInit.append("tenantId=" + tenantId + "\n");
1500         sbInit.append("vnfType=" + vnfType + "\n");
1501         sbInit.append("vnfVersion=" + vnfVersion + "\n");
1502         sbInit.append("vnfName=" + vnfName + "\n");
1503         sbInit.append("requestType=" + requestType + "\n");
1504         sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1505         sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1506         sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1507         sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1508         LOGGER.debug(sbInit.toString());
1509
1510         String mcu = modelCustomizationUuid;
1511         boolean useMCUuid = false;
1512         if (mcu != null && !mcu.isEmpty()) {
1513             if (mcu.equalsIgnoreCase("null")) {
1514                 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1515                 useMCUuid = false;
1516                 mcu = "";
1517             } else {
1518                 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1519                 useMCUuid = true;
1520             }
1521         }
1522
1523         String requestTypeString = "";
1524         if (requestType != null && !requestType.equals("")) {
1525                 requestTypeString = requestType;
1526         }
1527         String nestedStackId = null;
1528         if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1529                 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1530                         nestedStackId = volumeGroupHeatStackId;
1531                 }
1532         }
1533         String nestedBaseStackId = null;
1534         if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1535                 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1536                         nestedBaseStackId = baseVfHeatStackId;
1537                 }
1538         }
1539
1540         if (inputs == null) {
1541                 // Create an empty set of inputs
1542                 inputs = new HashMap<String,String>();
1543                 LOGGER.debug("inputs == null - setting to empty");
1544         } else {
1545                 this.sendMapToDebug(inputs);
1546         }
1547         boolean isBaseRequest = false;
1548         boolean isVolumeRequest = false;
1549         if (requestTypeString.startsWith("VOLUME")) {
1550                 isVolumeRequest = true;
1551         }
1552         if (vfModuleName == null || vfModuleName.trim().equals("")) {
1553                 if (vfModuleStackId != null) {
1554                         vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1555                 }
1556         }
1557
1558         LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1559         LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1560
1561         // Will capture execution time for metrics
1562         long startTime = System.currentTimeMillis ();
1563
1564         // Build a default rollback object (no actions performed)
1565         VnfRollback vfRollback = new VnfRollback ();
1566         vfRollback.setCloudSiteId (cloudSiteId);
1567         vfRollback.setTenantId (tenantId);
1568         vfRollback.setMsoRequest (msoRequest);
1569         vfRollback.setRequestType(requestTypeString);
1570         vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1571         vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1572         vfRollback.setIsBase(isBaseRequest);
1573         vfRollback.setVfModuleStackId(vfModuleStackId);
1574         vfRollback.setModelCustomizationUuid(mcu);
1575
1576         // First, look up to see if the VNF already exists.
1577         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1578         MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1579
1580         StackInfo heatStack = null;
1581         long queryStackStarttime = System.currentTimeMillis ();
1582         LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1583         try {
1584             heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1585             LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1586         } catch (MsoException me) {
1587             // Failed to query the Stack due to an openstack exception.
1588             // Convert to a generic VnfException
1589             me.addContext ("UpdateVFModule");
1590             String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1591             LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1592             LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1593             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1594             throw new VnfException (me);
1595         }
1596
1597         //TODO - do we need to check for the other status possibilities?
1598         if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1599             // Not Found
1600             String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1601             LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1602             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1603             throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1604         } else {
1605             LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1606             // Populate the outputs from the existing stack.
1607             outputs.value = copyStringOutputs (heatStack.getOutputs ());
1608             rollback.value = vfRollback; // Default rollback - no updates performed
1609         }
1610
1611         // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1612         StackInfo nestedHeatStack = null;
1613         long queryStackStarttime2 = System.currentTimeMillis ();
1614         Map<String, Object> nestedVolumeOutputs = null;
1615         if (nestedStackId != null) {
1616                 try {
1617                         LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1618                         nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1619                 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1620                 } catch (MsoException me) {
1621                     // Failed to query the Stack due to an openstack exception.
1622                     // Convert to a generic VnfException
1623                     me.addContext ("UpdateVFModule");
1624                     String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1625                 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1626                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1627                         LOGGER.debug("ERROR trying to query nested stack= " + error);
1628                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1629                     throw new VnfException (me);
1630                 }
1631                 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1632                         MsoLogger.setServiceName (serviceName);
1633                     String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
1634                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1635                     LOGGER.debug(error);
1636                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1637                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
1638                 } else {
1639                         LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1640                         nestedVolumeOutputs = nestedHeatStack.getOutputs();
1641                         //this.sendMapToDebug(inputs);
1642                         this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1643                         //TODO
1644                         heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1645                         //this.sendMapToDebug(inputs);
1646                 }
1647         }
1648         // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1649         StackInfo nestedBaseHeatStack = null;
1650         Map<String, Object> baseStackOutputs = null;
1651         if (nestedBaseStackId != null) {
1652             long queryStackStarttime3 = System.currentTimeMillis ();
1653                 try {
1654                         LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1655                         nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1656                 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1657                 } catch (MsoException me) {
1658                     // Failed to query the Stack due to an openstack exception.
1659                     // Convert to a generic VnfException
1660                     me.addContext ("UpdateVfModule");
1661                     String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1662                 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1663                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1664                         LOGGER.debug("ERROR trying to query nested base stack= " + error);
1665                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1666                     throw new VnfException (me);
1667                 }
1668                 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1669                         MsoLogger.setServiceName (serviceName);
1670                     String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"  ;
1671                     LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1672                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1673                     LOGGER.debug(error);
1674                     throw new VnfException (error, MsoExceptionCategory.USERDATA);
1675                 } else {
1676                         LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1677                         baseStackOutputs = nestedBaseHeatStack.getOutputs();
1678                         //this.sendMapToDebug(inputs);
1679                         this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1680                         //TODO
1681                         heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1682                         //this.sendMapToDebug(inputs);
1683                 }
1684         }
1685
1686         // Ready to deploy the new VNF
1687
1688         // Get a handle to the Catalog Database
1689         CatalogDatabase db = CatalogDatabase.getInstance();
1690
1691         // Make sure DB session is closed
1692         try {
1693             // Retrieve the VF definition
1694             VnfResource vnfResource = null;
1695                 VfModule vf = null;
1696                 VfModuleCustomization vfmc = null;
1697             if (useMCUuid) {
1698                         //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1699                         vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1700                         vf = vfmc != null ? vfmc.getVfModule() : null;
1701                 if (vf == null) {
1702                     LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1703                 }
1704                 } else {
1705                         LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1706             }
1707                 if (vf == null) {
1708                 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1709                 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1710                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1711                 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1712             }
1713             LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
1714             if (vf.isBase()) {
1715                 isBaseRequest = true;
1716                 LOGGER.debug("This a BASE update request");
1717             } else {
1718                 LOGGER.debug("This is *not* a BASE VF update request");
1719                 if (!isVolumeRequest && nestedBaseStackId == null) {
1720                         LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1721                 }
1722             }
1723             
1724             //1607 - Add version check
1725             // First - see if it's in the VnfResource record
1726             // if we have a vf Module - then we have to query to get the VnfResource record.
1727             if (vf.getVnfResourceModelUUId() != null) { 
1728                 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1729                 //vnfResource = db.getVnfResourceById(vnfResourceId);
1730                 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1731                 if (vnfResource == null) {
1732                         LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1733                 }
1734             }
1735             String minVersionVnf = null;
1736             String maxVersionVnf = null;
1737             if (vnfResource != null) {
1738                 try {
1739                         minVersionVnf = vnfResource.getAicVersionMin();
1740                         maxVersionVnf = vnfResource.getAicVersionMax();
1741                 } catch (Exception e) {
1742                         LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1743                         minVersionVnf = null;
1744                         maxVersionVnf = null;
1745                         }
1746                 if (minVersionVnf != null && minVersionVnf.equals("")) {
1747                         minVersionVnf = null;
1748                 }
1749                 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1750                         maxVersionVnf = null;
1751                         }
1752                 }
1753                         if (minVersionVnf != null && maxVersionVnf != null) {
1754                                 MavenLikeVersioning aicV = new MavenLikeVersioning();
1755                                 CloudSite cloudSite = null;
1756                                 //String aicVersion = "";
1757                                 if (this.cloudConfig == null) {
1758                                         this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1759             }
1760                                 // double check
1761                                 if (this.cloudConfig != null) {
1762                                         cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1763                                         if (cloudSite != null) {
1764                                                 aicV.setVersion(cloudSite.getAic_version());
1765                                                 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1766                                                                 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV.isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1767                                                         LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1768                                                 } else {
1769                                                         // ERROR
1770                                                         String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1771                                                         LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1772                                                         LOGGER.debug(error);
1773                                                         throw new VnfException(error, MsoExceptionCategory.USERDATA);
1774                     }
1775                                         } // let this error out downstream to avoid introducing uncertainty at this stage
1776                 } else {
1777                                         LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1778                 }
1779
1780                         } else {
1781                                 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1782             }
1783                         // End Version check 1607
1784             
1785                         String heatTemplateArtifactUuid = null;
1786                         String heatEnvironmentArtifactUuid = null;
1787
1788             HeatTemplate heatTemplate = null;
1789                         if (isVolumeRequest) {
1790                                 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1791                                 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1792                         } else {
1793                                 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1794                                 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1795                         }
1796                         if (heatTemplateArtifactUuid == null) {
1797                                 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1798                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1799                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1800                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1801                                                 MsoAlarmLogger.CRITICAL, error);
1802                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1803                         } else {
1804                                 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1805                         }
1806
1807                         if (heatTemplate == null) {
1808                                 String error = "Update VNF: undefined Heat Template. VF="
1809                                                 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1810                                 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1811                                                 "Heat Template ID",
1812                                                 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1813                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1814                                 // Alarm on this error, configuration must be fixed
1815                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1816                                                 MsoAlarmLogger.CRITICAL, error);
1817
1818                                 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1819                         }
1820
1821             LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
1822
1823             // Add check for any Environment variable
1824             HeatEnvironment heatEnvironment = null;
1825             String heatEnvironmentString = null;
1826
1827             if (heatEnvironmentArtifactUuid != null) {
1828                 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1829                 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1830                 if (heatEnvironment == null) {
1831
1832                     String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1833                                    + ", Environment ID="
1834                                    + heatEnvironmentArtifactUuid;
1835                     LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1836                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1837                     // Alarm on this error, configuration must be fixed
1838                     alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1839
1840                     throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1841                 } else {
1842                     LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1843                     heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1844                     LOGGER.debug ("After parsing: " + heatEnvironmentString);
1845                 }
1846             } else {
1847                 LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType);
1848             }
1849
1850
1851             LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1852                           + heatTemplate.getArtifactUuid ());
1853             Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid ());
1854             Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1855             if (nestedTemplates != null) {
1856                 // for debugging print them out
1857                 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1858                 for (String providerResourceFile : nestedTemplates.keySet ()) {
1859                     String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1860                     String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1861                     nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1862                     LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1863                 }
1864             } else {
1865                 LOGGER.debug ("No nested templates found - nothing to do here");
1866                 nestedTemplatesChecked = null;
1867             }
1868
1869             // Also add the files: for any get_files associated with this VfModule
1870             // *if* there are any
1871             LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1872                           + vf.getModelUUID());
1873
1874             Map <String, HeatFiles> heatFiles = null;
1875 //            Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1876             Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
1877
1878             // Add ability to turn on adding get_files with volume requests (by property).
1879             boolean addGetFilesOnVolumeReq = false;
1880             try {
1881                 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1882                 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1883                         addGetFilesOnVolumeReq = true;
1884                         LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1885                 }
1886             } catch (Exception e) {
1887                 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1888             }
1889             if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1890                 LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1891                                                 + vf.getModelUUID());
1892
1893                 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1894                 if (heatFiles != null) {
1895                     // add these to stack - to be done in createStack
1896                     // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1897                     // this will match the nested templates format
1898                     LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
1899
1900                     for (String heatFileName : heatFiles.keySet ()) {
1901                                                 if (heatFileName.startsWith("_ERROR|")) {
1902                                                         // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1903                                                         String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1904                                                         String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1905                                                         LOGGER.debug(error);
1906                                                         LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1907                             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1908                                                         // Alarm on this error, configuration must be fixed
1909                                                         alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1910                                                         throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1911                                                 }
1912                         String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
1913                         LOGGER.debug (heatFileName + " -> " + heatFileBody);
1914                         heatFilesObjects.put (heatFileName, heatFileBody);
1915                     }
1916                 } else {
1917                     LOGGER.debug ("No heat files found -nothing to do here");
1918                     heatFilesObjects = null;
1919                 }
1920             }
1921
1922             // Check that required parameters have been supplied
1923             String missingParams = null;
1924             List <String> paramList = new ArrayList <String> ();
1925
1926             // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1927             // supplied an alias. Only check if we don't find it initially.
1928             // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1929             // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1930             // shouldn't
1931             boolean haveEnvironmentParameters = false;
1932             boolean checkRequiredParameters = true;
1933             try {
1934                 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1935                                                      .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1936                 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1937                     checkRequiredParameters = false;
1938                     LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1939                                   + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1940                 }
1941             } catch (Exception e) {
1942                 // No problem - default is true
1943                 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1944             }
1945             // 1604 - Add enhanced environment & parameter checking
1946             // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1947             // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1948             // Note this also removes any comments
1949             MsoHeatEnvironmentEntry mhee = null;
1950             if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) {
1951                 LOGGER.debug("Enhanced environment checking enabled - 1604");
1952                 haveEnvironmentParameters = true;
1953                 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1954                 //LOGGER.debug("About to create MHEE with " + sb);
1955                 mhee = new MsoHeatEnvironmentEntry(sb);
1956                 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1957                 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1958                         sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1959                 }
1960                 if (!mhee.isValid()) {
1961                         sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1962                 } else {
1963                         sb2.append("\nEnvironment:");
1964                         sb2.append(mhee.toFullString());
1965                 }
1966                 LOGGER.debug(sb2.toString());
1967             } else {
1968                 LOGGER.debug("NO ENVIRONMENT for this entry");
1969             }
1970
1971             // New for 1607 - support params of json type
1972             HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
1973             boolean hasJson = false;
1974
1975             for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1976                 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1977                               + "', isRequired="
1978                               + parm.isRequired ()
1979                               + ", alias="
1980                               + parm.getParamAlias ());
1981                 // handle json
1982                 String parameterType = parm.getParamType();
1983                 if (parameterType == null || parameterType.trim().equals("")) {
1984                         parameterType = "String";
1985                 }
1986                 JsonNode jsonNode = null;
1987                 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
1988                         if (inputs.containsKey(parm.getParamName()) ) {
1989                                 hasJson = true;
1990                                 String jsonString = null;
1991                                 try {
1992                                         jsonString = inputs.get(parm.getParamName());
1993                                         jsonNode = new ObjectMapper().readTree(jsonString);
1994                                 } catch (JsonParseException jpe) {
1995                                         //TODO - what to do here?
1996                                         //for now - send the error to debug, but just leave it as a String
1997                                         String errorMessage = jpe.getMessage();
1998                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
1999                                         hasJson = false;
2000                                         jsonNode = null;
2001                                 } catch (Exception e) {
2002                                         // or here?
2003                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2004                                         hasJson = false;
2005                                         jsonNode = null;
2006                                 }
2007                                 if (jsonNode != null) {
2008                                         jsonParams.put(parm.getParamName(), jsonNode);
2009                                 }
2010                         } else if (inputs.containsKey(parm.getParamAlias())) {
2011                                 hasJson = true;
2012                                 String jsonString = null;
2013                                 try {
2014                                         jsonString = inputs.get(parm.getParamAlias());
2015                                         jsonNode = new ObjectMapper().readTree(jsonString);
2016                                 } catch (JsonParseException jpe) {
2017                                         //TODO - what to do here?
2018                                         //for now - send the error to debug, but just leave it as a String
2019                                         String errorMessage = jpe.getMessage();
2020                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
2021                                         hasJson = false;
2022                                         jsonNode = null;
2023                                 } catch (Exception e) {
2024                                         // or here?
2025                                         LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2026                                         hasJson = false;
2027                                         jsonNode = null;
2028                                 }
2029                                 if (jsonNode != null) {
2030                                         // Notice here - we add it to the jsonParams hashMap with the actual name -
2031                                         // then manipulate the inputs so when we check for aliases below - it will not
2032                                         // get flagged.
2033                                         jsonParams.put(parm.getParamName(), jsonNode);
2034                                         inputs.remove(parm.getParamAlias());
2035                                         inputs.put(parm.getParamName(), jsonString);
2036                                 }
2037                         } //TODO add a check for the parameter in the env file
2038                 }
2039
2040                 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
2041                     if (inputs.containsKey (parm.getParamAlias ())) {
2042                         // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2043                         String realParamName = parm.getParamName ();
2044                         String alias = parm.getParamAlias ();
2045                         String value = inputs.get (alias);
2046                         LOGGER.debug ("*Found an Alias: paramName=" + realParamName
2047                                       + ",alias="
2048                                       + alias
2049                                       + ",value="
2050                                       + value);
2051                         inputs.remove (alias);
2052                         inputs.put (realParamName, value);
2053                         LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
2054                     }
2055                     // enhanced - check if it's in the Environment (note: that method
2056                     else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2057
2058                         LOGGER.debug ("Required parameter " + parm.getParamName ()
2059                                       + " appears to be in environment - do not count as missing");
2060                     }
2061                     else {
2062                         LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
2063                         if (missingParams == null) {
2064                             missingParams = parm.getParamName ();
2065                         } else {
2066                             missingParams += "," + parm.getParamName ();
2067                         }
2068                     }
2069                 }
2070                 paramList.add (parm.getParamName ());
2071             }
2072             if (missingParams != null) {
2073                 // Problem - missing one or more required parameters
2074                 if (checkRequiredParameters) {
2075                 String error = "Update VNF: Missing Required inputs: " + missingParams;
2076                 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2077                     LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
2078                 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2079                 } else {
2080                         LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
2081                 }
2082             } else {
2083                 LOGGER.debug ("No missing parameters found - ok to proceed");
2084             }
2085
2086             // Just submit the envt entry as received from the database
2087             String newEnvironmentString = null;
2088             if (mhee != null) {
2089                 newEnvironmentString = mhee.getRawEntry().toString();
2090             }
2091
2092             // Remove any extraneous parameters (don't throw an error)
2093             if (inputs != null) {
2094                 List <String> extraParams = new ArrayList <String> ();
2095                 extraParams.addAll (inputs.keySet ());
2096                 // This is not a valid parameter for this template
2097                 extraParams.removeAll (paramList);
2098                 if (!extraParams.isEmpty ()) {
2099                         LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
2100                     inputs.keySet ().removeAll (extraParams);
2101                 }
2102             }
2103             // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2104             Map<String, Object> inputsTwo = null;
2105             if (hasJson && jsonParams.size() > 0) {
2106                 inputsTwo = new HashMap<String, Object>();
2107                 for (String keyParamName : inputs.keySet()) {
2108                         if (jsonParams.containsKey(keyParamName)) {
2109                                 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2110                         } else {
2111                                 inputsTwo.put(keyParamName, inputs.get(keyParamName));
2112                         }
2113                 }
2114             }
2115
2116             // "Fix" the template if it has CR/LF (getting this from Oracle)
2117             String template = heatTemplate.getHeatTemplate ();
2118             template = template.replaceAll ("\r\n", "\n");
2119
2120             // Have the tenant. Now deploy the stack itself
2121             // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2122             // because we already checked for those.
2123             long updateStackStarttime = System.currentTimeMillis ();
2124             try {
2125                 if (!hasJson) {
2126                         heatStack = heatU.updateStack (cloudSiteId,
2127                                                tenantId,
2128                                                vfModuleName,
2129                                                template,
2130                                                copyStringInputs (inputs),
2131                                                true,
2132                                                heatTemplate.getTimeoutMinutes (),
2133                                                newEnvironmentString,
2134                                                //heatEnvironmentString,
2135                                                nestedTemplatesChecked,
2136                                                heatFilesObjects);
2137                         LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2138                 } else {
2139                         heatStack = heatU.updateStack (cloudSiteId,
2140                                                tenantId,
2141                                                vfModuleName,
2142                                                template,
2143                                                inputsTwo,
2144                                                true,
2145                                                heatTemplate.getTimeoutMinutes (),
2146                                                newEnvironmentString,
2147                                                //heatEnvironmentString,
2148                                                nestedTemplatesChecked,
2149                                                heatFilesObjects);
2150                         LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2151
2152                 }
2153             } catch (MsoException me) {
2154                 me.addContext ("UpdateVFModule");
2155                 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2156                 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2157                 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2158                 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2159                 throw new VnfException (me);
2160             }
2161         } finally {
2162             // Make sure DB session is closed
2163             db.close ();
2164         }
2165
2166         // Reach this point if updateStack is successful.
2167         // Populate remaining rollback info and response parameters.
2168         vfRollback.setVnfId (heatStack.getCanonicalName ());
2169         vfRollback.setVnfCreated (true);
2170
2171         outputs.value = copyStringOutputs (heatStack.getOutputs ());
2172         rollback.value = vfRollback;
2173         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2174         return;
2175     }
2176
2177     private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2178         // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2179         // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2180         if (vfModuleStackId == null)
2181                 return null;
2182         int index = vfModuleStackId.lastIndexOf('/');
2183         if (index <= 0)
2184                 return null;
2185         String vfModuleName = null;
2186         try {
2187                 vfModuleName = vfModuleStackId.substring(0, index);
2188         } catch (Exception e) {
2189                 LOGGER.debug("Exception", e);
2190                 vfModuleName = null;
2191         }
2192         return vfModuleName;
2193     }
2194
2195 }