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