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