2 * ============LICENSE_START=======================================================
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.so.adapters.vnf;
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;
32 import java.util.Optional;
33 import java.util.concurrent.TimeUnit;
35 import javax.jws.WebService;
36 import javax.xml.ws.Holder;
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.cloud.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 import org.onap.so.logger.MsoAlarmLogger;
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;
81 import com.fasterxml.jackson.core.JsonParseException;
82 import com.fasterxml.jackson.databind.JsonNode;
83 import com.fasterxml.jackson.databind.ObjectMapper;
85 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf")
88 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
91 private CloudConfig cloudConfig;
94 private Environment environment;
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 private static final MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
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";
107 private VFModuleCustomizationRepository vfModuleCustomRepo;
111 private VnfResourceRepository vnfResourceRepo;
114 private MsoHeatUtilsWithUpdate heatU;
116 private MsoHeatUtils heat;
118 private ValetClient vci;
120 * Health Check web method. Does nothing but return to show the adapter is deployed.
123 public void healthCheck () {
124 LOGGER.debug ("Health check call in VNF Adapter");
128 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
129 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
131 public MsoVnfAdapterImpl() {}
134 * This is the "Create VNF" web service implementation.
135 * It will create a new VNF of the requested type in the specified cloud
136 * and tenant. The tenant must exist before this service is called.
138 * If a VNF with the same name already exists, this can be considered a
139 * success or failure, depending on the value of the 'failIfExists' parameter.
141 * All VNF types will be defined in the MSO catalog. The caller must request
142 * one of these pre-defined types or an error will be returned. Within the
143 * catalog, each VNF type references (among other things) a Heat template
144 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
147 * Depending on the Heat template, a variable set of input parameters will
148 * be defined, some of which are required. The caller is responsible to
149 * pass the necessary input data for the VNF or an error will be thrown.
151 * The method returns the vnfId (the canonical name), a Map of VNF output
152 * attributes, and a VnfRollback object. This last object can be passed
153 * as-is to the rollbackVnf operation to undo everything that was created
154 * for the VNF. This is useful if a VNF is successfully created but the
155 * orchestrator fails on a subsequent operation.
157 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
158 * @param tenantId Openstack tenant identifier
159 * @param vnfType VNF type key, should match a VNF definition in catalog DB
160 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
161 * @param vnfName Name to be assigned to the new VNF
162 * @param inputs Map of key=value inputs for VNF stack creation
163 * @param failIfExists Flag whether already existing VNF should be considered
164 * a success or failure
165 * @param msoRequest Request tracking information for logs
166 * @param vnfId Holder for output VNF Openstack ID
167 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
168 * @param rollback Holder for returning VnfRollback object
171 public void createVnf (String cloudSiteId,
177 String volumeGroupHeatStackId,
178 Map <String, String> inputs,
179 Boolean failIfExists,
181 Boolean enableBridge,
182 MsoRequest msoRequest,
183 Holder <String> vnfId,
184 Holder <Map <String, String>> outputs,
185 Holder <VnfRollback> rollback) throws VnfException {
186 // Create a hook here to catch shortcut createVf requests:
187 if (requestType != null && requestType.startsWith("VFMOD")) {
188 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
189 String newRequestType = requestType.substring(5);
190 String vfVolGroupHeatStackId = "";
191 String vfBaseHeatStackId = "";
193 if (volumeGroupHeatStackId != null) {
194 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf('|'));
195 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf('|')+1);
197 } catch (Exception e) {
198 // might be ok - both are just blank
199 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
201 this.createVfModule(cloudSiteId,
207 vfVolGroupHeatStackId,
220 // createVf will know if the requestType starts with "X" that it's the "old" way
221 StringBuilder newRequestTypeSb = new StringBuilder("X");
222 String vfVolGroupHeatStackId = "";
223 String vfBaseHeatStackId = "";
224 if (requestType != null) {
225 newRequestTypeSb.append(requestType);
227 this.createVfModule(cloudSiteId,
232 newRequestTypeSb.toString(),
233 vfVolGroupHeatStackId,
245 // End createVf shortcut
249 public void updateVnf (String cloudSiteId,
255 String volumeGroupHeatStackId,
256 Map <String, String> inputs,
257 MsoRequest msoRequest,
258 Holder <Map <String, String>> outputs,
259 Holder <VnfRollback> rollback) throws VnfException {
260 // As of 1707 - this method should no longer be called
261 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
262 MsoLogger.setServiceName ("UpdateVnf");
263 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
267 * This is the "Query VNF" web service implementation.
268 * It will look up a VNF by name or ID in the specified cloud and tenant.
270 * The method returns an indicator that the VNF exists, its Openstack internal
271 * ID, its status, and the set of outputs (from when the stack was created).
273 * @param cloudSiteId CLLI code of the cloud site in which to query
274 * @param tenantId Openstack tenant identifier
275 * @param vnfName VNF Name or Openstack ID
276 * @param msoRequest Request tracking information for logs
277 * @param vnfExists Flag reporting the result of the query
278 * @param vnfId Holder for output VNF Openstack ID
279 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
282 public void queryVnf (String cloudSiteId,
285 MsoRequest msoRequest,
286 Holder <Boolean> vnfExists,
287 Holder <String> vnfId,
288 Holder <VnfStatus> status,
289 Holder <Map <String, String>> outputs) throws VnfException {
290 MsoLogger.setLogContext (msoRequest);
291 MsoLogger.setServiceName ("QueryVnf");
292 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
294 // Will capture execution time for metrics
295 long startTime = System.currentTimeMillis ();
297 StackInfo heatStack = null;
298 long subStartTime = System.currentTimeMillis ();
300 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
301 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
302 } catch (MsoException me) {
303 me.addContext ("QueryVNF");
304 // Failed to query the Stack due to an openstack exception.
305 // Convert to a generic VnfException
306 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
307 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
308 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
309 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
310 throw new VnfException (me);
313 // Populate the outputs based on the returned Stack information
315 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
317 vnfExists.value = Boolean.FALSE;
318 status.value = VnfStatus.NOTFOUND;
320 outputs.value = new HashMap<>(); // Return as an empty map
322 LOGGER.debug ("VNF " + vnfName + " not found");
324 vnfExists.value = Boolean.TRUE;
325 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
326 vnfId.value = heatStack.getCanonicalName ();
327 outputs.value = copyStringOutputs (heatStack.getOutputs ());
329 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
331 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
336 * This is the "Delete VNF" web service implementation.
337 * It will delete a VNF by name or ID in the specified cloud and tenant.
339 * The method has no outputs.
341 * @param cloudSiteId CLLI code of the cloud site in which to delete
342 * @param tenantId Openstack tenant identifier
343 * @param vnfName VNF Name or Openstack ID
344 * @param msoRequest Request tracking information for logs
347 public void deleteVnf (String cloudSiteId,
350 MsoRequest msoRequest) throws VnfException {
351 MsoLogger.setLogContext (msoRequest);
352 MsoLogger.setServiceName ("DeleteVnf");
353 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
354 // Will capture execution time for metrics
355 long startTime = System.currentTimeMillis ();
357 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
358 // The possible outcomes of deleteStack are a StackInfo object with status
359 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
361 long subStartTime = System.currentTimeMillis ();
363 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
364 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
365 } catch (MsoException me) {
366 me.addContext ("DeleteVNF");
367 // Failed to query the Stack due to an openstack exception.
368 // Convert to a generic VnfException
369 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
370 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
371 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
372 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
373 throw new VnfException (me);
376 // On success, nothing is returned.
377 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
382 * This web service endpoint will rollback a previous Create VNF operation.
383 * A rollback object is returned to the client in a successful creation
384 * response. The client can pass that object as-is back to the rollbackVnf
385 * operation to undo the creation.
388 public void rollbackVnf (VnfRollback rollback) throws VnfException {
389 long startTime = System.currentTimeMillis ();
390 MsoLogger.setServiceName ("RollbackVnf");
391 // rollback may be null (e.g. if stack already existed when Create was called)
392 if (rollback == null) {
393 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
394 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
398 // Get the elements of the VnfRollback object for easier access
399 String cloudSiteId = rollback.getCloudSiteId ();
400 String tenantId = rollback.getTenantId ();
401 String vnfId = rollback.getVnfId ();
403 MsoLogger.setLogContext (rollback.getMsoRequest());
405 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
407 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
408 // The possible outcomes of deleteStack are a StackInfo object with status
409 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
411 long subStartTime = System.currentTimeMillis ();
413 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
414 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
415 } catch (MsoException me) {
416 // Failed to rollback the Stack due to an openstack exception.
417 // Convert to a generic VnfException
418 me.addContext ("RollbackVNF");
419 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
420 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
421 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
422 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
423 throw new VnfException (me);
425 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
429 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
430 switch (stackStatus) {
432 return VnfStatus.ACTIVE;
434 return VnfStatus.ACTIVE;
436 return VnfStatus.FAILED;
438 return VnfStatus.UNKNOWN;
442 private Map <String, String> copyStringOutputs(Map <String, Object> stackOutputs) {
443 Map <String, String> stringOutputs = new HashMap <> ();
444 for (Map.Entry<String,Object> entry : stackOutputs.entrySet ()) {
445 String key = entry.getKey();
446 Object value = entry.getValue();
448 stringOutputs.put(key, value.toString());
449 } catch (Exception e) {
450 StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs");
451 if (value instanceof Integer) { // nothing to add to the message
452 } else if (value instanceof JsonNode) {
453 msg.append(" - exception converting JsonNode");
454 } else if (value instanceof java.util.LinkedHashMap) {
455 msg.append(" exception converting LinkedHashMap");
457 msg.append(" - unable to call .toString() " + e.getMessage());
459 LOGGER.debug(msg.toString(), e);
462 return stringOutputs;
465 private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
466 return new HashMap <> (stringInputs);
469 protected boolean callHeatbridge(String heatStackId) {
470 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
471 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
472 long waitTimeMs = 10000L;
474 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
475 String[] envp = null;
476 File dir = new File(executionDir);
477 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
478 Runtime r = Runtime.getRuntime();
479 Process p = r.exec(cmdarray, envp, dir);
480 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
482 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
483 return wait && p.exitValue()==0;
484 } catch (IOException e) {
485 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
487 } catch (InterruptedException e) {
488 LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e);
490 } catch (RuntimeException e) {
491 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e);
496 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
498 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
499 if (inputs == null) {
502 else if (inputs.size() < 1) {
503 sb.append("\tEMPTY");
505 for (Map.Entry<String,Object> entry : inputs.entrySet()) {
507 String str = entry.getKey();
508 Object value = entry.getValue();
510 outputString = value.toString();
511 } catch (Exception e) {
512 LOGGER.debug("Exception :",e);
513 outputString = "Unable to call toString() on the value for " + str;
515 sb.append("\t\nitem ").append(i++).append(": '").append(str).append("'='").append(outputString)
519 LOGGER.debug(sb.toString());
523 private void sendMapToDebug(Map<String, String> inputs) {
525 StringBuilder sb = new StringBuilder("inputs:");
526 if (inputs == null) {
529 else if (inputs.size() < 1) {
530 sb.append("\tEMPTY");
532 for (Map.Entry<String, String> entry: inputs.entrySet()) {
533 sb.append("\titem ").append(i++).append(": ").append(entry.getKey()).append("=").append(entry.getValue());
536 LOGGER.debug(sb.toString());
540 private String convertNode(final JsonNode node) {
542 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
543 return JSON_MAPPER.writeValueAsString(obj);
544 } catch (JsonParseException jpe) {
545 LOGGER.debug("Error converting json to string " + jpe.getMessage(),jpe);
546 } catch (Exception e) {
547 LOGGER.debug("Error converting json to string " + e.getMessage(),e);
549 return "[Error converting json to string]";
552 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
553 if (objectMap == null) {
556 Map<String, String> stringMap = new HashMap<>();
557 for (String key : objectMap.keySet()) {
558 if (!stringMap.containsKey(key)) {
559 Object obj = objectMap.get(key);
560 if (obj instanceof String) {
561 stringMap.put(key, (String) objectMap.get(key));
562 } else if (obj instanceof JsonNode ){
563 // This is a bit of mess - but I think it's the least impacting
564 // let's convert it BACK to a string - then it will get converted back later
566 String str = this.convertNode((JsonNode) obj);
567 stringMap.put(key, str);
568 } catch (Exception e) {
569 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
570 //okay in this instance - only string values (fqdn) are expected to be needed
572 } else if (obj instanceof java.util.LinkedHashMap) {
573 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
575 String str = JSON_MAPPER.writeValueAsString(obj);
576 stringMap.put(key, str);
577 } catch (Exception e) {
578 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
580 } else if (obj instanceof Integer) {
582 String str = "" + obj;
583 stringMap.put(key, str);
584 } catch (Exception e) {
585 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
589 String str = obj.toString();
590 stringMap.put(key, str);
591 } catch (Exception e) {
592 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
602 public void createVfModule(String cloudSiteId,
608 String volumeGroupHeatStackId,
609 String baseVfHeatStackId,
610 String modelCustomizationUuid,
611 Map <String, String> inputs,
612 Boolean failIfExists,
614 Boolean enableBridge,
615 MsoRequest msoRequest,
616 Holder <String> vnfId,
617 Holder <Map <String, String>> outputs,
618 Holder <VnfRollback> rollback) throws VnfException {
619 String vfModuleName = vnfName;
620 String vfModuleType = vnfType;
621 String vfVersion = vnfVersion;
622 String mcu = modelCustomizationUuid;
623 boolean useMCUuid = false;
624 if (mcu != null && !mcu.isEmpty()) {
625 if ("null".equalsIgnoreCase(mcu)) {
626 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
630 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
634 MsoLogger.setLogContext (msoRequest);
635 MsoLogger.setServiceName ("CreateVfModule");
636 String requestTypeString = "";
637 if (requestType != null && !"".equals(requestType)) {
638 requestTypeString = requestType;
640 String nestedStackId = null;
641 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
642 nestedStackId = volumeGroupHeatStackId;
644 String nestedBaseStackId = null;
645 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
646 nestedBaseStackId = baseVfHeatStackId;
649 if (inputs == null) {
650 // Create an empty set of inputs
651 inputs = new HashMap<>();
652 LOGGER.debug("inputs == null - setting to empty");
654 this.sendMapToDebug(inputs);
656 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
657 boolean oldWay = false;
658 if (requestTypeString.startsWith("X")) {
660 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
661 requestTypeString = requestTypeString.substring(1);
664 // 1607 - let's parse out the request type we're being sent
665 boolean isBaseRequest = false;
666 boolean isVolumeRequest = false;
667 if (requestTypeString.startsWith("VOLUME")) {
668 isVolumeRequest = true;
671 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
672 // Will capture execution time for metrics
673 long startTime = System.currentTimeMillis ();
675 // Build a default rollback object (no actions performed)
676 VnfRollback vfRollback = new VnfRollback();
677 vfRollback.setCloudSiteId(cloudSiteId);
678 vfRollback.setTenantId(tenantId);
679 vfRollback.setMsoRequest(msoRequest);
680 vfRollback.setRequestType(requestTypeString);
681 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
682 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
683 vfRollback.setIsBase(isBaseRequest);
684 vfRollback.setModelCustomizationUuid(mcu);
686 // Put data into A&AI through Heatstack
687 if(enableBridge != null && enableBridge) {
688 callHeatbridge(baseVfHeatStackId);
691 StackInfo heatStack = null;
692 long subStartTime1 = System.currentTimeMillis ();
694 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
695 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
696 } catch (MsoException me) {
697 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
698 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
699 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
700 // Failed to query the Stack due to an openstack exception.
701 // Convert to a generic VnfException
702 me.addContext ("CreateVFModule");
703 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
704 throw new VnfException (me);
706 // New with 1607 - more precise handling/messaging if the stack already exists
707 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
708 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
709 HeatStatus status = heatStack.getStatus();
710 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
711 // fail - it's in progress - return meaningful error
712 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.";
713 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
714 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
715 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
717 if (status == HeatStatus.FAILED) {
718 // fail - it exists and is in a FAILED state
719 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
720 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
721 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
722 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
724 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
725 // fail - it exists and is in a FAILED state
726 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
727 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");
728 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
729 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
731 if (status == HeatStatus.CREATED) {
733 if (failIfExists != null && failIfExists) {
734 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
735 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
736 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
737 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
739 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
740 // Populate the outputs from the existing stack.
741 vnfId.value = heatStack.getCanonicalName ();
742 outputs.value = copyStringOutputs (heatStack.getOutputs ());
743 rollback.value = vfRollback; // Default rollback - no updates performed
746 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
751 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
752 StackInfo nestedHeatStack = null;
753 long subStartTime2 = System.currentTimeMillis ();
754 Map<String, Object> nestedVolumeOutputs = null;
755 if (nestedStackId != null) {
757 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
758 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
759 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
760 } catch (MsoException me) {
761 // Failed to query the Stack due to an openstack exception.
762 // Convert to a generic VnfException
763 me.addContext ("CreateVFModule");
764 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
765 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
766 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
767 LOGGER.debug("ERROR trying to query nested stack= " + error);
768 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
769 throw new VnfException (me);
771 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
772 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
773 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
774 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
776 throw new VnfException (error, MsoExceptionCategory.USERDATA);
778 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
779 //this.sendMapToDebug(inputs);
780 nestedVolumeOutputs = nestedHeatStack.getOutputs();
781 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
783 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
784 //this.sendMapToDebug(inputs);
788 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
789 StackInfo nestedBaseHeatStack = null;
790 long subStartTime3 = System.currentTimeMillis ();
791 Map<String, Object> baseStackOutputs = null;
792 if (nestedBaseStackId != null) {
794 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
795 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
796 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
797 } catch (MsoException me) {
798 // Failed to query the Stack due to an openstack exception.
799 // Convert to a generic VnfException
800 me.addContext ("CreateVFModule");
801 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
802 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
803 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
804 LOGGER.debug("ERROR trying to query nested base stack= " + error);
805 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
806 throw new VnfException (me);
808 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
809 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
810 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");
811 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
813 throw new VnfException (error, MsoExceptionCategory.USERDATA);
815 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
816 //this.sendMapToDebug(inputs);
817 baseStackOutputs = nestedBaseHeatStack.getOutputs();
818 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
820 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
821 //this.sendMapToDebug(inputs);
825 // Ready to deploy the new VNF
832 VnfResource vnfResource = null;
833 VfModuleCustomization vfmc = null;
834 LOGGER.debug("version: " + vfVersion);
836 // 1707 - db refactoring
837 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(mcu);
839 vf=vfmc.getVfModule();
843 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
845 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
846 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
847 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
848 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
849 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
850 throw new VnfException(error, MsoExceptionCategory.USERDATA);
852 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
854 if (vf.getIsBase()) {
855 isBaseRequest = true;
856 LOGGER.debug("This is a BASE VF request!");
858 LOGGER.debug("This is *not* a BASE VF request!");
859 if (!isVolumeRequest && nestedBaseStackId == null) {
860 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
865 else { // This is to support gamma only - get info from vnf_resource table
866 if (vfVersion != null && !vfVersion.isEmpty()) {
867 vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion);
869 vnfResource = vnfResourceRepo.findByModelName(vnfType);
871 if (vnfResource == null) {
872 String error = "Create VNF: Unknown VNF Type: " + vnfType;
873 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
874 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
875 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
876 throw new VnfException(error, MsoExceptionCategory.USERDATA);
878 LOGGER.debug("Got VNF module definition from Catalog: "
879 + vnfResource.toString());
881 // By here - we have either a vf or vnfResource
883 //1607 - Add version check
884 // First - see if it's in the VnfResource record
885 // if we have a vf Module - then we have to query to get the VnfResource record.
886 if (!oldWay && vf.getVnfResources() != null) {
887 vnfResource = vf.getVnfResources();
888 if (vnfResource == null) {
889 LOGGER.debug("Unable to find vnfResource will not error for now...");
892 String minVersionVnf = null;
893 String maxVersionVnf = null;
894 if (vnfResource != null) {
896 minVersionVnf = vnfResource.getAicVersionMin();
897 maxVersionVnf = vnfResource.getAicVersionMax();
898 } catch (Exception e) {
899 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
900 minVersionVnf = null;
901 maxVersionVnf = null;
903 if (minVersionVnf != null && "".equals(minVersionVnf)) {
904 minVersionVnf = null;
906 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
907 maxVersionVnf = null;
910 if (minVersionVnf != null && maxVersionVnf != null) {
911 MavenLikeVersioning aicV = new MavenLikeVersioning();
914 if (this.cloudConfig != null) {
915 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
916 if (cloudSiteOpt.isPresent()) {
917 aicV.setVersion(cloudSiteOpt.get().getAicVersion());
918 // Add code to handle unexpected values in here
919 boolean moreThanMin = true;
920 boolean equalToMin = true;
921 boolean moreThanMax = true;
922 boolean equalToMax = true;
923 boolean doNotTest = false;
925 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
926 equalToMin = aicV.isTheSameVersion(minVersionVnf);
927 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
928 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
929 } catch (Exception e) {
930 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e);
934 if ((moreThanMin || equalToMin) // aic >= min
935 && (equalToMax || !(moreThanMax))) { //aic <= max
936 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getAicVersion());
939 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getAicVersion();
940 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
942 throw new VnfException(error, MsoExceptionCategory.USERDATA);
945 LOGGER.debug("bypassing testing AIC version...");
947 } // let this error out downstream to avoid introducing uncertainty at this stage
949 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
952 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
954 // End Version check 1607
956 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
957 // with VNF_RESOURCE - we use the old methods.
958 //Integer heatTemplateId = null;
959 //Integer heatEnvtId = null;
963 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
964 HeatTemplate heatTemplate = null;
965 HeatEnvironment heatEnvironment = null;
967 //This will handle old Gamma BrocadeVCE VNF
968 heatTemplate = vnfResource.getHeatTemplates();
972 if (isVolumeRequest) {
973 heatTemplate = vf.getVolumeHeatTemplate();
974 heatEnvironment = vfmc.getVolumeHeatEnv();
976 heatTemplate = vf.getModuleHeatTemplate();
977 heatEnvironment = vfmc.getHeatEnvironment();
982 if (heatTemplate == null) {
983 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
984 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
985 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
986 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
987 MsoAlarmLogger.CRITICAL, error);
988 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
990 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
994 //This will handle old Gamma BrocadeVCE VNF
995 LOGGER.debug ("No environment parameter found for this Type " + vfModuleType);
997 if (heatEnvironment == null) {
998 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
999 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1000 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1001 // Alarm on this error, configuration must be fixed
1002 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1004 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1006 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
1009 // Replace flavors in environment with those returned by OOF
1011 Map<String, Object> returnMap = updateFlavorsFromOof(heatEnvironment.getEnvironment(), inputs);
1012 String heatEnvironmentString = returnMap.get("heatEnvironmentString").toString();
1013 LOGGER.debug("After OOF Update Heat Env String is: " + heatEnvironmentString);
1014 if (returnMap.get("inputs") instanceof Map) {
1015 inputs = (Map<String, String>) returnMap.get("inputs");
1016 LOGGER.debug("After OOF Update inputs are: " + inputs.toString());
1018 LOGGER.debug("inputs is not an instance of a Map: " + returnMap.get("inputs"));
1019 throw new VnfException("Updating inputs using OOF info failed.", MsoExceptionCategory.INTERNAL);
1023 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1024 + heatTemplate.getArtifactUuid ());
1027 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1028 Map <String, Object> nestedTemplatesChecked = new HashMap <> ();
1029 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1030 // for debugging print them out
1031 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1032 for (HeatTemplate entry : nestedTemplates) {
1033 nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody());
1034 LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody());
1037 LOGGER.debug ("No nested templates found - nothing to do here");
1038 nestedTemplatesChecked = null;
1041 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1042 // *if* there are any
1043 List<HeatFiles> heatFiles = null;
1045 Map<String, Object> heatFilesObjects = new HashMap<>();
1047 // Add ability to turn on adding get_files with volume requests (by property).
1048 boolean addGetFilesOnVolumeReq = false;
1050 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1051 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1052 addGetFilesOnVolumeReq = true;
1053 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1055 } catch (Exception e) {
1056 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1059 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1061 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1063 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1064 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1065 + vf.getModelUUID());
1066 heatFiles = vf.getHeatFiles();
1068 if (heatFiles != null && !heatFiles.isEmpty()) {
1069 // add these to stack - to be done in createStack
1070 // here, we will map them to Map<String, Object> from
1071 // Map<String, HeatFiles>
1072 // this will match the nested templates format
1073 LOGGER.debug("Contents of heatFiles - to be added to files: on stack");
1075 for(HeatFiles heatfile : heatFiles){
1076 LOGGER.debug(heatfile.getFileName() + " -> "
1077 + heatfile.getFileBody());
1078 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1081 LOGGER.debug("No heat files found -nothing to do here");
1082 heatFilesObjects = null;
1086 // Check that required parameters have been supplied
1087 String missingParams = null;
1088 List <String> paramList = new ArrayList <> ();
1090 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1091 // supplied an alias. Only check if we don't find it initially.
1092 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1093 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1095 boolean checkRequiredParameters = true;
1097 String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1098 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1099 checkRequiredParameters = false;
1100 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1101 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1103 } catch (Exception e) {
1104 // No problem - default is true
1105 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1107 // 1604 - Add enhanced environment & parameter checking
1108 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1109 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1110 // Note this also removes any comments
1111 MsoHeatEnvironmentEntry mhee = null;
1112 if (heatEnvironment != null && heatEnvironment.getEnvironment() != null && heatEnvironment.getEnvironment().contains ("parameters:")) {
1113 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1114 LOGGER.debug("Enhanced environment checking enabled - 1604");
1115 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1116 //LOGGER.debug("About to create MHEE with " + sb);
1117 mhee = new MsoHeatEnvironmentEntry(sb);
1118 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1119 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1120 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1122 if (!mhee.isValid()) {
1123 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1125 sb2.append("\nEnvironment:");
1126 sb2.append(mhee.toFullString());
1128 LOGGER.debug(sb2.toString());
1130 LOGGER.debug("NO ENVIRONMENT for this entry");
1132 // New with 1707 - all variables converted to their native object types
1133 Map<String, Object> goldenInputs = null;
1135 LOGGER.debug("Now handle the inputs....first convert");
1136 ArrayList<String> parameterNames = new ArrayList<>();
1137 HashMap<String, String> aliasToParam = new HashMap<>();
1138 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1141 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1142 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1143 parameterNames.add(htp.getParamName());
1144 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1145 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1146 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1150 LOGGER.debug(sb.toString());
1151 } catch (Exception e) {
1152 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e);
1154 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1155 // Map<String, Object> - where the object matches the param type identified in the template
1156 // This will also not copy over params that aren't identified in the template
1157 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1158 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1159 LOGGER.debug("Now add in the base stack outputs if applicable");
1160 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1161 // Step 3 - add the volume inputs if any
1162 LOGGER.debug("Now add in the volume stack outputs if applicable");
1163 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1164 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1166 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1167 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1169 + parm.isRequired ()
1171 + parm.getParamAlias ());
1173 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1174 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1175 LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment");
1176 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1177 LOGGER.debug ("Required parameter " + parm.getParamName ()
1178 + " appears to be in environment - do not count as missing");
1180 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1181 if (missingParams == null) {
1182 missingParams = parm.getParamName ();
1184 missingParams += "," + parm.getParamName ();
1188 paramList.add (parm.getParamName ());
1190 if (missingParams != null) {
1191 if (checkRequiredParameters) {
1192 // Problem - missing one or more required parameters
1193 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1194 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1195 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1196 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1198 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1201 LOGGER.debug ("No missing parameters found - ok to proceed");
1203 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1204 // and it causes problems with json that has arrays
1205 String newEnvironmentString = null;
1207 newEnvironmentString = mhee.getRawEntry().toString();
1210 // "Fix" the template if it has CR/LF (getting this from Oracle)
1211 String template = heatTemplate.getHeatTemplate ();
1212 template = template.replaceAll ("\r\n", "\n");
1215 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1216 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1217 LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure);
1218 if (oldWay || isVolumeRequest) {
1219 isValetEnabled = false;
1220 LOGGER.debug("do not send to valet for volume requests or brocade");
1222 boolean sendResponseToValet = false;
1223 if (isValetEnabled) {
1224 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1225 sendResponseToValet = this.valetCreateRequest(cloudSiteId, tenantId, heatFilesObjects,
1226 nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs,
1227 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1228 if (sendResponseToValet) {
1229 goldenInputs = valetModifiedParamsHolder.value;
1233 // Have the tenant. Now deploy the stack itself
1234 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1235 // because we already checked for those.
1236 long createStackStarttime = System.currentTimeMillis ();
1238 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1239 // heatTemplate.getTimeoutMinutes());
1240 if (backout == null) {
1244 LOGGER.debug("heat is not null!!");
1246 heatStack = heat.createStack (cloudSiteId,
1252 heatTemplate.getTimeoutMinutes(),
1253 newEnvironmentString,
1254 nestedTemplatesChecked,
1256 backout.booleanValue());
1259 LOGGER.debug("heat is null!");
1260 throw new MsoHeatNotFoundException();
1262 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1263 } catch (MsoException me) {
1264 me.addContext ("CreateVFModule");
1265 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1266 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1267 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1268 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1269 if (isValetEnabled && sendResponseToValet) {
1270 LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1272 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage());
1273 // Nothing to really do here whether it succeeded or not other than log it.
1274 LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode());
1275 } catch (Exception e) {
1276 LOGGER.error("Exception encountered while sending Rollback to Valet ", e);
1279 throw new VnfException (me);
1280 } catch (NullPointerException npe) {
1281 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1282 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1283 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1284 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1285 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1286 //npe.addContext ("CreateVNF");
1287 throw new VnfException ("NullPointerException during heat.createStack");
1288 } catch (Exception e) {
1289 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1290 LOGGER.debug("unhandled exception at heat.createStack",e);
1291 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1292 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1294 // Reach this point if createStack is successful.
1295 // Populate remaining rollback info and response parameters.
1296 vfRollback.setVnfId (heatStack.getCanonicalName ());
1297 vfRollback.setVnfCreated (true);
1299 vnfId.value = heatStack.getCanonicalName ();
1300 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1301 rollback.value = vfRollback;
1302 if (isValetEnabled && sendResponseToValet) {
1303 LOGGER.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id");
1305 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1306 // Nothing to really do here whether it succeeded or not other than log it.
1307 LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode());
1308 } catch (Exception e) {
1309 LOGGER.error("Exception encountered while sending Confirm to Valet ", e);
1312 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1313 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1315 } catch (Exception e) {
1316 LOGGER.debug("unhandled exception in create VF",e);
1317 throw new VnfException("Exception during create VF " + e.getMessage());
1322 public void deleteVfModule (String cloudSiteId,
1325 MsoRequest msoRequest,
1326 Holder <Map <String, String>> outputs) throws VnfException {
1327 MsoLogger.setLogContext (msoRequest);
1328 MsoLogger.setServiceName ("DeleteVf");
1329 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1330 // Will capture execution time for metrics
1331 long startTime = System.currentTimeMillis ();
1333 // 1702 capture the output parameters on a delete
1334 // so we'll need to query first
1335 Map<String, Object> stackOutputs = null;
1337 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1338 } catch (MsoException me) {
1339 // Failed to query the Stack due to an openstack exception.
1340 // Convert to a generic VnfException
1341 me.addContext ("DeleteVFModule");
1342 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1343 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1344 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1345 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1346 throw new VnfException (me);
1348 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1349 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1351 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1352 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1353 LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure);
1354 boolean valetDeleteRequestSucceeded = false;
1355 if (isValetEnabled) {
1356 valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, tenantId, vnfName, msoRequest, failRequestOnValetFailure);
1359 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1360 // The possible outcomes of deleteStack are a StackInfo object with status
1361 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1363 long subStartTime = System.currentTimeMillis ();
1365 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1366 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1367 } catch (MsoException me) {
1368 me.addContext ("DeleteVNF");
1369 // Failed to query the Stack due to an openstack exception.
1370 // Convert to a generic VnfException
1371 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1372 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1373 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1374 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1375 if (isValetEnabled && valetDeleteRequestSucceeded) {
1376 LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1378 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage());
1379 // Nothing to really do here whether it succeeded or not other than log it.
1380 LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode());
1381 } catch (Exception e) {
1382 LOGGER.error("Exception encountered while sending Rollback to Valet ", e);
1385 throw new VnfException (me);
1387 if (isValetEnabled && valetDeleteRequestSucceeded) {
1388 // only if the original request succeeded do we send a confirm
1389 LOGGER.debug("valet is enabled, the delete succeeded - now send confirm to valet");
1391 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName);
1392 // Nothing to really do here whether it succeeded or not other than log it.
1393 LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode());
1394 } catch (Exception e) {
1395 LOGGER.error("Exception encountered while sending Confirm to Valet ", e);
1399 // On success, nothing is returned.
1400 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1405 public void updateVfModule (String cloudSiteId,
1411 String volumeGroupHeatStackId,
1412 String baseVfHeatStackId,
1413 String vfModuleStackId,
1414 String modelCustomizationUuid,
1415 Map <String, String> inputs,
1416 MsoRequest msoRequest,
1417 Holder <Map <String, String>> outputs,
1418 Holder <VnfRollback> rollback) throws VnfException {
1419 String vfModuleName = vnfName;
1420 String vfModuleType = vnfType;
1421 String methodName = "updateVfModule";
1422 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1423 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1424 MsoLogger.setServiceName (serviceName);
1426 StringBuilder sbInit = new StringBuilder();
1427 sbInit.append("updateVfModule: \n");
1428 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1429 sbInit.append("tenantId=" + tenantId + "\n");
1430 sbInit.append("vnfType=" + vnfType + "\n");
1431 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1432 sbInit.append("vnfName=" + vnfName + "\n");
1433 sbInit.append("requestType=" + requestType + "\n");
1434 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1435 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1436 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1437 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1438 LOGGER.debug(sbInit.toString());
1440 String mcu = modelCustomizationUuid;
1441 boolean useMCUuid = false;
1442 if (mcu != null && !mcu.isEmpty()) {
1443 if (mcu.equalsIgnoreCase("null")) {
1444 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1448 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1453 String requestTypeString = "";
1454 if (requestType != null && !"".equals(requestType)) {
1455 requestTypeString = requestType;
1458 String nestedStackId = null;
1459 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1460 nestedStackId = volumeGroupHeatStackId;
1462 String nestedBaseStackId = null;
1463 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
1464 nestedBaseStackId = baseVfHeatStackId;
1467 if (inputs == null) {
1468 // Create an empty set of inputs
1469 inputs = new HashMap<>();
1470 LOGGER.debug("inputs == null - setting to empty");
1472 this.sendMapToDebug(inputs);
1474 boolean isBaseRequest = false;
1475 boolean isVolumeRequest = false;
1476 if (requestTypeString.startsWith("VOLUME")) {
1477 isVolumeRequest = true;
1479 if ((vfModuleName == null || "".equals(vfModuleName.trim())) && vfModuleStackId != null) {
1480 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1483 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1484 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1486 // Will capture execution time for metrics
1487 long startTime = System.currentTimeMillis ();
1489 // Build a default rollback object (no actions performed)
1490 VnfRollback vfRollback = new VnfRollback ();
1491 vfRollback.setCloudSiteId (cloudSiteId);
1492 vfRollback.setTenantId (tenantId);
1493 vfRollback.setMsoRequest (msoRequest);
1494 vfRollback.setRequestType(requestTypeString);
1495 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1496 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1497 vfRollback.setIsBase(isBaseRequest);
1498 vfRollback.setVfModuleStackId(vfModuleStackId);
1499 vfRollback.setModelCustomizationUuid(mcu);
1501 StackInfo heatStack = null;
1502 long queryStackStarttime = System.currentTimeMillis ();
1503 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1505 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1506 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1507 } catch (MsoException me) {
1508 // Failed to query the Stack due to an openstack exception.
1509 // Convert to a generic VnfException
1510 me.addContext ("UpdateVFModule");
1511 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1512 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1513 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1514 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1515 throw new VnfException (me);
1518 //TODO - do we need to check for the other status possibilities?
1519 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1521 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1522 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1523 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1524 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1526 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1527 // Populate the outputs from the existing stack.
1528 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1529 rollback.value = vfRollback; // Default rollback - no updates performed
1532 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1533 StackInfo nestedHeatStack = null;
1534 long queryStackStarttime2 = System.currentTimeMillis ();
1535 Map<String, Object> nestedVolumeOutputs = null;
1536 if (nestedStackId != null) {
1538 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1539 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1540 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1541 } catch (MsoException me) {
1542 // Failed to query the Stack due to an openstack exception.
1543 // Convert to a generic VnfException
1544 me.addContext ("UpdateVFModule");
1545 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1546 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1547 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1548 LOGGER.debug("ERROR trying to query nested stack= " + error);
1549 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1550 throw new VnfException (me);
1552 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1553 MsoLogger.setServiceName (serviceName);
1554 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1555 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1556 LOGGER.debug(error);
1557 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1558 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1560 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1561 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1562 //this.sendMapToDebug(inputs);
1563 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1565 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1566 //this.sendMapToDebug(inputs);
1569 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1570 StackInfo nestedBaseHeatStack = null;
1571 Map<String, Object> baseStackOutputs = null;
1572 if (nestedBaseStackId != null) {
1573 long queryStackStarttime3 = System.currentTimeMillis ();
1575 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1576 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1577 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1578 } catch (MsoException me) {
1579 // Failed to query the Stack due to an openstack exception.
1580 // Convert to a generic VnfException
1581 me.addContext ("UpdateVfModule");
1582 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1583 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1584 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1585 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1586 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1587 throw new VnfException (me);
1589 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1590 MsoLogger.setServiceName (serviceName);
1591 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1592 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1593 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1594 LOGGER.debug(error);
1595 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1597 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1598 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1599 //this.sendMapToDebug(inputs);
1600 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1602 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1603 //this.sendMapToDebug(inputs);
1607 // Ready to deploy the new VNF
1611 // Retrieve the VF definition
1612 VnfResource vnfResource = null;
1614 VfModuleCustomization vfmc = null;
1616 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
1617 vf = vfmc != null ? vfmc.getVfModule() : null;
1619 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1622 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1625 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1626 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1627 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1628 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1630 LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
1631 if (vf.getIsBase()) {
1632 isBaseRequest = true;
1633 LOGGER.debug("This a BASE update request");
1635 LOGGER.debug("This is *not* a BASE VF update request");
1636 if (!isVolumeRequest && nestedBaseStackId == null) {
1637 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1641 //1607 - Add version check
1642 // First - see if it's in the VnfResource record
1643 // if we have a vf Module - then we have to query to get the VnfResource record.
1644 if (vf.getModelUUID() != null) {
1645 String vnfResourceModelUuid = vf.getModelUUID();
1647 vnfResource = vf.getVnfResources();
1648 if (vnfResource == null) {
1649 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1653 String minVersionVnf = null;
1654 String maxVersionVnf = null;
1655 if (vnfResource != null) {
1657 minVersionVnf = vnfResource.getAicVersionMin();
1658 maxVersionVnf = vnfResource.getAicVersionMax();
1659 } catch (Exception e) {
1660 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1661 minVersionVnf = null;
1662 maxVersionVnf = null;
1664 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1665 minVersionVnf = null;
1667 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1668 maxVersionVnf = null;
1671 if (minVersionVnf != null && maxVersionVnf != null) {
1672 MavenLikeVersioning aicV = new MavenLikeVersioning();
1675 if (this.cloudConfig != null) {
1676 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1677 if (cloudSiteOpt.isPresent()) {
1678 aicV.setVersion(cloudSiteOpt.get().getAicVersion());
1679 boolean moreThanMin = true;
1680 boolean equalToMin = true;
1681 boolean moreThanMax = true;
1682 boolean equalToMax = true;
1683 boolean doNotTest = false;
1685 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1686 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1687 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1688 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1689 } catch (Exception e) {
1690 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage()
1691 + " - will default to not check", e);
1695 if ((moreThanMin || equalToMin) // aic >= min
1696 && ((equalToMax) || !(moreThanMax))) { // aic <= max
1697 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1698 + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId
1699 + " with AIC_Version:" + aicV);
1702 String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin="
1703 + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: "
1704 + cloudSiteId + " with AIC_Version:" + aicV;
1705 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1706 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1707 LOGGER.debug(error);
1708 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1711 LOGGER.debug("bypassing testing AIC version...");
1713 } // let this error out downstream to avoid introducing uncertainty at this stage
1715 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1719 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1721 // End Version check 1607
1723 HeatTemplate heatTemplate = null;
1724 HeatEnvironment heatEnvironment = null;
1725 if (isVolumeRequest) {
1726 heatTemplate = vf.getVolumeHeatTemplate();
1727 heatEnvironment = vfmc.getVolumeHeatEnv();
1729 heatTemplate = vf.getModuleHeatTemplate();
1730 heatEnvironment = vfmc.getHeatEnvironment();
1733 if (heatTemplate == null) {
1734 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1735 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1736 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1737 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1738 MsoAlarmLogger.CRITICAL, error);
1739 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1741 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
1744 if (heatEnvironment == null) {
1745 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
1746 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1747 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1748 // Alarm on this error, configuration must be fixed
1749 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1751 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1753 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
1756 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1757 + heatTemplate.getArtifactUuid ());
1760 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1761 Map <String, Object> nestedTemplatesChecked = new HashMap <> ();
1762 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1763 // for debugging print them out
1764 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1765 for (HeatTemplate entry : nestedTemplates) {
1767 nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody());
1768 LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody());
1771 LOGGER.debug ("No nested templates found - nothing to do here");
1772 nestedTemplatesChecked = null;
1775 // Also add the files: for any get_files associated with this VfModule
1776 // *if* there are any
1777 LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1778 + vf.getModelUUID());
1780 List<HeatFiles> heatFiles = null;
1781 Map <String, Object> heatFilesObjects = new HashMap <> ();
1783 // Add ability to turn on adding get_files with volume requests (by property).
1784 boolean addGetFilesOnVolumeReq = false;
1786 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1787 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1788 addGetFilesOnVolumeReq = true;
1789 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1791 } catch (Exception e) {
1792 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1794 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1795 LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1796 + vf.getModelUUID());
1798 heatFiles = vf.getHeatFiles();
1799 if (heatFiles != null && !heatFiles.isEmpty()) {
1800 // add these to stack - to be done in createStack
1801 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1802 // this will match the nested templates format
1803 LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
1804 for(HeatFiles heatfile : heatFiles){
1805 LOGGER.debug(heatfile.getFileName() + " -> "
1806 + heatfile.getFileBody());
1807 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1810 LOGGER.debug ("No heat files found -nothing to do here");
1811 heatFilesObjects = null;
1815 // Check that required parameters have been supplied
1816 String missingParams = null;
1817 List <String> paramList = new ArrayList <> ();
1819 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1820 // supplied an alias. Only check if we don't find it initially.
1821 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1822 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1824 boolean checkRequiredParameters = true;
1826 String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1827 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1828 checkRequiredParameters = false;
1829 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1830 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1832 } catch (Exception e) {
1833 // No problem - default is true
1834 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1836 // 1604 - Add enhanced environment & parameter checking
1837 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1838 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1839 // Note this also removes any comments
1840 MsoHeatEnvironmentEntry mhee = null;
1841 if (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase ().contains ("parameters:")) {
1842 LOGGER.debug("Enhanced environment checking enabled - 1604");
1843 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1844 mhee = new MsoHeatEnvironmentEntry(sb);
1845 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1846 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1847 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1849 if (!mhee.isValid()) {
1850 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1852 sb2.append("\nEnvironment:");
1853 sb2.append(mhee.toFullString());
1855 LOGGER.debug(sb2.toString());
1857 LOGGER.debug("NO ENVIRONMENT for this entry");
1859 // New for 1607 - support params of json type
1860 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1861 boolean hasJson = false;
1863 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1864 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1866 + parm.isRequired ()
1868 + parm.getParamAlias ());
1870 String parameterType = parm.getParamType();
1871 if (parameterType == null || "".equals(parameterType.trim())) {
1872 parameterType = "String";
1874 JsonNode jsonNode = null;
1875 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1876 if (inputs.containsKey(parm.getParamName()) ) {
1878 String jsonString = null;
1880 jsonString = inputs.get(parm.getParamName());
1881 jsonNode = new ObjectMapper().readTree(jsonString);
1882 } catch (JsonParseException jpe) {
1883 //TODO - what to do here?
1884 //for now - send the error to debug, but just leave it as a String
1885 String errorMessage = jpe.getMessage();
1886 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
1889 } catch (Exception e) {
1891 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
1895 if (jsonNode != null) {
1896 jsonParams.put(parm.getParamName(), jsonNode);
1898 } else if (inputs.containsKey(parm.getParamAlias())) {
1900 String jsonString = null;
1902 jsonString = inputs.get(parm.getParamAlias());
1903 jsonNode = new ObjectMapper().readTree(jsonString);
1904 } catch (JsonParseException jpe) {
1905 //TODO - what to do here?
1906 //for now - send the error to debug, but just leave it as a String
1907 String errorMessage = jpe.getMessage();
1908 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
1911 } catch (Exception e) {
1913 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
1917 if (jsonNode != null) {
1918 // Notice here - we add it to the jsonParams hashMap with the actual name -
1919 // then manipulate the inputs so when we check for aliases below - it will not
1921 jsonParams.put(parm.getParamName(), jsonNode);
1922 inputs.remove(parm.getParamAlias());
1923 inputs.put(parm.getParamName(), jsonString);
1925 } //TODO add a check for the parameter in the env file
1928 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
1929 if (inputs.containsKey (parm.getParamAlias ())) {
1930 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1931 String realParamName = parm.getParamName ();
1932 String alias = parm.getParamAlias ();
1933 String value = inputs.get (alias);
1934 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
1939 inputs.remove (alias);
1940 inputs.put (realParamName, value);
1941 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
1943 // enhanced - check if it's in the Environment (note: that method
1944 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1946 LOGGER.debug ("Required parameter " + parm.getParamName ()
1947 + " appears to be in environment - do not count as missing");
1950 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1951 if (missingParams == null) {
1952 missingParams = parm.getParamName ();
1954 missingParams += "," + parm.getParamName ();
1958 paramList.add (parm.getParamName ());
1962 if (missingParams != null) {
1963 // Problem - missing one or more required parameters
1964 if (checkRequiredParameters) {
1965 String error = "Update VNF: Missing Required inputs: " + missingParams;
1966 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1967 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1968 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1970 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1973 LOGGER.debug ("No missing parameters found - ok to proceed");
1976 // Just submit the envt entry as received from the database
1977 String newEnvironmentString = null;
1979 newEnvironmentString = mhee.getRawEntry().toString();
1981 // Remove any extraneous parameters (don't throw an error)
1982 if (inputs != null) {
1983 List <String> extraParams = new ArrayList <> ();
1984 extraParams.addAll (inputs.keySet ());
1985 // This is not a valid parameter for this template
1986 extraParams.removeAll (paramList);
1987 if (!extraParams.isEmpty ()) {
1988 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
1989 inputs.keySet ().removeAll (extraParams);
1992 Map<String, Object> goldenInputs = copyStringInputs(inputs);
1993 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
1994 Map<String, Object> inputsTwo = null;
1995 if (hasJson && jsonParams.size() > 0) {
1996 inputsTwo = new HashMap<>();
1997 for (Map.Entry<String, String> entry : inputs.entrySet()) {
1998 String keyParamName = entry.getKey();
1999 String value = entry.getValue();
2000 if (jsonParams.containsKey(keyParamName)) {
2001 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2003 inputsTwo.put(keyParamName, value);
2006 goldenInputs = inputsTwo;
2009 // "Fix" the template if it has CR/LF (getting this from Oracle)
2010 String template = heatTemplate.getHeatTemplate ();
2011 template = template.replaceAll ("\r\n", "\n");
2013 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
2014 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
2015 LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure);
2016 if (isVolumeRequest) {
2017 isValetEnabled = false;
2018 LOGGER.debug("never send a volume request to valet");
2020 boolean sendResponseToValet = false;
2021 if (isValetEnabled) {
2022 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
2023 String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
2024 // Make sure it is set to something.
2025 if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) {
2026 parsedVfModuleName = "unknown";
2028 sendResponseToValet = this.valetUpdateRequest(cloudSiteId, tenantId, heatFilesObjects,
2029 nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, (HashMap<String, Object>) goldenInputs,
2030 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
2031 if (sendResponseToValet) {
2032 goldenInputs = valetModifiedParamsHolder.value;
2036 // Have the tenant. Now deploy the stack itself
2037 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2038 // because we already checked for those.
2039 long updateStackStarttime = System.currentTimeMillis ();
2041 heatStack = heatU.updateStack(
2048 heatTemplate.getTimeoutMinutes(),
2049 newEnvironmentString,
2050 //heatEnvironmentString,
2051 nestedTemplatesChecked,
2054 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2055 } catch (MsoException me) {
2056 me.addContext ("UpdateVFModule");
2057 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2058 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2059 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2060 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2061 if (isValetEnabled && sendResponseToValet) {
2062 LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
2064 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage());
2065 // Nothing to really do here whether it succeeded or not other than log it.
2066 LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode());
2067 } catch (Exception e) {
2068 LOGGER.error("Exception encountered while sending Rollback to Valet ", e);
2071 throw new VnfException (me);
2075 // Reach this point if updateStack is successful.
2076 // Populate remaining rollback info and response parameters.
2077 vfRollback.setVnfId (heatStack.getCanonicalName ());
2078 vfRollback.setVnfCreated (true);
2080 if (isValetEnabled && sendResponseToValet) {
2081 LOGGER.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id");
2083 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
2084 // Nothing to really do here whether it succeeded or not other than log it.
2085 LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode());
2086 } catch (Exception e) {
2087 LOGGER.error("Exception encountered while sending Confirm to Valet ", e);
2091 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2092 rollback.value = vfRollback;
2093 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2097 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2098 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2099 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2100 if (vfModuleStackId == null)
2102 int index = vfModuleStackId.lastIndexOf('/');
2105 String vfModuleName = null;
2107 vfModuleName = vfModuleStackId.substring(0, index);
2108 } catch (Exception e) {
2109 LOGGER.debug("Exception", e);
2110 vfModuleName = null;
2112 return vfModuleName;
2115 private Map<String, Object> updateFlavorsFromOof(String heatEnvironmentString, Map<String, String> inputs) {
2116 Map<String, Object> returnMap = new HashMap<>();
2117 for (Map.Entry<String, String> input : inputs.entrySet()){
2118 if (heatEnvironmentString.contains("label_" + input.getKey())){
2119 heatEnvironmentString = heatEnvironmentString.replace("label_" + input.getKey(),
2121 inputs.remove("label_" + input.getKey());
2124 returnMap.put("heatEnvironmentString", heatEnvironmentString);
2125 returnMap.put("inputs", inputs);
2129 * Helper method to check a boolean property value - on error return provided default
2131 private boolean checkBooleanProperty(String propertyName, boolean defaultValue) {
2132 boolean property = defaultValue;
2134 String propertyString = this.environment.getProperty(propertyName);
2135 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
2137 } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
2140 } catch (Exception e) {
2141 LOGGER.debug ("An exception occured trying to get property " + propertyName + " - defaulting to " + defaultValue, e);
2142 property = defaultValue;
2148 * Helper method to combine getFiles and nestedTemplates in to a single Map
2150 private Map<String, Object> combineGetFilesAndNestedTemplates(Map<String, Object> getFiles, Map<String, Object> nestedTemplates) {
2151 boolean haveGetFiles = true;
2152 boolean haveNestedTemplates = true;
2153 Map<String, Object> files = new HashMap<String, Object>();
2154 if (getFiles == null || getFiles.isEmpty()) {
2155 haveGetFiles = false;
2157 if (nestedTemplates == null || nestedTemplates.isEmpty()) {
2158 haveNestedTemplates = false;
2160 if (haveGetFiles && haveNestedTemplates) {
2161 for (String keyString : getFiles.keySet ()) {
2162 files.put (keyString, getFiles.get (keyString));
2164 for (String keyString : nestedTemplates.keySet ()) {
2165 files.put (keyString, nestedTemplates.get (keyString));
2168 // Handle if we only have one or neither:
2172 if (haveNestedTemplates) {
2173 files = nestedTemplates;
2180 * Valet Create request
2182 private boolean valetCreateRequest(String cloudSiteId, String tenantId, Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked,
2183 String vfModuleName, boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
2184 MsoRequest msoRequest, Map<String, String> inputs, boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2185 boolean valetSucceeded = false;
2186 String valetErrorMessage = "more detail not available";
2188 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2189 Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects,
2190 nestedTemplatesChecked);
2191 HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(),
2192 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2193 GenericValetResponse<ValetCreateResponse> createReq = this.vci.callValetCreateRequest(msoRequest.getRequestId(),
2194 cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), inputs.get("vnf_id"),
2195 inputs.get("vnf_name"), inputs.get("vf_module_id"), inputs.get("vf_module_name"), keystoneUrl,
2197 ValetCreateResponse vcr = createReq.getReturnObject();
2198 if (vcr != null && createReq.getStatusCode() == 200) {
2199 ValetStatus status = vcr.getStatus();
2200 if (status != null) {
2201 String statusCode = status.getStatus(); // "ok" or "failed"
2202 if ("ok".equalsIgnoreCase(statusCode)) {
2203 Map<String, Object> newInputs = vcr.getParameters();
2204 if (newInputs != null) {
2205 Map<String, Object> oldGold = goldenInputs;
2206 LOGGER.debug("parameters before being modified by valet:" + oldGold.toString());
2207 goldenInputs = new HashMap<String, Object>();
2208 for (String key : newInputs.keySet()) {
2209 goldenInputs.put(key, newInputs.get(key));
2211 valetModifiedParamsHolder.value = goldenInputs;
2212 LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString());
2213 valetSucceeded = true;
2216 valetErrorMessage = status.getMessage();
2220 LOGGER.debug("Got a bad response back from valet");
2221 valetErrorMessage = "Bad response back from Valet";
2222 valetSucceeded = false;
2224 } catch (Exception e) {
2225 LOGGER.error("An exception occurred trying to call valet ...", e);
2226 valetSucceeded = false;
2227 valetErrorMessage = e.getMessage();
2229 if (failRequestOnValetFailure && !valetSucceeded) {
2230 // The valet request failed - and property says to fail the request
2231 //TODO Create a new exception class for valet?
2232 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2234 return valetSucceeded;
2238 * Valet update request
2241 private boolean valetUpdateRequest(String cloudSiteId, String tenantId,
2242 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
2243 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString,
2244 Map<String, Object> goldenInputs, MsoRequest msoRequest, Map<String, String> inputs,
2245 boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2247 boolean valetSucceeded = false;
2248 String valetErrorMessage = "more detail not available";
2250 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2251 Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects,
2252 nestedTemplatesChecked);
2253 HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(),
2254 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2255 // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now
2256 GenericValetResponse<ValetUpdateResponse> updateReq = this.vci.callValetUpdateRequest(msoRequest.getRequestId(),
2257 cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), inputs.get("vnf_id"),
2258 vfModuleName, inputs.get("vf_module_id"), vfModuleName, keystoneUrl,
2260 ValetUpdateResponse vur = updateReq.getReturnObject();
2261 if (vur != null && updateReq.getStatusCode() == 200) {
2262 ValetStatus status = vur.getStatus();
2263 if (status != null) {
2264 String statusCode = status.getStatus(); // "ok" or "failed"
2265 if ("ok".equalsIgnoreCase(statusCode)) {
2266 Map<String, Object> newInputs = vur.getParameters();
2267 if (newInputs != null) {
2268 Map<String, Object> oldGold = goldenInputs;
2269 LOGGER.debug("parameters before being modified by valet:" + oldGold.toString());
2270 goldenInputs = new HashMap<String, Object>();
2271 for (String key : newInputs.keySet()) {
2272 goldenInputs.put(key, newInputs.get(key));
2274 valetModifiedParamsHolder.value = goldenInputs;
2275 LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString());
2276 valetSucceeded = true;
2279 valetErrorMessage = status.getMessage();
2283 LOGGER.debug("Got a bad response back from valet");
2284 valetErrorMessage = "Got a bad response back from valet";
2285 valetSucceeded = false;
2287 } catch (Exception e) {
2288 LOGGER.error("An exception occurred trying to call valet - will continue processing for now...", e);
2289 valetErrorMessage = e.getMessage();
2290 valetSucceeded = false;
2292 if (failRequestOnValetFailure && !valetSucceeded) {
2293 // The valet request failed - and property says to fail the request
2294 // TODO Create a new exception class for valet?
2295 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2297 return valetSucceeded;
2301 * Valet delete request
2303 private boolean valetDeleteRequest(String cloudSiteId, String tenantId, String vnfName,
2304 MsoRequest msoRequest, boolean failRequestOnValetFailure) {
2305 boolean valetDeleteRequestSucceeded = false;
2306 String valetErrorMessage = "more detail not available";
2308 String vfModuleId = vnfName;
2309 String vfModuleName = vnfName;
2311 vfModuleName = vnfName.substring(0, vnfName.indexOf('/'));
2312 vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1);
2313 } catch (Exception e) {
2314 // do nothing - send what we got for vnfName for both to valet
2316 GenericValetResponse<ValetDeleteResponse> deleteReq = this.vci.callValetDeleteRequest(msoRequest.getRequestId(),
2317 cloudSiteId, tenantId, vfModuleId, vfModuleName);
2318 ValetDeleteResponse vdr = deleteReq.getReturnObject();
2319 if (vdr != null && deleteReq.getStatusCode() == 200) {
2320 ValetStatus status = vdr.getStatus();
2321 if (status != null) {
2322 String statusCode = status.getStatus(); // "ok" or "failed"
2323 if ("ok".equalsIgnoreCase(statusCode)) {
2324 LOGGER.debug("delete request to valet returned success");
2325 valetDeleteRequestSucceeded = true;
2327 LOGGER.debug("delete request to valet returned failure");
2328 valetDeleteRequestSucceeded = false;
2329 valetErrorMessage = status.getMessage();
2333 LOGGER.debug("Got a bad response back from valet - delete request failed");
2334 valetDeleteRequestSucceeded = false;
2335 valetErrorMessage = "Got a bad response back from valet - delete request failed";
2337 } catch (Exception e) {
2338 LOGGER.error("An exception occurred trying to call valet - valetDeleteRequest failed", e);
2339 valetDeleteRequestSucceeded = false;
2340 valetErrorMessage = e.getMessage();
2342 if (valetDeleteRequestSucceeded == false && failRequestOnValetFailure == true) {
2343 LOGGER.error("ValetDeleteRequestFailed - del req still will be sent to openstack", new VnfException("ValetDeleteRequestFailedError"));
2345 return valetDeleteRequestSucceeded;