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.db.catalog.beans.CloudSite;
43 import org.onap.so.db.catalog.beans.HeatEnvironment;
44 import org.onap.so.db.catalog.beans.HeatFiles;
45 import org.onap.so.db.catalog.beans.HeatTemplate;
46 import org.onap.so.db.catalog.beans.HeatTemplateParam;
47 import org.onap.so.db.catalog.beans.VfModule;
48 import org.onap.so.db.catalog.beans.VfModuleCustomization;
49 import org.onap.so.db.catalog.beans.VnfResource;
50 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
51 import org.onap.so.db.catalog.data.repository.VnfResourceRepository;
52 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
53 import org.onap.so.entity.MsoRequest;
54 import org.onap.so.logger.MessageEnum;
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);
100 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
101 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq";
102 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
103 private static final String VALET_ENABLED = "org.onap.so.adapters.vnf.valet_enabled";
104 private static final String FAIL_REQUESTS_ON_VALET_FAILURE = "org.onap.so.adapters.vnf.fail_requests_on_valet_failure";
105 private static final String SUCCESS_MSG = "Successfully received response from Open Stack";
108 private VFModuleCustomizationRepository vfModuleCustomRepo;
112 private VnfResourceRepository vnfResourceRepo;
115 private MsoHeatUtilsWithUpdate heatU;
117 private MsoHeatUtils heat;
119 private ValetClient vci;
122 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
123 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
125 public MsoVnfAdapterImpl() {
127 //DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
131 * Health Check web method. Does nothing but return to show the adapter is deployed.
134 public void healthCheck () {
135 LOGGER.debug ("Health check call in VNF Adapter");
139 * This is the "Create VNF" web service implementation.
140 * It will create a new VNF of the requested type in the specified cloud
141 * and tenant. The tenant must exist before this service is called.
143 * If a VNF with the same name already exists, this can be considered a
144 * success or failure, depending on the value of the 'failIfExists' parameter.
146 * All VNF types will be defined in the MSO catalog. The caller must request
147 * one of these pre-defined types or an error will be returned. Within the
148 * catalog, each VNF type references (among other things) a Heat template
149 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
152 * Depending on the Heat template, a variable set of input parameters will
153 * be defined, some of which are required. The caller is responsible to
154 * pass the necessary input data for the VNF or an error will be thrown.
156 * The method returns the vnfId (the canonical name), a Map of VNF output
157 * attributes, and a VnfRollback object. This last object can be passed
158 * as-is to the rollbackVnf operation to undo everything that was created
159 * for the VNF. This is useful if a VNF is successfully created but the
160 * orchestrator fails on a subsequent operation.
162 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
163 * @param tenantId Openstack tenant identifier
164 * @param vnfType VNF type key, should match a VNF definition in catalog DB
165 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
166 * @param vnfName Name to be assigned to the new VNF
167 * @param inputs Map of key=value inputs for VNF stack creation
168 * @param failIfExists Flag whether already existing VNF should be considered
169 * a success or failure
170 * @param msoRequest Request tracking information for logs
171 * @param vnfId Holder for output VNF Openstack ID
172 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
173 * @param rollback Holder for returning VnfRollback object
176 public void createVnf (String cloudSiteId,
182 String volumeGroupHeatStackId,
183 Map <String, Object> inputs,
184 Boolean failIfExists,
186 Boolean enableBridge,
187 MsoRequest msoRequest,
188 Holder <String> vnfId,
189 Holder <Map <String, String>> outputs,
190 Holder <VnfRollback> rollback) throws VnfException {
191 // parameters used for multicloud adapter
192 String genericVnfId = "";
193 String vfModuleId = "";
194 // Create a hook here to catch shortcut createVf requests:
195 if (requestType != null && requestType.startsWith("VFMOD")) {
196 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
197 String newRequestType = requestType.substring(5);
198 String vfVolGroupHeatStackId = "";
199 String vfBaseHeatStackId = "";
201 if (volumeGroupHeatStackId != null) {
202 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf('|'));
203 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf('|')+1);
205 } catch (Exception e) {
206 // might be ok - both are just blank
207 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
209 this.createVfModule(cloudSiteId,
217 vfVolGroupHeatStackId,
230 // createVf will know if the requestType starts with "X" that it's the "old" way
231 StringBuilder newRequestTypeSb = new StringBuilder("X");
232 String vfVolGroupHeatStackId = "";
233 String vfBaseHeatStackId = "";
234 if (requestType != null) {
235 newRequestTypeSb.append(requestType);
237 this.createVfModule(cloudSiteId,
244 newRequestTypeSb.toString(),
245 vfVolGroupHeatStackId,
257 // End createVf shortcut
261 public void updateVnf (String cloudSiteId,
267 String volumeGroupHeatStackId,
268 Map <String, Object> inputs,
269 MsoRequest msoRequest,
270 Holder <Map <String, String>> outputs,
271 Holder <VnfRollback> rollback) throws VnfException {
272 // As of 1707 - this method should no longer be called
273 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
274 MsoLogger.setServiceName ("UpdateVnf");
275 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
279 * This is the "Query VNF" web service implementation.
280 * It will look up a VNF by name or ID in the specified cloud and tenant.
282 * The method returns an indicator that the VNF exists, its Openstack internal
283 * ID, its status, and the set of outputs (from when the stack was created).
285 * @param cloudSiteId CLLI code of the cloud site in which to query
286 * @param tenantId Openstack tenant identifier
287 * @param vnfName VNF Name or Openstack ID
288 * @param msoRequest Request tracking information for logs
289 * @param vnfExists Flag reporting the result of the query
290 * @param vnfId Holder for output VNF Openstack ID
291 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
294 public void queryVnf (String cloudSiteId,
297 MsoRequest msoRequest,
298 Holder <Boolean> vnfExists,
299 Holder <String> vnfId,
300 Holder <VnfStatus> status,
301 Holder <Map <String, String>> outputs) throws VnfException {
302 MsoLogger.setLogContext (msoRequest);
303 MsoLogger.setServiceName ("QueryVnf");
304 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
306 // Will capture execution time for metrics
307 long startTime = System.currentTimeMillis ();
309 StackInfo heatStack = null;
310 long subStartTime = System.currentTimeMillis ();
312 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
313 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "QueryStack", vnfName);
314 } catch (MsoException me) {
315 me.addContext ("QueryVNF");
316 // Failed to query the Stack due to an openstack exception.
317 // Convert to a generic VnfException
318 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
319 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
320 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
321 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
322 throw new VnfException (me);
325 // Populate the outputs based on the returned Stack information
327 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
329 vnfExists.value = Boolean.FALSE;
330 status.value = VnfStatus.NOTFOUND;
332 outputs.value = new HashMap<>(); // Return as an empty map
334 LOGGER.debug ("VNF " + vnfName + " not found");
336 vnfExists.value = Boolean.TRUE;
337 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
338 vnfId.value = heatStack.getCanonicalName ();
339 outputs.value = copyStringOutputs (heatStack.getOutputs ());
341 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
343 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
348 * This is the "Delete VNF" web service implementation.
349 * It will delete a VNF by name or ID in the specified cloud and tenant.
351 * The method has no outputs.
353 * @param cloudSiteId CLLI code of the cloud site in which to delete
354 * @param tenantId Openstack tenant identifier
355 * @param vnfName VNF Name or Openstack ID
356 * @param msoRequest Request tracking information for logs
359 public void deleteVnf (String cloudSiteId,
362 MsoRequest msoRequest) throws VnfException {
363 MsoLogger.setLogContext (msoRequest);
364 MsoLogger.setServiceName ("DeleteVnf");
365 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
366 // Will capture execution time for metrics
367 long startTime = System.currentTimeMillis ();
369 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
370 // The possible outcomes of deleteStack are a StackInfo object with status
371 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
373 long subStartTime = System.currentTimeMillis ();
375 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
376 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "DeleteStack", vnfName);
377 } catch (MsoException me) {
378 me.addContext ("DeleteVNF");
379 // Failed to query the Stack due to an openstack exception.
380 // Convert to a generic VnfException
381 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
382 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
383 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
384 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
385 throw new VnfException (me);
388 // On success, nothing is returned.
389 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
394 * This web service endpoint will rollback a previous Create VNF operation.
395 * A rollback object is returned to the client in a successful creation
396 * response. The client can pass that object as-is back to the rollbackVnf
397 * operation to undo the creation.
400 public void rollbackVnf (VnfRollback rollback) throws VnfException {
401 long startTime = System.currentTimeMillis ();
402 MsoLogger.setServiceName ("RollbackVnf");
403 // rollback may be null (e.g. if stack already existed when Create was called)
404 if (rollback == null) {
405 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
406 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
410 // Get the elements of the VnfRollback object for easier access
411 String cloudSiteId = rollback.getCloudSiteId ();
412 String tenantId = rollback.getTenantId ();
413 String vnfId = rollback.getVnfId ();
415 MsoLogger.setLogContext (rollback.getMsoRequest());
417 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
419 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
420 // The possible outcomes of deleteStack are a StackInfo object with status
421 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
423 long subStartTime = System.currentTimeMillis ();
425 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
426 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "DeleteStack", null);
427 } catch (MsoException me) {
428 // Failed to rollback the Stack due to an openstack exception.
429 // Convert to a generic VnfException
430 me.addContext ("RollbackVNF");
431 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
432 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
433 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
434 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
435 throw new VnfException (me);
437 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
441 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
442 switch (stackStatus) {
444 return VnfStatus.ACTIVE;
446 return VnfStatus.ACTIVE;
448 return VnfStatus.FAILED;
450 return VnfStatus.UNKNOWN;
454 private Map <String, String> copyStringOutputs(Map <String, Object> stackOutputs) {
455 Map <String, String> stringOutputs = new HashMap <> ();
456 for (Map.Entry<String,Object> entry : stackOutputs.entrySet ()) {
457 String key = entry.getKey();
458 Object value = entry.getValue();
460 stringOutputs.put(key, value.toString());
461 } catch (Exception e) {
462 StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs");
463 if (value instanceof Integer) { // nothing to add to the message
464 } else if (value instanceof JsonNode) {
465 msg.append(" - exception converting JsonNode");
466 } else if (value instanceof java.util.LinkedHashMap) {
467 msg.append(" exception converting LinkedHashMap");
469 msg.append(" - unable to call .toString() " + e.getMessage());
471 LOGGER.debug(msg.toString(), e);
474 return stringOutputs;
477 private Map <String, Object> copyStringInputs (Map <String, Object> stringInputs) {
478 return new HashMap <> (stringInputs);
481 protected boolean callHeatbridge(String heatStackId) {
482 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
483 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
484 long waitTimeMs = 10000L;
486 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
487 String[] envp = null;
488 File dir = new File(executionDir);
489 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
490 Runtime r = Runtime.getRuntime();
491 Process p = r.exec(cmdarray, envp, dir);
492 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
494 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
495 return wait && p.exitValue()==0;
496 } catch (IOException e) {
497 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
499 } catch (RuntimeException e) {
500 LOGGER.debug(" HeatBridgeMain.py failed during runtime!" + e);
503 catch (Exception e) {
504 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons! " + e);
509 private String convertNode(final JsonNode node) {
511 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
512 return JSON_MAPPER.writeValueAsString(obj);
513 } catch (JsonParseException jpe) {
514 LOGGER.debug("Error converting json to string " + jpe.getMessage(),jpe);
515 } catch (Exception e) {
516 LOGGER.debug("Error converting json to string " + e.getMessage(),e);
518 return "[Error converting json to string]";
521 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
522 if (objectMap == null) {
525 Map<String, String> stringMap = new HashMap<>();
526 for (String key : objectMap.keySet()) {
527 if (!stringMap.containsKey(key)) {
528 Object obj = objectMap.get(key);
529 if (obj instanceof String) {
530 stringMap.put(key, (String) objectMap.get(key));
531 } else if (obj instanceof JsonNode ){
532 // This is a bit of mess - but I think it's the least impacting
533 // let's convert it BACK to a string - then it will get converted back later
535 String str = this.convertNode((JsonNode) obj);
536 stringMap.put(key, str);
537 } catch (Exception e) {
538 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
539 //okay in this instance - only string values (fqdn) are expected to be needed
541 } else if (obj instanceof java.util.LinkedHashMap) {
542 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
544 String str = JSON_MAPPER.writeValueAsString(obj);
545 stringMap.put(key, str);
546 } catch (Exception e) {
547 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
549 } else if (obj instanceof Integer) {
551 String str = "" + obj;
552 stringMap.put(key, str);
553 } catch (Exception e) {
554 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
558 String str = obj.toString();
559 stringMap.put(key, str);
560 } catch (Exception e) {
561 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
571 public void createVfModule(String cloudSiteId,
575 String genericVnfName,
579 String volumeGroupHeatStackId,
580 String baseVfHeatStackId,
581 String modelCustomizationUuid,
582 Map <String, Object> inputs,
583 Boolean failIfExists,
585 Boolean enableBridge,
586 MsoRequest msoRequest,
587 Holder <String> vnfId,
588 Holder <Map <String, String>> outputs,
589 Holder <VnfRollback> rollback) throws VnfException {
590 String vfModuleName = vnfName;
591 String vfModuleType = vnfType;
592 String vfVersion = vnfVersion;
593 String mcu = modelCustomizationUuid;
594 boolean useMCUuid = false;
595 if (mcu != null && !mcu.isEmpty()) {
596 if ("null".equalsIgnoreCase(mcu)) {
597 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
601 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
605 MsoLogger.setLogContext (msoRequest);
606 MsoLogger.setServiceName ("CreateVfModule");
607 String requestTypeString = "";
608 if (requestType != null && !"".equals(requestType)) {
609 requestTypeString = requestType;
611 String nestedStackId = null;
612 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
613 nestedStackId = volumeGroupHeatStackId;
615 String nestedBaseStackId = null;
616 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
617 nestedBaseStackId = baseVfHeatStackId;
620 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
621 boolean oldWay = false;
622 if (requestTypeString.startsWith("X")) {
624 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
625 requestTypeString = requestTypeString.substring(1);
628 // 1607 - let's parse out the request type we're being sent
629 boolean isBaseRequest = false;
630 boolean isVolumeRequest = false;
631 if (requestTypeString.startsWith("VOLUME")) {
632 isVolumeRequest = true;
635 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
636 // Will capture execution time for metrics
637 long startTime = System.currentTimeMillis ();
639 // Build a default rollback object (no actions performed)
640 VnfRollback vfRollback = new VnfRollback();
641 vfRollback.setCloudSiteId(cloudSiteId);
642 vfRollback.setTenantId(tenantId);
643 vfRollback.setMsoRequest(msoRequest);
644 vfRollback.setRequestType(requestTypeString);
645 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
646 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
647 vfRollback.setIsBase(isBaseRequest);
648 vfRollback.setModelCustomizationUuid(mcu);
650 // Put data into A&AI through Heatstack
651 if(enableBridge != null && enableBridge) {
652 callHeatbridge(baseVfHeatStackId);
655 StackInfo heatStack = null;
656 long subStartTime1 = System.currentTimeMillis ();
658 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
659 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "QueryStack", vfModuleName);
660 } catch (MsoException me) {
661 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
662 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
663 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
664 // Failed to query the Stack due to an openstack exception.
665 // Convert to a generic VnfException
666 me.addContext ("CreateVFModule");
667 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
668 throw new VnfException (me);
670 // New with 1607 - more precise handling/messaging if the stack already exists
671 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
672 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
673 HeatStatus status = heatStack.getStatus();
674 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
675 // fail - it's in progress - return meaningful error
676 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
677 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
678 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
679 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
681 if (status == HeatStatus.FAILED) {
682 // fail - it exists and is in a FAILED state
683 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
684 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
685 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
686 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
688 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
689 // fail - it exists and is in a FAILED state
690 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
691 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in UPDATED or UNKNOWN state");
692 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
693 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
695 if (status == HeatStatus.CREATED) {
697 if (failIfExists != null && failIfExists) {
698 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
699 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
700 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
701 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
703 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
704 // Populate the outputs from the existing stack.
705 vnfId.value = heatStack.getCanonicalName ();
706 outputs.value = copyStringOutputs (heatStack.getOutputs ());
707 rollback.value = vfRollback; // Default rollback - no updates performed
710 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
715 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
716 StackInfo nestedHeatStack = null;
717 long subStartTime2 = System.currentTimeMillis ();
718 Map<String, Object> nestedVolumeOutputs = null;
719 if (nestedStackId != null) {
721 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
722 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
723 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "QueryStack", vfModuleName);
724 } catch (MsoException me) {
725 // Failed to query the Stack due to an openstack exception.
726 // Convert to a generic VnfException
727 me.addContext ("CreateVFModule");
728 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
729 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
730 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
731 LOGGER.debug("ERROR trying to query nested stack= " + error);
732 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
733 throw new VnfException (me);
735 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
736 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
737 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
738 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
740 throw new VnfException (error, MsoExceptionCategory.USERDATA);
742 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
743 nestedVolumeOutputs = nestedHeatStack.getOutputs();
747 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
748 StackInfo nestedBaseHeatStack = null;
749 long subStartTime3 = System.currentTimeMillis ();
750 Map<String, Object> baseStackOutputs = null;
751 if (nestedBaseStackId != null) {
753 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
754 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
755 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "QueryStack", vfModuleName);
756 } catch (MsoException me) {
757 // Failed to query the Stack due to an openstack exception.
758 // Convert to a generic VnfException
759 me.addContext ("CreateVFModule");
760 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
761 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
762 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
763 LOGGER.debug("ERROR trying to query nested base stack= " + error);
764 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
765 throw new VnfException (me);
767 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
768 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
769 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached base heatStack ID DOES NOT EXIST");
770 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
772 throw new VnfException (error, MsoExceptionCategory.USERDATA);
774 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
775 baseStackOutputs = nestedBaseHeatStack.getOutputs();
779 // Ready to deploy the new VNF
786 VnfResource vnfResource = null;
787 VfModuleCustomization vfmc = null;
788 LOGGER.debug("version: " + vfVersion);
790 // 1707 - db refactoring
791 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(mcu);
793 vf=vfmc.getVfModule();
797 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
799 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
800 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
801 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
802 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
803 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
804 throw new VnfException(error, MsoExceptionCategory.USERDATA);
806 LOGGER.trace("Found vfModuleCust entry " + vfmc.toString());
808 if (vf.getIsBase()) {
809 isBaseRequest = true;
810 LOGGER.debug("This is a BASE VF request!");
812 LOGGER.debug("This is *not* a BASE VF request!");
813 if (!isVolumeRequest && nestedBaseStackId == null) {
814 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
819 else { // This is to support gamma only - get info from vnf_resource table
820 if (vfVersion != null && !vfVersion.isEmpty()) {
821 vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion);
823 vnfResource = vnfResourceRepo.findByModelName(vnfType);
825 if (vnfResource == null) {
826 String error = "Create VNF: Unknown VNF Type: " + vnfType;
827 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
828 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
829 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
830 throw new VnfException(error, MsoExceptionCategory.USERDATA);
832 LOGGER.debug("Got VNF module definition from Catalog: "
833 + vnfResource.toString());
835 // By here - we have either a vf or vnfResource
837 //1607 - Add version check
838 // First - see if it's in the VnfResource record
839 // if we have a vf Module - then we have to query to get the VnfResource record.
840 if (!oldWay && vf.getVnfResources() != null) {
841 vnfResource = vf.getVnfResources();
842 if (vnfResource == null) {
843 LOGGER.debug("Unable to find vnfResource will not error for now...");
846 String minVersionVnf = null;
847 String maxVersionVnf = null;
848 if (vnfResource != null) {
850 minVersionVnf = vnfResource.getAicVersionMin();
851 maxVersionVnf = vnfResource.getAicVersionMax();
852 } catch (Exception e) {
853 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
854 minVersionVnf = null;
855 maxVersionVnf = null;
857 if (minVersionVnf != null && "".equals(minVersionVnf)) {
858 minVersionVnf = null;
860 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
861 maxVersionVnf = null;
864 if (minVersionVnf != null && maxVersionVnf != null) {
865 MavenLikeVersioning aicV = new MavenLikeVersioning();
868 if (this.cloudConfig != null) {
869 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
870 if (cloudSiteOpt.isPresent()) {
871 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
872 // Add code to handle unexpected values in here
873 boolean moreThanMin = true;
874 boolean equalToMin = true;
875 boolean moreThanMax = true;
876 boolean equalToMax = true;
877 boolean doNotTest = false;
879 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
880 equalToMin = aicV.isTheSameVersion(minVersionVnf);
881 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
882 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
883 } catch (Exception e) {
884 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e);
888 if ((moreThanMin || equalToMin) // aic >= min
889 && (equalToMax || !(moreThanMax))) { //aic <= max
890 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion());
893 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion();
894 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
896 throw new VnfException(error, MsoExceptionCategory.USERDATA);
899 LOGGER.debug("bypassing testing AIC version...");
901 } // let this error out downstream to avoid introducing uncertainty at this stage
903 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
906 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
908 // End Version check 1607
913 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
914 HeatTemplate heatTemplate = null;
915 HeatEnvironment heatEnvironment = null;
917 //This will handle old Gamma BrocadeVCE VNF
918 heatTemplate = vnfResource.getHeatTemplates();
922 if (isVolumeRequest) {
923 heatTemplate = vf.getVolumeHeatTemplate();
924 heatEnvironment = vfmc.getVolumeHeatEnv();
926 heatTemplate = vf.getModuleHeatTemplate();
927 heatEnvironment = vfmc.getHeatEnvironment();
932 if (heatTemplate == null) {
933 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
934 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
935 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
936 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
938 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
942 //This will handle old Gamma BrocadeVCE VNF
943 LOGGER.debug ("No environment parameter found for this Type " + vfModuleType);
945 if (heatEnvironment == null) {
946 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
947 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
948 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
949 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
951 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
955 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
956 + heatTemplate.getArtifactUuid ());
959 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
960 Map <String, Object> nestedTemplatesChecked = new HashMap <> ();
961 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
962 // for debugging print them out
963 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
964 for (HeatTemplate entry : nestedTemplates) {
965 nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody());
966 LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody());
969 LOGGER.debug ("No nested templates found - nothing to do here");
970 nestedTemplatesChecked = null;
973 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
974 // *if* there are any
975 List<HeatFiles> heatFiles = null;
977 Map<String, Object> heatFilesObjects = new HashMap<>();
979 // Add ability to turn on adding get_files with volume requests (by property).
980 boolean addGetFilesOnVolumeReq = false;
982 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
983 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
984 addGetFilesOnVolumeReq = true;
985 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
987 } catch (Exception e) {
988 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
991 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
993 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
995 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
996 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
997 + vf.getModelUUID());
998 heatFiles = vf.getHeatFiles();
1000 if (heatFiles != null && !heatFiles.isEmpty()) {
1001 // add these to stack - to be done in createStack
1002 // here, we will map them to Map<String, Object> from
1003 // Map<String, HeatFiles>
1004 // this will match the nested templates format
1005 LOGGER.debug("Contents of heatFiles - to be added to files: on stack");
1007 for(HeatFiles heatfile : heatFiles){
1008 LOGGER.debug(heatfile.getFileName() + " -> "
1009 + heatfile.getFileBody());
1010 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1013 LOGGER.debug("No heat files found -nothing to do here");
1014 heatFilesObjects = null;
1018 // Check that required parameters have been supplied
1019 String missingParams = null;
1020 List <String> paramList = new ArrayList <> ();
1022 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1023 // supplied an alias. Only check if we don't find it initially.
1024 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1025 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1027 boolean checkRequiredParameters = true;
1029 String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1030 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1031 checkRequiredParameters = false;
1032 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1033 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1035 } catch (Exception e) {
1036 // No problem - default is true
1037 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1039 // 1604 - Add enhanced environment & parameter checking
1040 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1041 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1042 // Note this also removes any comments
1043 MsoHeatEnvironmentEntry mhee = null;
1044 if (heatEnvironment != null && heatEnvironment.getEnvironment() != null && heatEnvironment.getEnvironment().contains ("parameters:")) {
1046 LOGGER.debug("Enhanced environment checking enabled - 1604");
1047 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1049 mhee = new MsoHeatEnvironmentEntry(sb);
1050 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1051 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1052 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1054 if (!mhee.isValid()) {
1055 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1057 sb2.append("\nEnvironment:");
1058 sb2.append(mhee.toFullString());
1060 LOGGER.debug(sb2.toString());
1062 LOGGER.debug("NO ENVIRONMENT for this entry");
1064 // New with 1707 - all variables converted to their native object types
1065 Map<String, Object> goldenInputs = null;
1067 LOGGER.debug("Now handle the inputs....first convert");
1068 ArrayList<String> parameterNames = new ArrayList<>();
1069 HashMap<String, String> aliasToParam = new HashMap<>();
1070 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1073 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1074 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1075 parameterNames.add(htp.getParamName());
1076 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1077 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1078 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1082 LOGGER.debug(sb.toString());
1083 } catch (Exception e) {
1084 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e);
1086 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1087 // Map<String, Object> - where the object matches the param type identified in the template
1088 // This will also not copy over params that aren't identified in the template
1089 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1090 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1091 LOGGER.debug("Now add in the base stack outputs if applicable");
1092 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1093 // Step 3 - add the volume inputs if any
1094 LOGGER.debug("Now add in the volume stack outputs if applicable");
1095 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1097 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1098 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1100 + parm.isRequired ()
1102 + parm.getParamAlias ());
1104 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1105 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1106 LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment");
1107 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1108 LOGGER.debug ("Required parameter " + parm.getParamName ()
1109 + " appears to be in environment - do not count as missing");
1111 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1112 if (missingParams == null) {
1113 missingParams = parm.getParamName ();
1115 missingParams += "," + parm.getParamName ();
1119 paramList.add (parm.getParamName ());
1121 if (missingParams != null) {
1122 if (checkRequiredParameters) {
1123 // Problem - missing one or more required parameters
1124 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1125 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1126 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1127 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1129 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1132 LOGGER.debug ("No missing parameters found - ok to proceed");
1134 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1135 // and it causes problems with json that has arrays
1136 String newEnvironmentString = null;
1138 newEnvironmentString = mhee.getRawEntry().toString();
1141 // "Fix" the template if it has CR/LF (getting this from Oracle)
1142 String template = heatTemplate.getHeatTemplate ();
1143 template = template.replaceAll ("\r\n", "\n");
1146 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1147 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1148 LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure);
1149 if (oldWay || isVolumeRequest) {
1150 isValetEnabled = false;
1151 LOGGER.debug("do not send to valet for volume requests or brocade");
1153 boolean sendResponseToValet = false;
1154 if (isValetEnabled) {
1155 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1156 sendResponseToValet = this.valetCreateRequest(cloudSiteId, tenantId, heatFilesObjects,
1157 nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs,
1158 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1159 if (sendResponseToValet) {
1160 goldenInputs = valetModifiedParamsHolder.value;
1164 // Have the tenant. Now deploy the stack itself
1165 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1166 // because we already checked for those.
1167 long createStackStarttime = System.currentTimeMillis ();
1169 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1170 // heatTemplate.getTimeoutMinutes());
1171 if (backout == null) {
1175 LOGGER.debug("heat is not null!!");
1177 heatStack = heat.createStack (cloudSiteId,
1183 heatTemplate.getTimeoutMinutes(),
1184 newEnvironmentString,
1185 nestedTemplatesChecked,
1187 backout.booleanValue());
1190 LOGGER.debug("heat is null!");
1191 throw new MsoHeatNotFoundException();
1193 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "CreateStack", vfModuleName);
1194 } catch (MsoException me) {
1195 me.addContext ("CreateVFModule");
1196 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1197 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1198 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1199 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1200 if (isValetEnabled && sendResponseToValet) {
1201 LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1203 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage());
1204 // Nothing to really do here whether it succeeded or not other than log it.
1205 LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode());
1206 } catch (Exception e) {
1207 LOGGER.error("Exception encountered while sending Rollback to Valet ", e);
1210 throw new VnfException (me);
1211 } catch (NullPointerException npe) {
1212 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1213 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1214 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1215 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1216 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1217 //npe.addContext ("CreateVNF");
1218 throw new VnfException ("NullPointerException during heat.createStack");
1219 } catch (Exception e) {
1220 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1221 LOGGER.debug("unhandled exception at heat.createStack",e);
1222 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1223 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1225 // Reach this point if createStack is successful.
1226 // Populate remaining rollback info and response parameters.
1227 vfRollback.setVnfId (heatStack.getCanonicalName ());
1228 vfRollback.setVnfCreated (true);
1230 vnfId.value = heatStack.getCanonicalName ();
1231 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1232 rollback.value = vfRollback;
1233 if (isValetEnabled && sendResponseToValet) {
1234 LOGGER.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id");
1236 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1237 // Nothing to really do here whether it succeeded or not other than log it.
1238 LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode());
1239 } catch (Exception e) {
1240 LOGGER.error("Exception encountered while sending Confirm to Valet ", e);
1243 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1244 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1246 } catch (Exception e) {
1247 LOGGER.debug("unhandled exception in create VF",e);
1248 throw new VnfException("Exception during create VF " + e.getMessage());
1253 public void deleteVfModule (String cloudSiteId,
1256 MsoRequest msoRequest,
1257 Holder <Map <String, String>> outputs) throws VnfException {
1258 MsoLogger.setLogContext (msoRequest);
1259 MsoLogger.setServiceName ("DeleteVf");
1260 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1261 // Will capture execution time for metrics
1262 long startTime = System.currentTimeMillis ();
1264 // 1702 capture the output parameters on a delete
1265 // so we'll need to query first
1266 Map<String, Object> stackOutputs = null;
1268 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1269 } catch (MsoException me) {
1270 // Failed to query the Stack due to an openstack exception.
1271 // Convert to a generic VnfException
1272 me.addContext ("DeleteVFModule");
1273 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1274 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1275 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1276 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1277 throw new VnfException (me);
1279 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1280 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1282 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1283 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1284 LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure);
1285 boolean valetDeleteRequestSucceeded = false;
1286 if (isValetEnabled) {
1287 valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, tenantId, vnfName, msoRequest, failRequestOnValetFailure);
1290 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1291 // The possible outcomes of deleteStack are a StackInfo object with status
1292 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1294 long subStartTime = System.currentTimeMillis ();
1296 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1297 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, SUCCESS_MSG, "OpenStack", "DeleteStack", vnfName);
1298 } catch (MsoException me) {
1299 me.addContext ("DeleteVNF");
1300 // Failed to query the Stack due to an openstack exception.
1301 // Convert to a generic VnfException
1302 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1303 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1304 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1305 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1306 if (isValetEnabled && valetDeleteRequestSucceeded) {
1307 LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1309 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage());
1310 // Nothing to really do here whether it succeeded or not other than log it.
1311 LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode());
1312 } catch (Exception e) {
1313 LOGGER.error("Exception encountered while sending Rollback to Valet ", e);
1316 throw new VnfException (me);
1318 if (isValetEnabled && valetDeleteRequestSucceeded) {
1319 // only if the original request succeeded do we send a confirm
1320 LOGGER.debug("valet is enabled, the delete succeeded - now send confirm to valet");
1322 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName);
1323 // Nothing to really do here whether it succeeded or not other than log it.
1324 LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode());
1325 } catch (Exception e) {
1326 LOGGER.error("Exception encountered while sending Confirm to Valet ", e);
1330 // On success, nothing is returned.
1331 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1336 public void updateVfModule (String cloudSiteId,
1342 String volumeGroupHeatStackId,
1343 String baseVfHeatStackId,
1344 String vfModuleStackId,
1345 String modelCustomizationUuid,
1346 Map <String, Object> inputs,
1347 MsoRequest msoRequest,
1348 Holder <Map <String, String>> outputs,
1349 Holder <VnfRollback> rollback) throws VnfException {
1350 String vfModuleName = vnfName;
1351 String vfModuleType = vnfType;
1352 String methodName = "updateVfModule";
1353 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1354 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1355 MsoLogger.setServiceName (serviceName);
1357 StringBuilder sbInit = new StringBuilder();
1358 sbInit.append("updateVfModule: \n");
1359 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1360 sbInit.append("tenantId=" + tenantId + "\n");
1361 sbInit.append("vnfType=" + vnfType + "\n");
1362 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1363 sbInit.append("vnfName=" + vnfName + "\n");
1364 sbInit.append("requestType=" + requestType + "\n");
1365 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1366 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1367 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1368 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1369 LOGGER.debug(sbInit.toString());
1371 String mcu = modelCustomizationUuid;
1372 boolean useMCUuid = false;
1373 if (mcu != null && !mcu.isEmpty()) {
1374 if ("null".equalsIgnoreCase(mcu)) {
1375 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1379 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1384 String requestTypeString = "";
1385 if (requestType != null && !"".equals(requestType)) {
1386 requestTypeString = requestType;
1389 String nestedStackId = null;
1390 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1391 nestedStackId = volumeGroupHeatStackId;
1393 String nestedBaseStackId = null;
1394 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
1395 nestedBaseStackId = baseVfHeatStackId;
1398 if (inputs == null) {
1399 // Create an empty set of inputs
1400 inputs = new HashMap<>();
1401 LOGGER.debug("inputs == null - setting to empty");
1404 boolean isBaseRequest = false;
1405 boolean isVolumeRequest = false;
1406 if (requestTypeString.startsWith("VOLUME")) {
1407 isVolumeRequest = true;
1409 if ((vfModuleName == null || "".equals(vfModuleName.trim())) && vfModuleStackId != null) {
1410 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1413 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1414 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1416 // Will capture execution time for metrics
1417 long startTime = System.currentTimeMillis ();
1419 // Build a default rollback object (no actions performed)
1420 VnfRollback vfRollback = new VnfRollback ();
1421 vfRollback.setCloudSiteId (cloudSiteId);
1422 vfRollback.setTenantId (tenantId);
1423 vfRollback.setMsoRequest (msoRequest);
1424 vfRollback.setRequestType(requestTypeString);
1425 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1426 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1427 vfRollback.setIsBase(isBaseRequest);
1428 vfRollback.setVfModuleStackId(vfModuleStackId);
1429 vfRollback.setModelCustomizationUuid(mcu);
1431 StackInfo heatStack = null;
1432 long queryStackStarttime = System.currentTimeMillis ();
1433 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1435 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1436 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1437 } catch (MsoException me) {
1438 // Failed to query the Stack due to an openstack exception.
1439 // Convert to a generic VnfException
1440 me.addContext ("UpdateVFModule");
1441 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1442 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1443 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1444 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1445 throw new VnfException (me);
1448 //TODO - do we need to check for the other status possibilities?
1449 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1451 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1452 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1453 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1454 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1456 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1457 // Populate the outputs from the existing stack.
1458 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1459 rollback.value = vfRollback; // Default rollback - no updates performed
1462 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1463 StackInfo nestedHeatStack = null;
1464 long queryStackStarttime2 = System.currentTimeMillis ();
1465 Map<String, Object> nestedVolumeOutputs = null;
1466 if (nestedStackId != null) {
1468 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1469 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1470 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1471 } catch (MsoException me) {
1472 // Failed to query the Stack due to an openstack exception.
1473 // Convert to a generic VnfException
1474 me.addContext ("UpdateVFModule");
1475 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1476 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1477 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1478 LOGGER.debug("ERROR trying to query nested stack= " + error);
1479 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1480 throw new VnfException (me);
1482 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1483 MsoLogger.setServiceName (serviceName);
1484 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1485 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1486 LOGGER.debug(error);
1487 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1488 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1490 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1491 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1492 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1495 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1496 StackInfo nestedBaseHeatStack = null;
1497 Map<String, Object> baseStackOutputs = null;
1498 if (nestedBaseStackId != null) {
1499 long queryStackStarttime3 = System.currentTimeMillis ();
1501 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1502 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1503 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1504 } catch (MsoException me) {
1505 // Failed to query the Stack due to an openstack exception.
1506 // Convert to a generic VnfException
1507 me.addContext ("UpdateVfModule");
1508 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1509 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1510 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1511 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1512 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1513 throw new VnfException (me);
1515 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1516 MsoLogger.setServiceName (serviceName);
1517 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1518 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1519 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1520 LOGGER.debug(error);
1521 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1523 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1524 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1525 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1529 // Ready to deploy the new VNF
1533 // Retrieve the VF definition
1534 VnfResource vnfResource = null;
1536 VfModuleCustomization vfmc = null;
1538 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
1539 vf = vfmc != null ? vfmc.getVfModule() : null;
1541 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1544 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1547 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1548 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1549 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1550 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1552 LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
1553 if (vf.getIsBase()) {
1554 isBaseRequest = true;
1555 LOGGER.debug("This a BASE update request");
1557 LOGGER.debug("This is *not* a BASE VF update request");
1558 if (!isVolumeRequest && nestedBaseStackId == null) {
1559 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1563 //1607 - Add version check
1564 // First - see if it's in the VnfResource record
1565 // if we have a vf Module - then we have to query to get the VnfResource record.
1566 if (vf.getModelUUID() != null) {
1567 String vnfResourceModelUuid = vf.getModelUUID();
1569 vnfResource = vf.getVnfResources();
1570 if (vnfResource == null) {
1571 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1575 String minVersionVnf = null;
1576 String maxVersionVnf = null;
1577 if (vnfResource != null) {
1579 minVersionVnf = vnfResource.getAicVersionMin();
1580 maxVersionVnf = vnfResource.getAicVersionMax();
1581 } catch (Exception e) {
1582 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1583 minVersionVnf = null;
1584 maxVersionVnf = null;
1586 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1587 minVersionVnf = null;
1589 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1590 maxVersionVnf = null;
1593 if (minVersionVnf != null && maxVersionVnf != null) {
1594 MavenLikeVersioning aicV = new MavenLikeVersioning();
1597 if (this.cloudConfig != null) {
1598 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1599 if (cloudSiteOpt.isPresent()) {
1600 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
1601 boolean moreThanMin = true;
1602 boolean equalToMin = true;
1603 boolean moreThanMax = true;
1604 boolean equalToMax = true;
1605 boolean doNotTest = false;
1607 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1608 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1609 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1610 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1611 } catch (Exception e) {
1612 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage()
1613 + " - will default to not check", e);
1617 if ((moreThanMin || equalToMin) // aic >= min
1618 && ((equalToMax) || !(moreThanMax))) { // aic <= max
1619 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1620 + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId
1621 + " with AIC_Version:" + aicV);
1624 String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin="
1625 + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: "
1626 + cloudSiteId + " with AIC_Version:" + aicV;
1627 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1628 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1629 LOGGER.debug(error);
1630 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1633 LOGGER.debug("bypassing testing AIC version...");
1635 } // let this error out downstream to avoid introducing uncertainty at this stage
1637 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1641 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1643 // End Version check 1607
1645 HeatTemplate heatTemplate = null;
1646 HeatEnvironment heatEnvironment = null;
1647 if (isVolumeRequest) {
1648 heatTemplate = vf.getVolumeHeatTemplate();
1649 heatEnvironment = vfmc.getVolumeHeatEnv();
1651 heatTemplate = vf.getModuleHeatTemplate();
1652 heatEnvironment = vfmc.getHeatEnvironment();
1655 if (heatTemplate == null) {
1656 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1657 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1658 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1659 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1661 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate());
1664 if (heatEnvironment == null) {
1665 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
1666 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1667 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1668 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1670 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.getEnvironment());
1673 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1674 + heatTemplate.getArtifactUuid ());
1677 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1678 Map <String, Object> nestedTemplatesChecked = new HashMap <> ();
1679 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1680 // for debugging print them out
1681 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1682 for (HeatTemplate entry : nestedTemplates) {
1684 nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody());
1685 LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody());
1688 LOGGER.debug ("No nested templates found - nothing to do here");
1689 nestedTemplatesChecked = null;
1692 // Also add the files: for any get_files associated with this VfModule
1693 // *if* there are any
1694 LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1695 + vf.getModelUUID());
1697 List<HeatFiles> heatFiles = null;
1698 Map <String, Object> heatFilesObjects = new HashMap <> ();
1700 // Add ability to turn on adding get_files with volume requests (by property).
1701 boolean addGetFilesOnVolumeReq = false;
1703 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1704 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1705 addGetFilesOnVolumeReq = true;
1706 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1708 } catch (Exception e) {
1709 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1711 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1712 LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1713 + vf.getModelUUID());
1715 heatFiles = vf.getHeatFiles();
1716 if (heatFiles != null && !heatFiles.isEmpty()) {
1717 // add these to stack - to be done in createStack
1718 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1719 // this will match the nested templates format
1720 LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
1721 for(HeatFiles heatfile : heatFiles){
1722 LOGGER.debug(heatfile.getFileName() + " -> "
1723 + heatfile.getFileBody());
1724 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1727 LOGGER.debug ("No heat files found -nothing to do here");
1728 heatFilesObjects = null;
1732 // Check that required parameters have been supplied
1733 String missingParams = null;
1734 List <String> paramList = new ArrayList <> ();
1736 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1737 // supplied an alias. Only check if we don't find it initially.
1738 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1739 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1741 boolean checkRequiredParameters = true;
1743 String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1744 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1745 checkRequiredParameters = false;
1746 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1747 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1749 } catch (Exception e) {
1750 // No problem - default is true
1751 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1753 // 1604 - Add enhanced environment & parameter checking
1754 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1755 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1756 // Note this also removes any comments
1757 MsoHeatEnvironmentEntry mhee = null;
1758 if (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase ().contains ("parameters:")) {
1759 LOGGER.debug("Enhanced environment checking enabled - 1604");
1760 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1761 mhee = new MsoHeatEnvironmentEntry(sb);
1762 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1763 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1764 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1766 if (!mhee.isValid()) {
1767 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1769 sb2.append("\nEnvironment:");
1770 sb2.append(mhee.toFullString());
1772 LOGGER.debug(sb2.toString());
1774 LOGGER.debug("NO ENVIRONMENT for this entry");
1776 // New for 1607 - support params of json type
1777 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1778 boolean hasJson = false;
1780 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1781 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1783 + parm.isRequired ()
1785 + parm.getParamAlias ());
1787 String parameterType = parm.getParamType();
1788 if (parameterType == null || "".equals(parameterType.trim())) {
1789 parameterType = "String";
1791 JsonNode jsonNode = null;
1792 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1793 if (inputs.containsKey(parm.getParamName()) ) {
1795 String jsonString = null;
1797 jsonString = JSON_MAPPER.writeValueAsString(inputs.get(parm.getParamName()));
1798 jsonNode = JSON_MAPPER.readTree(jsonString);
1799 } catch (JsonParseException jpe) {
1800 //TODO - what to do here?
1801 //for now - send the error to debug, but just leave it as a String
1802 String errorMessage = jpe.getMessage();
1803 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
1806 } catch (Exception e) {
1808 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
1812 if (jsonNode != null) {
1813 jsonParams.put(parm.getParamName(), jsonNode);
1815 } else if (inputs.containsKey(parm.getParamAlias())) {
1817 String jsonString = null;
1819 jsonString = (String)inputs.get(parm.getParamAlias());
1820 jsonNode = JSON_MAPPER.readTree(jsonString);
1821 } catch (JsonParseException jpe) {
1822 //TODO - what to do here?
1823 //for now - send the error to debug, but just leave it as a String
1824 String errorMessage = jpe.getMessage();
1825 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
1828 } catch (Exception e) {
1830 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
1834 if (jsonNode != null) {
1835 // Notice here - we add it to the jsonParams hashMap with the actual name -
1836 // then manipulate the inputs so when we check for aliases below - it will not
1838 jsonParams.put(parm.getParamName(), jsonNode);
1839 inputs.remove(parm.getParamAlias());
1840 inputs.put(parm.getParamName(), jsonString);
1842 } //TODO add a check for the parameter in the env file
1845 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
1846 if (inputs.containsKey (parm.getParamAlias ())) {
1847 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1848 String realParamName = parm.getParamName ();
1849 String alias = parm.getParamAlias ();
1850 Object value = inputs.get (alias);
1851 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
1856 inputs.remove (alias);
1857 inputs.put (realParamName, value);
1858 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
1860 // enhanced - check if it's in the Environment (note: that method
1861 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1863 LOGGER.debug ("Required parameter " + parm.getParamName ()
1864 + " appears to be in environment - do not count as missing");
1867 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1868 if (missingParams == null) {
1869 missingParams = parm.getParamName ();
1871 missingParams += "," + parm.getParamName ();
1875 paramList.add (parm.getParamName ());
1879 if (missingParams != null) {
1880 // Problem - missing one or more required parameters
1881 if (checkRequiredParameters) {
1882 String error = "Update VNF: Missing Required inputs: " + missingParams;
1883 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1884 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1885 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1887 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1890 LOGGER.debug ("No missing parameters found - ok to proceed");
1893 // Just submit the envt entry as received from the database
1894 String newEnvironmentString = null;
1896 newEnvironmentString = mhee.getRawEntry().toString();
1898 // Remove any extraneous parameters (don't throw an error)
1899 if (inputs != null) {
1900 List <String> extraParams = new ArrayList <> ();
1901 extraParams.addAll (inputs.keySet ());
1902 // This is not a valid parameter for this template
1903 extraParams.removeAll (paramList);
1904 if (!extraParams.isEmpty ()) {
1905 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
1906 inputs.keySet ().removeAll (extraParams);
1909 Map<String, Object> goldenInputs = copyStringInputs(inputs);
1910 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
1911 Map<String, Object> inputsTwo = null;
1912 if (hasJson && jsonParams.size() > 0) {
1913 inputsTwo = new HashMap<>();
1914 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
1915 String keyParamName = entry.getKey();
1916 Object value = entry.getValue();
1917 if (jsonParams.containsKey(keyParamName)) {
1918 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
1920 inputsTwo.put(keyParamName, value);
1923 goldenInputs = inputsTwo;
1926 // "Fix" the template if it has CR/LF (getting this from Oracle)
1927 String template = heatTemplate.getHeatTemplate ();
1928 template = template.replaceAll ("\r\n", "\n");
1930 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1931 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1932 LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure);
1933 if (isVolumeRequest) {
1934 isValetEnabled = false;
1935 LOGGER.debug("never send a volume request to valet");
1937 boolean sendResponseToValet = false;
1938 if (isValetEnabled) {
1939 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1940 String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1941 // Make sure it is set to something.
1942 if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) {
1943 parsedVfModuleName = "unknown";
1945 sendResponseToValet = this.valetUpdateRequest(cloudSiteId, tenantId, heatFilesObjects,
1946 nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, (HashMap<String, Object>) goldenInputs,
1947 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1948 if (sendResponseToValet) {
1949 goldenInputs = valetModifiedParamsHolder.value;
1953 // Have the tenant. Now deploy the stack itself
1954 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1955 // because we already checked for those.
1956 long updateStackStarttime = System.currentTimeMillis ();
1958 heatStack = heatU.updateStack(
1965 heatTemplate.getTimeoutMinutes(),
1966 newEnvironmentString,
1967 //heatEnvironmentString,
1968 nestedTemplatesChecked,
1971 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
1972 } catch (MsoException me) {
1973 me.addContext ("UpdateVFModule");
1974 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1975 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
1976 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1977 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1978 if (isValetEnabled && sendResponseToValet) {
1979 LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1981 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage());
1982 // Nothing to really do here whether it succeeded or not other than log it.
1983 LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode());
1984 } catch (Exception e) {
1985 LOGGER.error("Exception encountered while sending Rollback to Valet ", e);
1988 throw new VnfException (me);
1992 // Reach this point if updateStack is successful.
1993 // Populate remaining rollback info and response parameters.
1994 vfRollback.setVnfId (heatStack.getCanonicalName ());
1995 vfRollback.setVnfCreated (true);
1997 if (isValetEnabled && sendResponseToValet) {
1998 LOGGER.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id");
2000 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
2001 // Nothing to really do here whether it succeeded or not other than log it.
2002 LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode());
2003 } catch (Exception e) {
2004 LOGGER.error("Exception encountered while sending Confirm to Valet ", e);
2008 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2009 rollback.value = vfRollback;
2010 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2014 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2015 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2016 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2017 if (vfModuleStackId == null)
2019 int index = vfModuleStackId.lastIndexOf('/');
2022 String vfModuleName = null;
2024 vfModuleName = vfModuleStackId.substring(0, index);
2025 } catch (Exception e) {
2026 LOGGER.debug("Exception", e);
2027 vfModuleName = null;
2029 return vfModuleName;
2033 * Helper method to check a boolean property value - on error return provided default
2035 private boolean checkBooleanProperty(String propertyName, boolean defaultValue) {
2036 boolean property = defaultValue;
2038 String propertyString = this.environment.getProperty(propertyName);
2039 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
2041 } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
2044 } catch (Exception e) {
2045 LOGGER.debug ("An exception occured trying to get property " + propertyName + " - defaulting to " + defaultValue, e);
2046 property = defaultValue;
2052 * Helper method to combine getFiles and nestedTemplates in to a single Map
2054 private Map<String, Object> combineGetFilesAndNestedTemplates(Map<String, Object> getFiles, Map<String, Object> nestedTemplates) {
2055 boolean haveGetFiles = true;
2056 boolean haveNestedTemplates = true;
2057 Map<String, Object> files = new HashMap<String, Object>();
2058 if (getFiles == null || getFiles.isEmpty()) {
2059 haveGetFiles = false;
2061 if (nestedTemplates == null || nestedTemplates.isEmpty()) {
2062 haveNestedTemplates = false;
2064 if (haveGetFiles && haveNestedTemplates) {
2065 for (String keyString : getFiles.keySet ()) {
2066 files.put (keyString, getFiles.get (keyString));
2068 for (String keyString : nestedTemplates.keySet ()) {
2069 files.put (keyString, nestedTemplates.get (keyString));
2072 // Handle if we only have one or neither:
2076 if (haveNestedTemplates) {
2077 files = nestedTemplates;
2084 * Valet Create request
2086 private boolean valetCreateRequest(String cloudSiteId, String tenantId, Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked,
2087 String vfModuleName, boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
2088 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2089 boolean valetSucceeded = false;
2090 String valetErrorMessage = "more detail not available";
2092 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2093 Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects,
2094 nestedTemplatesChecked);
2095 HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(),
2096 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2097 GenericValetResponse<ValetCreateResponse> createReq = this.vci.callValetCreateRequest(msoRequest.getRequestId(),
2098 cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), (String)inputs.get("vnf_id"),
2099 (String)inputs.get("vnf_name"), (String)inputs.get("vf_module_id"), (String)inputs.get("vf_module_name"), keystoneUrl,
2101 ValetCreateResponse vcr = createReq.getReturnObject();
2102 if (vcr != null && createReq.getStatusCode() == 200) {
2103 ValetStatus status = vcr.getStatus();
2104 if (status != null) {
2105 String statusCode = status.getStatus(); // "ok" or "failed"
2106 if ("ok".equalsIgnoreCase(statusCode)) {
2107 Map<String, Object> newInputs = vcr.getParameters();
2108 if (newInputs != null) {
2109 Map<String, Object> oldGold = goldenInputs;
2110 LOGGER.debug("parameters before being modified by valet:" + oldGold.toString());
2111 goldenInputs = new HashMap<String, Object>();
2112 for (String key : newInputs.keySet()) {
2113 goldenInputs.put(key, newInputs.get(key));
2115 valetModifiedParamsHolder.value = goldenInputs;
2116 LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString());
2117 valetSucceeded = true;
2120 valetErrorMessage = status.getMessage();
2124 LOGGER.debug("Got a bad response back from valet");
2125 valetErrorMessage = "Bad response back from Valet";
2126 valetSucceeded = false;
2128 } catch (Exception e) {
2129 LOGGER.error("An exception occurred trying to call valet ...", e);
2130 valetSucceeded = false;
2131 valetErrorMessage = e.getMessage();
2133 if (failRequestOnValetFailure && !valetSucceeded) {
2134 // The valet request failed - and property says to fail the request
2135 //TODO Create a new exception class for valet?
2136 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2138 return valetSucceeded;
2142 * Valet update request
2145 private boolean valetUpdateRequest(String cloudSiteId, String tenantId,
2146 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
2147 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString,
2148 Map<String, Object> goldenInputs, MsoRequest msoRequest, Map<String, Object> inputs,
2149 boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2151 boolean valetSucceeded = false;
2152 String valetErrorMessage = "more detail not available";
2154 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2155 Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects,
2156 nestedTemplatesChecked);
2157 HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(),
2158 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2159 // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now
2160 GenericValetResponse<ValetUpdateResponse> updateReq = this.vci.callValetUpdateRequest(msoRequest.getRequestId(),
2161 cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), (String)inputs.get("vnf_id"),
2162 vfModuleName, (String)inputs.get("vf_module_id"), vfModuleName, keystoneUrl,
2164 ValetUpdateResponse vur = updateReq.getReturnObject();
2165 if (vur != null && updateReq.getStatusCode() == 200) {
2166 ValetStatus status = vur.getStatus();
2167 if (status != null) {
2168 String statusCode = status.getStatus(); // "ok" or "failed"
2169 if ("ok".equalsIgnoreCase(statusCode)) {
2170 Map<String, Object> newInputs = vur.getParameters();
2171 if (newInputs != null) {
2172 Map<String, Object> oldGold = goldenInputs;
2173 LOGGER.debug("parameters before being modified by valet:" + oldGold.toString());
2174 goldenInputs = new HashMap<String, Object>();
2175 for (String key : newInputs.keySet()) {
2176 goldenInputs.put(key, newInputs.get(key));
2178 valetModifiedParamsHolder.value = goldenInputs;
2179 LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString());
2180 valetSucceeded = true;
2183 valetErrorMessage = status.getMessage();
2187 LOGGER.debug("Got a bad response back from valet");
2188 valetErrorMessage = "Got a bad response back from valet";
2189 valetSucceeded = false;
2191 } catch (Exception e) {
2192 LOGGER.error("An exception occurred trying to call valet - will continue processing for now...", e);
2193 valetErrorMessage = e.getMessage();
2194 valetSucceeded = false;
2196 if (failRequestOnValetFailure && !valetSucceeded) {
2197 // The valet request failed - and property says to fail the request
2198 // TODO Create a new exception class for valet?
2199 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2201 return valetSucceeded;
2205 * Valet delete request
2207 private boolean valetDeleteRequest(String cloudSiteId, String tenantId, String vnfName,
2208 MsoRequest msoRequest, boolean failRequestOnValetFailure) {
2209 boolean valetDeleteRequestSucceeded = false;
2210 String valetErrorMessage = "more detail not available";
2212 String vfModuleId = vnfName;
2213 String vfModuleName = vnfName;
2215 vfModuleName = vnfName.substring(0, vnfName.indexOf('/'));
2216 vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1);
2217 } catch (Exception e) {
2218 // do nothing - send what we got for vnfName for both to valet
2219 LOGGER.error("An exception occurred trying to call MsoVnfAdapterImpl.valetDeleteRequest() method", e);
2221 GenericValetResponse<ValetDeleteResponse> deleteReq = this.vci.callValetDeleteRequest(msoRequest.getRequestId(),
2222 cloudSiteId, tenantId, vfModuleId, vfModuleName);
2223 ValetDeleteResponse vdr = deleteReq.getReturnObject();
2224 if (vdr != null && deleteReq.getStatusCode() == 200) {
2225 ValetStatus status = vdr.getStatus();
2226 if (status != null) {
2227 String statusCode = status.getStatus(); // "ok" or "failed"
2228 if ("ok".equalsIgnoreCase(statusCode)) {
2229 LOGGER.debug("delete request to valet returned success");
2230 valetDeleteRequestSucceeded = true;
2232 LOGGER.debug("delete request to valet returned failure");
2233 valetDeleteRequestSucceeded = false;
2234 valetErrorMessage = status.getMessage();
2238 LOGGER.debug("Got a bad response back from valet - delete request failed");
2239 valetDeleteRequestSucceeded = false;
2240 valetErrorMessage = "Got a bad response back from valet - delete request failed";
2242 } catch (Exception e) {
2243 LOGGER.error("An exception occurred trying to call valet - valetDeleteRequest failed", e);
2244 valetDeleteRequestSucceeded = false;
2245 valetErrorMessage = e.getMessage();
2247 if (valetDeleteRequestSucceeded == false && failRequestOnValetFailure == true) {
2248 LOGGER.error("ValetDeleteRequestFailed - del req still will be sent to openstack", new VnfException("ValetDeleteRequestFailedError"));
2250 return valetDeleteRequestSucceeded;