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 * Modifications Copyright (c) 2019 Samsung
9 * Modifications Copyright (c) 2019 IBM
10 * ================================================================================
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 * ============LICENSE_END=========================================================
25 package org.onap.so.adapters.vnf;
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.HashMap;
33 import java.util.List;
35 import java.util.Optional;
36 import java.util.concurrent.TimeUnit;
37 import javax.jws.WebService;
38 import javax.xml.ws.Holder;
39 import org.apache.commons.collections.CollectionUtils;
40 import org.onap.so.adapters.valet.GenericValetResponse;
41 import org.onap.so.adapters.valet.ValetClient;
42 import org.onap.so.adapters.valet.beans.HeatRequest;
43 import org.onap.so.adapters.valet.beans.ValetConfirmResponse;
44 import org.onap.so.adapters.valet.beans.ValetCreateResponse;
45 import org.onap.so.adapters.valet.beans.ValetDeleteResponse;
46 import org.onap.so.adapters.valet.beans.ValetRollbackResponse;
47 import org.onap.so.adapters.valet.beans.ValetStatus;
48 import org.onap.so.adapters.valet.beans.ValetUpdateResponse;
49 import org.onap.so.adapters.vnf.exceptions.VnfException;
50 import org.onap.so.adapters.vnf.exceptions.VnfNotFound;
51 import org.onap.so.client.aai.AAIResourcesClient;
52 import org.onap.so.cloud.CloudConfig;
53 import org.onap.so.db.catalog.beans.CloudIdentity;
54 import org.onap.so.db.catalog.beans.CloudSite;
55 import org.onap.so.db.catalog.beans.HeatEnvironment;
56 import org.onap.so.db.catalog.beans.HeatFiles;
57 import org.onap.so.db.catalog.beans.HeatTemplate;
58 import org.onap.so.db.catalog.beans.HeatTemplateParam;
59 import org.onap.so.db.catalog.beans.VfModule;
60 import org.onap.so.db.catalog.beans.VfModuleCustomization;
61 import org.onap.so.db.catalog.beans.VnfResource;
62 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
63 import org.onap.so.db.catalog.data.repository.VnfResourceRepository;
64 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
65 import org.onap.so.entity.MsoRequest;
66 import org.onap.so.heatbridge.HeatBridgeApi;
67 import org.onap.so.heatbridge.HeatBridgeImpl;
68 import org.onap.so.logger.ErrorCode;
69 import org.onap.so.logger.LoggingAnchor;
70 import org.onap.so.logger.MessageEnum;
71 import org.onap.so.openstack.beans.HeatStatus;
72 import org.onap.so.openstack.beans.StackInfo;
73 import org.onap.so.openstack.beans.VnfRollback;
74 import org.onap.so.openstack.beans.VnfStatus;
75 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
76 import org.onap.so.openstack.exceptions.MsoException;
77 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
78 import org.onap.so.openstack.exceptions.MsoHeatNotFoundException;
79 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
80 import org.onap.so.openstack.utils.MsoHeatUtils;
81 import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate;
82 import org.openstack4j.model.compute.Flavor;
83 import org.openstack4j.model.compute.Image;
84 import org.openstack4j.model.compute.Server;
85 import org.openstack4j.model.heat.Resource;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88 import org.springframework.beans.factory.annotation.Autowired;
89 import org.springframework.core.env.Environment;
90 import org.springframework.stereotype.Component;
91 import org.springframework.transaction.annotation.Transactional;
92 import com.fasterxml.jackson.core.JsonParseException;
93 import com.fasterxml.jackson.databind.JsonNode;
94 import com.fasterxml.jackson.databind.ObjectMapper;
96 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
97 targetNamespace = "http://org.onap.so/vnf")
100 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
103 private CloudConfig cloudConfig;
106 private Environment environment;
108 private static final Logger logger = LoggerFactory.getLogger(MsoVnfAdapterImpl.class);
111 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
112 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
113 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq";
114 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
115 private static final String VALET_ENABLED = "org.onap.so.adapters.vnf.valet_enabled";
116 private static final String FAIL_REQUESTS_ON_VALET_FAILURE =
117 "org.onap.so.adapters.vnf.fail_requests_on_valet_failure";
118 private static final String OPENSTACK = "OpenStack";
119 private static final String DELETE_VNF = "DeleteVNF";
120 private static final String QUERY_STACK = "QueryStack";
121 private static final String CREATE_VFM_MODULE = "CreateVFModule";
122 private static final String CREATE_VF_STACK = "Create VF: Stack";
123 private static final String STACK = "Stack";
124 private static final String USER_ERROR = "USER ERROR";
125 private static final String VERSION_MIN = "VersionMin";
126 private static final String VERSION_MAX = "VersionMax";
129 private VFModuleCustomizationRepository vfModuleCustomRepo;
131 private VnfResourceRepository vnfResourceRepo;
133 private MsoHeatUtilsWithUpdate heatU;
135 private MsoHeatUtils msoHeatUtils;
137 private ValetClient vci;
140 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
142 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
144 public MsoVnfAdapterImpl() {
146 // DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
150 * Health Check web method. Does nothing but return to show the adapter is deployed.
153 public void healthCheck() {
154 logger.debug("Health check call in VNF Adapter");
158 * This is the "Create VNF" web service implementation. It will create a new VNF of the requested type in the
159 * specified cloud and tenant. The tenant must exist before this service is called.
161 * If a VNF with the same name already exists, this can be considered a success or failure, depending on the value
162 * of the 'failIfExists' parameter.
164 * All VNF types will be defined in the MSO catalog. The caller must request one of these pre-defined types or an
165 * error will be returned. Within the catalog, each VNF type references (among other things) a Heat template which
166 * is used to deploy the required VNF artifacts (VMs, networks, etc.) to the cloud.
168 * Depending on the Heat template, a variable set of input parameters will be defined, some of which are required.
169 * The caller is responsible to pass the necessary input data for the VNF or an error will be thrown.
171 * The method returns the vnfId (the canonical name), a Map of VNF output attributes, and a VnfRollback object. This
172 * last object can be passed as-is to the rollbackVnf operation to undo everything that was created for the VNF.
173 * This is useful if a VNF is successfully created but the orchestrator fails on a subsequent operation.
175 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
176 * @param cloudOwner cloud owner of the cloud region in which to create the VNF
177 * @param tenantId Openstack tenant identifier
178 * @param vnfType VNF type key, should match a VNF definition in catalog DB
179 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
180 * @param vnfName Name to be assigned to the new VNF
181 * @param inputs Map of key=value inputs for VNF stack creation
182 * @param failIfExists Flag whether already existing VNF should be considered a success or failure
183 * @param msoRequest Request tracking information for logs
184 * @param vnfId Holder for output VNF Openstack ID
185 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
186 * @param rollback Holder for returning VnfRollback object
189 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
190 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
191 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
192 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
193 // parameters used for multicloud adapter
194 String genericVnfId = "";
195 String vfModuleId = "";
196 // Create a hook here to catch shortcut createVf requests:
197 if (requestType != null && requestType.startsWith("VFMOD")) {
198 logger.debug("Calling createVfModule from createVnf -- requestType={}", requestType);
199 String newRequestType = requestType.substring(5);
200 String vfVolGroupHeatStackId = "";
201 String vfBaseHeatStackId = "";
203 if (volumeGroupHeatStackId != null) {
204 vfVolGroupHeatStackId =
205 volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf('|'));
206 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf('|') + 1);
208 } catch (Exception e) {
209 // might be ok - both are just blank
210 logger.debug("ERROR trying to parse the volumeGroupHeatStackId {}", volumeGroupHeatStackId, e);
212 this.createVfModule(cloudSiteId, cloudOwner, tenantId, vnfType, vnfVersion, genericVnfId, vnfName,
213 vfModuleId, newRequestType, vfVolGroupHeatStackId, vfBaseHeatStackId, null, inputs, failIfExists,
214 backout, enableBridge, msoRequest, vnfId, outputs, rollback);
217 // createVf will know if the requestType starts with "X" that it's the "old" way
218 StringBuilder newRequestTypeSb = new StringBuilder("X");
219 String vfVolGroupHeatStackId = "";
220 String vfBaseHeatStackId = "";
221 if (requestType != null) {
222 newRequestTypeSb.append(requestType);
224 this.createVfModule(cloudSiteId, cloudOwner, tenantId, vnfType, vnfVersion, genericVnfId, vnfName, vfModuleId,
225 newRequestTypeSb.toString(), vfVolGroupHeatStackId, vfBaseHeatStackId, null, inputs, failIfExists,
226 backout, enableBridge, msoRequest, vnfId, outputs, rollback);
228 // End createVf shortcut
232 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
233 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
234 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
235 throws VnfException {
236 // As of 1707 - this method should no longer be called
237 logger.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
241 * This is the "Query VNF" web service implementation. It will look up a VNF by name or ID in the specified cloud
244 * The method returns an indicator that the VNF exists, its Openstack internal ID, its status, and the set of
245 * outputs (from when the stack was created).
247 * @param cloudSiteId CLLI code of the cloud site in which to query
248 * @param tenantId Openstack tenant identifier
249 * @param vnfName VNF Name or Openstack ID
250 * @param msoRequest Request tracking information for logs
251 * @param vnfExists Flag reporting the result of the query
252 * @param vnfId Holder for output VNF Openstack ID
253 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
256 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
257 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
258 Holder<Map<String, String>> outputs) throws VnfException {
260 logger.debug("Querying VNF {} in {}/{}", vnfName, cloudSiteId, tenantId);
262 // Will capture execution time for metrics
266 heatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, vnfName);
267 } catch (MsoException me) {
268 me.addContext("QueryVNF");
269 // Failed to query the Stack due to an openstack exception.
270 // Convert to a generic VnfException
272 "Query VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
273 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudSiteId, tenantId,
274 OPENSTACK, "QueryVNF", ErrorCode.DataError.getValue(), "Exception - " + QUERY_STACK, me);
276 throw new VnfException(me);
279 // Populate the outputs based on the returned Stack information
281 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
283 vnfExists.value = Boolean.FALSE;
284 status.value = VnfStatus.NOTFOUND;
286 outputs.value = new HashMap<>(); // Return as an empty map
288 logger.debug("VNF {} not found", vnfName);
290 vnfExists.value = Boolean.TRUE;
291 status.value = stackStatusToVnfStatus(heatStack.getStatus());
292 vnfId.value = heatStack.getCanonicalName();
293 outputs.value = copyStringOutputs(heatStack.getOutputs());
295 logger.debug("VNF {} found, ID = {}", vnfName, vnfId.value);
301 * This is the "Delete VNF" web service implementation. It will delete a VNF by name or ID in the specified cloud
304 * The method has no outputs.
306 * @param cloudSiteId CLLI code of the cloud site in which to delete
307 * @param cloudOwner cloud owner of the cloud region in which to delete
308 * @param tenantId Openstack tenant identifier
309 * @param vnfName VNF Name or Openstack ID
310 * @param msoRequest Request tracking information for logs
313 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
314 throws VnfException {
316 logger.debug("Deleting VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
319 msoHeatUtils.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true, 118);
320 } catch (MsoException me) {
321 me.addContext(DELETE_VNF);
322 // Failed to query the Stack due to an openstack exception.
323 // Convert to a generic VnfException
325 "Delete VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
326 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
327 tenantId, OPENSTACK, DELETE_VNF, ErrorCode.DataError.getValue(), "Exception - " + DELETE_VNF, me);
329 throw new VnfException(me);
332 // On success, nothing is returned.
337 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
338 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
339 * to undo the creation.
342 public void rollbackVnf(VnfRollback rollback) throws VnfException {
343 // rollback may be null (e.g. if stack already existed when Create was called)
344 if (rollback == null) {
345 logger.info(MessageEnum.RA_ROLLBACK_NULL.toString(), OPENSTACK, "rollbackVnf");
349 // Get the elements of the VnfRollback object for easier access
350 String cloudSiteId = rollback.getCloudSiteId();
351 String cloudOwner = rollback.getCloudOwner();
352 String tenantId = rollback.getTenantId();
353 String vnfId = rollback.getVnfId();
355 logger.debug("Rolling Back VNF {} in {}", vnfId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
357 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
358 // The possible outcomes of deleteStack are a StackInfo object with status
359 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
362 msoHeatUtils.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfId, true, 118);
363 } catch (MsoException me) {
364 // Failed to rollback the Stack due to an openstack exception.
365 // Convert to a generic VnfException
366 me.addContext("RollbackVNF");
368 "Rollback VNF: " + vnfId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
369 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfId, cloudOwner, cloudSiteId,
370 tenantId, OPENSTACK, "DeleteStack", ErrorCode.DataError.getValue(), "Exception - DeleteStack", me);
372 throw new VnfException(me);
377 private VnfStatus stackStatusToVnfStatus(HeatStatus stackStatus) {
378 switch (stackStatus) {
380 return VnfStatus.ACTIVE;
382 return VnfStatus.ACTIVE;
384 return VnfStatus.FAILED;
386 return VnfStatus.UNKNOWN;
390 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
391 Map<String, String> stringOutputs = new HashMap<>();
392 for (Map.Entry<String, Object> entry : stackOutputs.entrySet()) {
393 String key = entry.getKey();
394 Object value = entry.getValue();
396 stringOutputs.put(key, value.toString());
397 } catch (Exception e) {
398 StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs");
399 if (value instanceof Integer) { // nothing to add to the message
400 } else if (value instanceof JsonNode) {
401 msg.append(" - exception converting JsonNode");
402 } else if (value instanceof java.util.LinkedHashMap) {
403 msg.append(" exception converting LinkedHashMap");
405 msg.append(" - unable to call .toString() " + e.getMessage());
407 logger.debug(msg.toString(), e);
410 return stringOutputs;
413 private Map<String, Object> copyStringInputs(Map<String, Object> stringInputs) {
414 return new HashMap<>(stringInputs);
417 private void heatbridge(StackInfo heatStack, String cloudOwner, String cloudSiteId, String tenantId,
418 String genericVnfName, String vfModuleId) {
420 CloudSite cloudSite =
421 cloudConfig.getCloudSite(cloudSiteId).orElseThrow(() -> new MsoCloudSiteNotFound(cloudSiteId));
422 CloudIdentity cloudIdentity = cloudSite.getIdentityService();
423 String heatStackId = heatStack.getCanonicalName().split("/")[1];
425 List<String> oobMgtNetNames = new ArrayList<>();
427 HeatBridgeApi heatBridgeClient =
428 new HeatBridgeImpl(new AAIResourcesClient(), cloudIdentity, cloudOwner, cloudSiteId, tenantId);
430 List<Resource> stackResources = heatBridgeClient.queryNestedHeatStackResources(heatStackId);
432 List<Server> osServers = heatBridgeClient.getAllOpenstackServers(stackResources);
434 heatBridgeClient.createPserversAndPinterfacesIfNotPresentInAai(stackResources);
436 List<Image> osImages = heatBridgeClient.extractOpenstackImagesFromServers(osServers);
438 List<Flavor> osFlavors = heatBridgeClient.extractOpenstackFlavorsFromServers(osServers);
440 logger.debug("Successfully queried heat stack{} for resources.", heatStackId);
442 if (osImages != null && !osImages.isEmpty()) {
443 heatBridgeClient.buildAddImagesToAaiAction(osImages);
444 logger.debug("Successfully built AAI actions to add images.");
446 logger.debug("No images to update to AAI.");
449 if (osFlavors != null && !osFlavors.isEmpty()) {
450 heatBridgeClient.buildAddFlavorsToAaiAction(osFlavors);
451 logger.debug("Successfully built AAI actions to add flavors.");
453 logger.debug("No flavors to update to AAI.");
457 heatBridgeClient.buildAddVserversToAaiAction(genericVnfName, vfModuleId, osServers);
458 logger.debug("Successfully queried compute resources and built AAI vserver actions.");
461 List<String> oobMgtNetIds = new ArrayList<>();
463 // if no network-id list is provided, however network-name list is
464 if (!CollectionUtils.isEmpty(oobMgtNetNames)) {
465 oobMgtNetIds = heatBridgeClient.extractNetworkIds(oobMgtNetNames);
467 heatBridgeClient.buildAddVserverLInterfacesToAaiAction(stackResources, oobMgtNetIds);
469 "Successfully queried neutron resources and built AAI actions to add l-interfaces to vservers.");
472 heatBridgeClient.submitToAai();
473 } catch (Exception ex) {
474 logger.debug("Heatbrige failed for stackId: " + heatStack.getCanonicalName(), ex);
478 private String convertNode(final JsonNode node) {
480 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
481 return JSON_MAPPER.writeValueAsString(obj);
482 } catch (JsonParseException jpe) {
483 logger.debug("Error converting json to string: {}", jpe.getMessage(), jpe);
484 } catch (Exception e) {
485 logger.debug("Error converting json to string: {}", e.getMessage(), e);
487 return "[Error converting json to string]";
490 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
491 if (objectMap == null) {
494 Map<String, String> stringMap = new HashMap<>();
495 for (String key : objectMap.keySet()) {
496 if (!stringMap.containsKey(key)) {
497 Object obj = objectMap.get(key);
498 if (obj instanceof String) {
499 stringMap.put(key, (String) objectMap.get(key));
500 } else if (obj instanceof JsonNode) {
501 // This is a bit of mess - but I think it's the least impacting
502 // let's convert it BACK to a string - then it will get converted back later
504 String str = this.convertNode((JsonNode) obj);
505 stringMap.put(key, str);
506 } catch (Exception e) {
507 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
508 // okay in this instance - only string values (fqdn) are expected to be needed
510 } else if (obj instanceof java.util.LinkedHashMap) {
511 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
513 String str = JSON_MAPPER.writeValueAsString(obj);
514 stringMap.put(key, str);
515 } catch (Exception e) {
516 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
518 } else if (obj instanceof Integer) {
520 String str = "" + obj;
521 stringMap.put(key, str);
522 } catch (Exception e) {
523 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
527 String str = obj.toString();
528 stringMap.put(key, str);
529 } catch (Exception e) {
531 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")",
542 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
543 String vnfVersion, String genericVnfName, String vnfName, String vfModuleId, String requestType,
544 String volumeGroupHeatStackId, String baseVfHeatStackId, String modelCustomizationUuid,
545 Map<String, Object> inputs, Boolean failIfExists, Boolean backout, Boolean enableBridge,
546 MsoRequest msoRequest, Holder<String> vnfId, Holder<Map<String, String>> outputs,
547 Holder<VnfRollback> rollback) throws VnfException {
548 String vfModuleName = vnfName;
549 String vfModuleType = vnfType;
550 String vfVersion = vnfVersion;
551 String mcu = modelCustomizationUuid;
552 boolean useMCUuid = false;
553 if (mcu != null && !mcu.isEmpty()) {
554 if ("null".equalsIgnoreCase(mcu)) {
555 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: "
556 + modelCustomizationUuid);
560 logger.debug("Found modelCustomizationUuid! Will use that: {}", mcu);
565 String requestTypeString = "";
566 if (requestType != null && !"".equals(requestType)) {
567 requestTypeString = requestType;
569 String nestedStackId = null;
570 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)
571 && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
572 nestedStackId = volumeGroupHeatStackId;
574 String nestedBaseStackId = null;
575 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
576 nestedBaseStackId = baseVfHeatStackId;
579 // This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
580 boolean oldWay = false;
581 if (requestTypeString.startsWith("X")) {
583 logger.debug("orchestrating a VNF - *NOT* a module!");
584 requestTypeString = requestTypeString.substring(1);
587 // let's parse out the request type we're being sent
588 boolean isBaseRequest = false;
589 boolean isVolumeRequest = false;
590 if (requestTypeString.startsWith("VOLUME")) {
591 isVolumeRequest = true;
594 logger.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId
595 + ", nestedBaseStackId = " + nestedBaseStackId);
597 // Build a default rollback object (no actions performed)
598 VnfRollback vfRollback = new VnfRollback();
599 vfRollback.setCloudSiteId(cloudSiteId);
600 vfRollback.setCloudOwner(cloudOwner);
601 vfRollback.setTenantId(tenantId);
602 vfRollback.setMsoRequest(msoRequest);
603 vfRollback.setRequestType(requestTypeString);
604 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
605 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
606 vfRollback.setIsBase(isBaseRequest);
607 vfRollback.setModelCustomizationUuid(mcu);
609 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
610 StackInfo nestedHeatStack = null;
611 Map<String, Object> nestedVolumeOutputs = null;
612 if (nestedStackId != null) {
614 logger.debug("Querying for nestedStackId = {}", nestedStackId);
615 nestedHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
616 } catch (MsoException me) {
617 // Failed to query the Stack due to an openstack exception.
618 // Convert to a generic VnfException
619 me.addContext(CREATE_VFM_MODULE);
620 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner
621 + "/" + cloudSiteId + "/" + tenantId + ": " + me;
622 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
623 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcesssError.getValue(),
624 "MsoException trying to query nested stack", me);
625 logger.debug("ERROR trying to query nested stack= {}", error);
626 throw new VnfException(me);
628 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
629 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in "
630 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
631 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
632 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK,
633 ErrorCode.BusinessProcesssError.getValue(),
634 "Create VFModule: Attached heatStack ID " + "DOES NOT EXIST");
636 throw new VnfException(error, MsoExceptionCategory.USERDATA);
638 logger.debug("Found nested volume heat stack - copying values to inputs *later*");
639 nestedVolumeOutputs = nestedHeatStack.getOutputs();
643 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
644 StackInfo nestedBaseHeatStack = null;
645 Map<String, Object> baseStackOutputs = null;
646 if (nestedBaseStackId != null) {
648 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
649 nestedBaseHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
650 } catch (MsoException me) {
651 // Failed to query the Stack due to an openstack exception.
652 // Convert to a generic VnfException
653 me.addContext(CREATE_VFM_MODULE);
654 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in "
655 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
656 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
657 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcesssError.getValue(),
658 "MsoException trying to query nested base stack", me);
659 logger.debug("ERROR trying to query nested base stack= {}", error);
660 throw new VnfException(me);
662 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
663 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId
664 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
665 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
666 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK,
667 ErrorCode.BusinessProcesssError.getValue(),
668 "Create VFModule: Attached base heatStack ID DOES NOT EXIST");
669 logger.debug("Exception occurred", error);
670 throw new VnfException(error, MsoExceptionCategory.USERDATA);
672 logger.debug("Found nested base heat stack - these values will be copied to inputs *later*");
673 baseStackOutputs = nestedBaseHeatStack.getOutputs();
679 VnfResource vnfResource = null;
680 VfModuleCustomization vfmc = null;
682 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(mcu);
684 vf = vfmc.getVfModule();
688 // this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
690 logger.debug("Unable to find vfModuleCust with modelCustomizationUuid={}", mcu);
692 "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
693 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
694 "VF Module ModelCustomizationUuid", modelCustomizationUuid, OPENSTACK,
695 ErrorCode.DataError.getValue(),
696 "Create VF Module: Unable to find vfModule with " + "modelCustomizationUuid=" + mcu);
698 throw new VnfException(error, MsoExceptionCategory.USERDATA);
700 logger.trace("Found vfModuleCust entry {}", vfmc.toString());
702 if (vf.getIsBase()) {
703 isBaseRequest = true;
704 logger.debug("This is a BASE VF request!");
706 logger.debug("This is *not* a BASE VF request!");
707 if (!isVolumeRequest && nestedBaseStackId == null) {
709 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
714 else { // This is to support gamma only - get info from vnf_resource table
715 if (vfVersion != null && !vfVersion.isEmpty()) {
716 vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion);
718 vnfResource = vnfResourceRepo.findByModelName(vnfType);
720 if (vnfResource == null) {
721 String error = "Create VNF: Unknown VNF Type: " + vnfType;
722 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VNF Type", vnfType,
723 OPENSTACK, ErrorCode.DataError.getValue(), "Create VNF: Unknown VNF Type");
725 throw new VnfException(error, MsoExceptionCategory.USERDATA);
727 logger.debug("Got VNF module definition from Catalog: {}", vnfResource.toString());
729 // By here - we have either a vf or vnfResource
732 // First - see if it's in the VnfResource record
733 // if we have a vf Module - then we have to query to get the VnfResource record.
736 vnfResource = vf.getVnfResources();
738 if (vnfResource == null) {
739 logger.debug("Unable to find vnfResource will not error for now...");
742 String minVersionVnf = null;
743 String maxVersionVnf = null;
744 if (vnfResource != null) {
746 minVersionVnf = vnfResource.getAicVersionMin();
747 maxVersionVnf = vnfResource.getAicVersionMax();
748 } catch (Exception e) {
749 logger.debug("Unable to pull min/max version for this VNF Resource entry", e);
750 minVersionVnf = null;
751 maxVersionVnf = null;
753 if (minVersionVnf != null && "".equals(minVersionVnf)) {
754 minVersionVnf = null;
756 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
757 maxVersionVnf = null;
760 if (minVersionVnf != null && maxVersionVnf != null) {
761 MavenLikeVersioning aicV = new MavenLikeVersioning();
764 if (this.cloudConfig != null) {
765 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
766 if (cloudSiteOpt.isPresent()) {
767 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
768 // Add code to handle unexpected values in here
769 boolean moreThanMin = true;
770 boolean equalToMin = true;
771 boolean moreThanMax = true;
772 boolean equalToMax = true;
773 boolean doNotTest = false;
775 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
776 equalToMin = aicV.isTheSameVersion(minVersionVnf);
777 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
778 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
779 } catch (Exception e) {
781 "An exception occurred while trying to test Cloud Version {} - will default to not check",
786 if ((moreThanMin || equalToMin) // aic >= min
787 && (equalToMax || !(moreThanMax))) { // aic <= max
788 logger.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid="
789 + vnfResource.getModelUUID() + " " + VERSION_MIN + " =" + minVersionVnf + " "
790 + VERSION_MAX + " :" + maxVersionVnf + " supported on Cloud: " + cloudSiteId
791 + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion());
794 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
795 + vnfResource.getModelUUID() + " " + VERSION_MIN + " =" + minVersionVnf + " "
796 + VERSION_MAX + " :" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId
797 + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion();
798 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK,
799 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
801 throw new VnfException(error, MsoExceptionCategory.USERDATA);
804 logger.debug("bypassing testing Cloud version...");
806 } // let this error out downstream to avoid introducing uncertainty at this stage
808 logger.debug("cloudConfig is NULL - cannot check cloud site version");
812 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
813 HeatTemplate heatTemplate = null;
814 HeatEnvironment heatEnvironment = null;
816 // This will handle old Gamma BrocadeVCE VNF
817 heatTemplate = vnfResource.getHeatTemplates();
820 if (isVolumeRequest) {
821 heatTemplate = vf.getVolumeHeatTemplate();
822 heatEnvironment = vfmc.getVolumeHeatEnv();
824 heatTemplate = vf.getModuleHeatTemplate();
825 heatEnvironment = vfmc.getHeatEnvironment();
830 if (heatTemplate == null) {
831 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
832 + ", modelCustomizationUuid=" + mcu + ", vfModuleUuid="
833 + (vf != null ? vf.getModelUUID() : "null") + ", vnfResourceModelUuid="
834 + vnfResource.getModelUUID() + ", reqType=" + requestTypeString;
835 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template " + "ID",
836 vfModuleType, OPENSTACK, ErrorCode.DataError.getValue(), error);
838 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
840 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
844 // This will handle old Gamma BrocadeVCE VNF
845 logger.debug("No environment parameter found for this Type " + vfModuleType);
847 if (heatEnvironment == null) {
848 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
849 + ", modelCustomizationUuid=" + mcu + ", vfModuleUuid="
850 + (vf != null ? vf.getModelUUID() : "null") + ", vnfResourceModelUuid="
851 + vnfResource.getModelUUID() + ", reqType=" + requestTypeString;
852 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
853 "Heat " + "Environment ID", OPENSTACK, ErrorCode.DataError.getValue(), error);
855 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
857 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
861 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
862 + heatTemplate.getArtifactUuid());
865 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
866 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
867 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
868 // for debugging print them out
869 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
870 for (HeatTemplate entry : nestedTemplates) {
871 nestedTemplatesChecked.put(entry.getTemplateName(), entry.getTemplateBody());
872 logger.debug("Adding Nested Template", entry.getTemplateName());
875 logger.debug("No nested templates found - nothing to do here");
876 nestedTemplatesChecked = null;
879 // Also add the files: for any get_files associated with this vnf_resource_id
880 // *if* there are any
881 List<HeatFiles> heatFiles = null;
883 Map<String, Object> heatFilesObjects = new HashMap<>();
885 // Add ability to turn on adding get_files with volume requests (by property).
886 boolean addGetFilesOnVolumeReq = false;
888 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
889 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
890 addGetFilesOnVolumeReq = true;
891 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
893 } catch (Exception e) {
894 logger.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
895 + " - default to false", e);
898 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
900 logger.debug("In MsoVnfAdapterImpl createVfModule, this should not happen, no heat files!");
902 // now use VF_MODULE_TO_HEAT_FILES table
904 "In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
905 + vf.getModelUUID());
906 heatFiles = vf.getHeatFiles();
908 if (heatFiles != null && !heatFiles.isEmpty()) {
909 // add these to stack - to be done in createStack
910 // here, we will map them to Map<String, Object> from
911 // Map<String, HeatFiles>
912 // this will match the nested templates format
913 logger.debug("Contents of heatFiles - to be added to files: on stack");
915 for (HeatFiles heatfile : heatFiles) {
916 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
917 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
920 logger.debug("No heat files found -nothing to do here");
921 heatFilesObjects = null;
925 // Check that required parameters have been supplied
926 String missingParams = null;
927 List<String> paramList = new ArrayList<>();
929 // consult the PARAM_ALIAS field to see if we've been
930 // supplied an alias. Only check if we don't find it initially.
931 // don't flag missing parameters if there's an environment - because they might be there.
932 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
934 boolean checkRequiredParameters = true;
936 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
937 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
938 checkRequiredParameters = false;
939 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
940 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
942 } catch (Exception e) {
943 // No problem - default is true
944 logger.debug("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
946 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
947 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
948 // Note this also removes any comments
949 MsoHeatEnvironmentEntry mhee = null;
950 if (heatEnvironment != null && heatEnvironment.getEnvironment() != null
951 && heatEnvironment.getEnvironment().contains("parameters:")) {
953 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
955 mhee = new MsoHeatEnvironmentEntry(sb);
956 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
957 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
958 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
960 if (!mhee.isValid()) {
961 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
963 sb2.append("\nEnvironment:");
964 sb2.append(mhee.toFullString());
966 logger.debug(sb2.toString());
968 logger.debug("NO ENVIRONMENT for this entry");
970 // all variables converted to their native object types
971 Map<String, Object> goldenInputs = null;
973 ArrayList<String> parameterNames = new ArrayList<>();
974 HashMap<String, String> aliasToParam = new HashMap<>();
975 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
978 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
979 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
980 parameterNames.add(htp.getParamName());
981 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
982 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
983 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
987 logger.debug(sb.toString());
988 } catch (Exception e) {
989 logger.debug("??An exception occurred trying to go through Parameter Names {}", e.getMessage(), e);
991 // Step 1 - convert what we got as inputs (Map<String, String>) to a
992 // Map<String, Object> - where the object matches the param type identified in the template
993 // This will also not copy over params that aren't identified in the template
994 goldenInputs = msoHeatUtils.convertInputMap(inputs, heatTemplate);
995 // Step 2 - now simply add the outputs as we received them - no need to convert to string
996 logger.debug("Now add in the base stack outputs if applicable");
997 msoHeatUtils.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
998 // Step 3 - add the volume inputs if any
999 logger.debug("Now add in the volume stack outputs if applicable");
1000 msoHeatUtils.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1002 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1003 logger.debug("Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias="
1004 + parm.getParamAlias());
1006 if (parm.isRequired() && (goldenInputs == null || !goldenInputs.containsKey(parm.getParamName()))) {
1007 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the
1008 // Map<String, String> to Map<String, Object>
1009 logger.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check "
1011 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1012 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1013 parm.getParamName());
1015 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1016 if (missingParams == null) {
1017 missingParams = parm.getParamName();
1019 missingParams += "," + parm.getParamName();
1023 paramList.add(parm.getParamName());
1025 if (missingParams != null) {
1026 if (checkRequiredParameters) {
1027 // Problem - missing one or more required parameters
1028 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1029 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams, OPENSTACK,
1030 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1031 logger.debug(error);
1032 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1034 logger.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1037 logger.debug("No missing parameters found - ok to proceed");
1039 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1040 // and it causes problems with json that has arrays
1041 String newEnvironmentString = null;
1043 newEnvironmentString = mhee.getRawEntry().toString();
1046 // "Fix" the template if it has CR/LF (getting this from Oracle)
1047 String template = heatTemplate.getHeatTemplate();
1048 template = template.replaceAll("\r\n", "\n");
1051 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1052 boolean failRequestOnValetFailure =
1053 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1054 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1055 if (oldWay || isVolumeRequest) {
1056 isValetEnabled = false;
1057 logger.debug("do not send to valet for volume requests or brocade");
1059 boolean sendResponseToValet = false;
1060 if (isValetEnabled) {
1061 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1062 sendResponseToValet = this.valetCreateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
1063 nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs,
1064 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1065 if (sendResponseToValet) {
1066 goldenInputs = valetModifiedParamsHolder.value;
1070 // Have the tenant. Now deploy the stack itself
1071 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1072 // because we already checked for those.
1074 StackInfo heatStack = null;
1076 if (backout == null) {
1079 if (failIfExists == null) {
1080 failIfExists = false;
1082 if (msoHeatUtils != null) {
1083 heatStack = msoHeatUtils.createStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, null,
1084 template, goldenInputs, true, heatTemplate.getTimeoutMinutes(), newEnvironmentString,
1085 nestedTemplatesChecked, heatFilesObjects, backout.booleanValue(), failIfExists);
1087 throw new MsoHeatNotFoundException();
1089 } catch (MsoException me) {
1090 me.addContext(CREATE_VFM_MODULE);
1091 logger.error("Error creating Stack", me);
1092 if (isValetEnabled && sendResponseToValet) {
1093 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1095 GenericValetResponse<ValetRollbackResponse> gvr = this.vci
1096 .callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage());
1097 // Nothing to really do here whether it succeeded or not other than log it.
1098 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1099 } catch (Exception e) {
1100 logger.error("Exception encountered while sending Rollback to Valet ", e);
1103 throw new VnfException(me);
1104 } catch (NullPointerException npe) {
1105 logger.error("Error creating Stack", npe);
1106 throw new VnfException("NullPointerException during heat.createStack");
1107 } catch (Exception e) {
1108 logger.error("Error creating Stack", e);
1109 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1111 // Reach this point if createStack is successful.
1112 // Populate remaining rollback info and response parameters.
1113 vfRollback.setVnfId(heatStack.getCanonicalName());
1114 vfRollback.setVnfCreated(true);
1116 vnfId.value = heatStack.getCanonicalName();
1117 outputs.value = copyStringOutputs(heatStack.getOutputs());
1118 rollback.value = vfRollback;
1119 if (isValetEnabled && sendResponseToValet) {
1120 logger.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id");
1122 GenericValetResponse<ValetConfirmResponse> gvr =
1123 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1124 // Nothing to really do here whether it succeeded or not other than log it.
1125 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1126 } catch (Exception e) {
1127 logger.error("Exception encountered while sending Confirm to Valet ", e);
1130 logger.debug("VF Module {} successfully created", vfModuleName);
1131 if (enableBridge != null && enableBridge) {
1133 heatbridge(heatStack, cloudOwner, cloudSiteId, tenantId, genericVnfName, vfModuleId);
1135 } catch (Exception e) {
1136 logger.debug("unhandled exception in create VF", e);
1137 throw new VnfException("Exception during create VF " + e.getMessage());
1142 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1143 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1144 Map<String, Object> stackOutputs;
1146 stackOutputs = msoHeatUtils.queryStackForOutputs(cloudSiteId, cloudOwner, tenantId, vnfName);
1147 } catch (MsoException me) {
1148 // Failed to query the Stack due to an openstack exception.
1149 // Convert to a generic VnfException
1150 me.addContext("DeleteVFModule");
1151 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1152 + "/" + tenantId + ": " + me;
1153 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1154 tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), "Exception - " + QUERY_STACK, me);
1155 logger.debug(error);
1156 throw new VnfException(me);
1158 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1160 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1162 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1163 boolean failRequestOnValetFailure =
1164 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1165 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1166 boolean valetDeleteRequestSucceeded = false;
1167 if (isValetEnabled) {
1168 valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, cloudOwner, tenantId, vnfName,
1169 msoRequest, failRequestOnValetFailure);
1173 msoHeatUtils.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true, 118);
1174 } catch (MsoException me) {
1175 me.addContext(DELETE_VNF);
1176 // Failed to query the Stack due to an openstack exception.
1177 // Convert to a generic VnfException
1179 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1180 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1181 tenantId, OPENSTACK, "DeleteStack", ErrorCode.DataError.getValue(), "Exception - deleteStack", me);
1182 logger.debug(error);
1183 if (isValetEnabled && valetDeleteRequestSucceeded) {
1184 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1186 GenericValetResponse<ValetRollbackResponse> gvr = this.vci
1187 .callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage());
1188 // Nothing to really do here whether it succeeded or not other than log it.
1189 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1190 } catch (Exception e) {
1191 logger.error("Exception encountered while sending Rollback to Valet ", e);
1194 throw new VnfException(me);
1196 if (isValetEnabled && valetDeleteRequestSucceeded) {
1197 // only if the original request succeeded do we send a confirm
1198 logger.debug("valet is enabled, the delete succeeded - now send confirm to valet");
1200 GenericValetResponse<ValetConfirmResponse> gvr =
1201 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName);
1202 // Nothing to really do here whether it succeeded or not other than log it.
1203 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1204 } catch (Exception e) {
1205 logger.error("Exception encountered while sending Confirm to Valet ", e);
1211 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1212 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1213 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1214 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1215 throws VnfException {
1216 String vfModuleName = vnfName;
1217 String vfModuleType = vnfType;
1218 String methodName = "updateVfModule";
1219 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1221 StringBuilder sbInit = new StringBuilder();
1222 sbInit.append("updateVfModule: \n");
1223 sbInit.append("cloudOwner=" + cloudOwner + "\n");
1224 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1225 sbInit.append("tenantId=" + tenantId + "\n");
1226 sbInit.append("vnfType=" + vnfType + "\n");
1227 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1228 sbInit.append("vnfName=" + vnfName + "\n");
1229 sbInit.append("requestType=" + requestType + "\n");
1230 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1231 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1232 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1233 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1234 logger.debug(sbInit.toString());
1236 String mcu = modelCustomizationUuid;
1237 boolean useMCUuid = false;
1238 if (mcu != null && !mcu.isEmpty()) {
1239 if ("null".equalsIgnoreCase(mcu)) {
1240 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: {}",
1241 modelCustomizationUuid);
1245 logger.debug("Found modelCustomizationUuid! Will use that: {}", mcu);
1250 String requestTypeString = "";
1251 if (requestType != null && !"".equals(requestType)) {
1252 requestTypeString = requestType;
1255 String nestedStackId = null;
1256 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)
1257 && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1258 nestedStackId = volumeGroupHeatStackId;
1260 String nestedBaseStackId = null;
1261 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
1262 nestedBaseStackId = baseVfHeatStackId;
1265 if (inputs == null) {
1266 // Create an empty set of inputs
1267 inputs = new HashMap<>();
1268 logger.debug("inputs == null - setting to empty");
1271 boolean isBaseRequest = false;
1272 boolean isVolumeRequest = false;
1273 if (requestTypeString.startsWith("VOLUME")) {
1274 isVolumeRequest = true;
1276 if ((vfModuleName == null || "".equals(vfModuleName.trim())) && vfModuleStackId != null) {
1277 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1280 logger.debug("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudOwner + "/"
1281 + cloudSiteId + "/" + tenantId);
1282 logger.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId
1283 + ", nestedBaseStackId = " + nestedBaseStackId);
1285 // Build a default rollback object (no actions performed)
1286 VnfRollback vfRollback = new VnfRollback();
1287 vfRollback.setCloudSiteId(cloudSiteId);
1288 vfRollback.setCloudOwner(cloudOwner);
1289 vfRollback.setTenantId(tenantId);
1290 vfRollback.setMsoRequest(msoRequest);
1291 vfRollback.setRequestType(requestTypeString);
1292 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1293 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1294 vfRollback.setIsBase(isBaseRequest);
1295 vfRollback.setVfModuleStackId(vfModuleStackId);
1296 vfRollback.setModelCustomizationUuid(mcu);
1298 StackInfo heatStack;
1299 logger.debug("UpdateVfModule - querying for {}", vfModuleName);
1301 heatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName);
1302 } catch (MsoException me) {
1303 // Failed to query the Stack due to an openstack exception.
1304 // Convert to a generic VnfException
1305 me.addContext("UpdateVFModule");
1306 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
1307 + tenantId + ": " + me;
1308 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
1309 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
1310 "Exception - " + QUERY_STACK, me);
1311 logger.debug(error);
1312 throw new VnfException(me);
1315 // TODO - do we need to check for the other status possibilities?
1316 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
1318 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudOwner + "/" + cloudSiteId
1320 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_NOT_EXIST.toString(), vfModuleName, cloudOwner,
1321 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), error);
1322 throw new VnfNotFound(cloudSiteId, cloudOwner, tenantId, vfModuleName);
1324 logger.debug("Found Existing stack, status={}", heatStack.getStatus());
1325 // Populate the outputs from the existing stack.
1326 outputs.value = copyStringOutputs(heatStack.getOutputs());
1327 rollback.value = vfRollback; // Default rollback - no updates performed
1330 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1331 StackInfo nestedHeatStack = null;
1332 Map<String, Object> nestedVolumeOutputs = null;
1333 if (nestedStackId != null) {
1335 logger.debug("Querying for nestedStackId = {}", nestedStackId);
1336 nestedHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
1337 } catch (MsoException me) {
1338 // Failed to query the Stack due to an openstack exception.
1339 // Convert to a generic VnfException
1340 me.addContext("UpdateVFModule");
1341 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner + "/"
1342 + cloudSiteId + "/" + tenantId + ": " + me;
1343 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1344 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
1345 "Exception - " + error, me);
1346 logger.debug("ERROR trying to query nested stack= {}", error);
1347 throw new VnfException(me);
1349 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1350 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in "
1351 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
1352 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1353 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), error);
1354 logger.debug(error);
1355 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1357 logger.debug("Found nested heat stack - copying values to inputs *later*");
1358 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1359 msoHeatUtils.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1362 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1363 StackInfo nestedBaseHeatStack = null;
1364 Map<String, Object> baseStackOutputs = null;
1365 if (nestedBaseStackId != null) {
1367 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
1368 nestedBaseHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
1369 } catch (MsoException me) {
1370 // Failed to query the Stack due to an openstack exception.
1371 // Convert to a generic VnfException
1372 me.addContext("UpdateVfModule");
1373 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in "
1374 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1375 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
1376 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
1377 "Exception - " + error, me);
1378 logger.debug("ERROR trying to query nested base stack= {}", error);
1379 throw new VnfException(me);
1381 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1382 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId
1383 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
1384 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
1385 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), error);
1386 logger.debug(error);
1387 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1389 logger.debug("Found nested base heat stack - copying values to inputs *later*");
1390 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1391 msoHeatUtils.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1395 // Retrieve the VF definition
1396 VnfResource vnfResource = null;
1398 VfModuleCustomization vfmc = null;
1400 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
1401 vf = vfmc != null ? vfmc.getVfModule() : null;
1403 logger.debug("Unable to find a vfModule matching modelCustomizationUuid={}", mcu);
1406 logger.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1409 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1410 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VF Module Type", vfModuleType,
1411 OPENSTACK, ErrorCode.DataError.getValue(), error);
1412 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1414 logger.debug("Got VF module definition from Catalog: {}", vf.toString());
1415 if (vf.getIsBase()) {
1416 isBaseRequest = true;
1417 logger.debug("This a BASE update request");
1419 logger.debug("This is *not* a BASE VF update request");
1420 if (!isVolumeRequest && nestedBaseStackId == null) {
1422 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1426 // 1607 - Add version check
1427 // First - see if it's in the VnfResource record
1428 // if we have a vf Module - then we have to query to get the VnfResource record.
1429 if (vf.getModelUUID() != null) {
1430 String vnfResourceModelUuid = vf.getModelUUID();
1432 vnfResource = vf.getVnfResources();
1433 if (vnfResource == null) {
1434 logger.debug("Unable to find vnfResource at ? will not error for now...", vnfResourceModelUuid);
1438 String minVersionVnf = null;
1439 String maxVersionVnf = null;
1440 if (vnfResource != null) {
1442 minVersionVnf = vnfResource.getAicVersionMin();
1443 maxVersionVnf = vnfResource.getAicVersionMax();
1444 } catch (Exception e) {
1445 logger.debug("Unable to pull min/max version for this VNF Resource entry", e);
1446 minVersionVnf = null;
1447 maxVersionVnf = null;
1449 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1450 minVersionVnf = null;
1452 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1453 maxVersionVnf = null;
1456 if (minVersionVnf != null && maxVersionVnf != null) {
1457 MavenLikeVersioning aicV = new MavenLikeVersioning();
1460 if (this.cloudConfig != null) {
1461 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1462 if (cloudSiteOpt.isPresent()) {
1463 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
1464 boolean moreThanMin = true;
1465 boolean equalToMin = true;
1466 boolean moreThanMax = true;
1467 boolean equalToMax = true;
1468 boolean doNotTest = false;
1470 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1471 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1472 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1473 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1474 } catch (Exception e) {
1476 "An exception occured while trying to test AIC Version {} - will default to not check",
1481 if ((moreThanMin || equalToMin) // aic >= min
1482 && ((equalToMax) || !(moreThanMax))) { // aic <= max
1483 logger.debug("VNF Resource " + vnfResource.getModelName() + " " + VERSION_MIN + " ="
1484 + minVersionVnf + " " + VERSION_MAX + " :" + maxVersionVnf + " supported on Cloud: "
1485 + cloudSiteId + " with AIC_Version:" + aicV);
1488 String error = "VNF Resource type: " + vnfResource.getModelName() + " " + VERSION_MIN + " ="
1489 + minVersionVnf + " " + VERSION_MAX + " :" + maxVersionVnf
1490 + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + aicV;
1491 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK,
1492 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
1493 logger.debug(error);
1494 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1497 logger.debug("bypassing testing AIC version...");
1499 } // let this error out downstream to avoid introducing uncertainty at this stage
1501 logger.debug("cloudConfig is NULL - cannot check cloud site version");
1505 logger.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1507 // End Version check 1607
1509 HeatTemplate heatTemplate = null;
1510 HeatEnvironment heatEnvironment = null;
1511 if (isVolumeRequest) {
1512 heatTemplate = vf.getVolumeHeatTemplate();
1513 heatEnvironment = vfmc.getVolumeHeatEnv();
1515 heatTemplate = vf.getModuleHeatTemplate();
1516 heatEnvironment = vfmc.getHeatEnvironment();
1519 if (heatTemplate == null) {
1520 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
1521 + ", modelCustomizationUuid=" + mcu + ", vfModuleUuid=" + vf.getModelUUID() + ", reqType="
1522 + requestTypeString;
1523 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
1524 vfModuleType, OPENSTACK, ErrorCode.DataError.getValue(), error);
1525 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1527 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
1530 if (heatEnvironment == null) {
1531 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + ", modelCustomizationUuid="
1532 + mcu + ", vfModuleUuid=" + vf.getModelUUID() + ", reqType=" + requestTypeString;
1533 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
1534 OPENSTACK, ErrorCode.DataError.getValue(), error);
1535 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1537 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
1540 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId={}",
1541 heatTemplate.getArtifactUuid());
1544 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1545 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1546 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1547 // for debugging print them out
1548 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
1549 for (HeatTemplate entry : nestedTemplates) {
1551 nestedTemplatesChecked.put(entry.getTemplateName(), entry.getTemplateBody());
1552 logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody());
1555 logger.debug("No nested templates found - nothing to do here");
1556 nestedTemplatesChecked = null;
1559 // Also add the files: for any get_files associated with this VfModule
1560 // *if* there are any
1561 logger.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId={}",
1564 List<HeatFiles> heatFiles = null;
1565 Map<String, Object> heatFilesObjects = new HashMap<>();
1567 // Add ability to turn on adding get_files with volume requests (by property).
1568 boolean addGetFilesOnVolumeReq = false;
1570 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1571 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1572 addGetFilesOnVolumeReq = true;
1573 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
1575 } catch (Exception e) {
1576 logger.debug("An error occured trying to get property {} - default to false",
1577 MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, e);
1579 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1580 logger.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec "
1581 + "vfModuleId={}", vf.getModelUUID());
1583 heatFiles = vf.getHeatFiles();
1584 if (heatFiles != null && !heatFiles.isEmpty()) {
1585 // add these to stack - to be done in createStack
1586 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1587 // this will match the nested templates format
1588 logger.debug("Contents of heatFiles - to be added to files: on stack:");
1589 for (HeatFiles heatfile : heatFiles) {
1590 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
1591 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1594 logger.debug("No heat files found -nothing to do here");
1595 heatFilesObjects = null;
1599 // Check that required parameters have been supplied
1600 String missingParams = null;
1601 List<String> paramList = new ArrayList<>();
1603 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1604 // supplied an alias. Only check if we don't find it initially.
1605 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1606 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1608 boolean checkRequiredParameters = true;
1610 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1611 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1612 checkRequiredParameters = false;
1613 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking...",
1614 MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1616 } catch (Exception e) {
1617 // No problem - default is true
1618 logger.debug("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1620 // 1604 - Add enhanced environment & parameter checking
1621 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1622 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1623 // Note this also removes any comments
1624 MsoHeatEnvironmentEntry mhee = null;
1625 if (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase().contains("parameters:")) {
1626 logger.debug("Enhanced environment checking enabled - 1604");
1627 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1628 mhee = new MsoHeatEnvironmentEntry(sb);
1629 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1630 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1631 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1633 if (!mhee.isValid()) {
1634 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1636 sb2.append("\nEnvironment:");
1637 sb2.append(mhee.toFullString());
1639 logger.debug(sb2.toString());
1641 logger.debug("NO ENVIRONMENT for this entry");
1643 // New for 1607 - support params of json type
1644 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1645 boolean hasJson = false;
1647 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1648 logger.debug("Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias="
1649 + parm.getParamAlias());
1651 String parameterType = parm.getParamType();
1652 if (parameterType == null || "".equals(parameterType.trim())) {
1653 parameterType = "String";
1655 JsonNode jsonNode = null;
1656 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1657 if (inputs.containsKey(parm.getParamName())) {
1659 String jsonString = null;
1661 jsonString = JSON_MAPPER.writeValueAsString(inputs.get(parm.getParamName()));
1662 jsonNode = JSON_MAPPER.readTree(jsonString);
1663 } catch (JsonParseException jpe) {
1664 // TODO - what to do here?
1665 // for now - send the error to debug
1666 logger.debug("Json Error Converting {} - {}", parm.getParamName(), jpe.getMessage(), jpe);
1669 } catch (Exception e) {
1671 logger.debug("Json Error Converting {} {}", parm.getParamName(), e.getMessage(), e);
1675 if (jsonNode != null) {
1676 jsonParams.put(parm.getParamName(), jsonNode);
1678 } else if (inputs.containsKey(parm.getParamAlias())) {
1680 String jsonString = null;
1682 jsonString = (String) inputs.get(parm.getParamAlias());
1683 jsonNode = JSON_MAPPER.readTree(jsonString);
1684 } catch (JsonParseException jpe) {
1685 // TODO - what to do here?
1686 // for now - send the error to debug, but just leave it as a String
1687 String errorMessage = jpe.getMessage();
1688 logger.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1691 } catch (Exception e) {
1693 logger.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1697 if (jsonNode != null) {
1698 // Notice here - we add it to the jsonParams hashMap with the actual name -
1699 // then manipulate the inputs so when we check for aliases below - it will not
1701 jsonParams.put(parm.getParamName(), jsonNode);
1702 inputs.remove(parm.getParamAlias());
1703 inputs.put(parm.getParamName(), jsonString);
1705 } // TODO add a check for the parameter in the env file
1708 if (parm.isRequired() && (inputs == null || !inputs.containsKey(parm.getParamName()))) {
1709 if (inputs.containsKey(parm.getParamAlias())) {
1710 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1711 String realParamName = parm.getParamName();
1712 String alias = parm.getParamAlias();
1713 Object value = inputs.get(alias);
1714 logger.debug("*Found an Alias: paramName=" + realParamName + ",alias=" + alias + ",value=" + value);
1715 inputs.remove(alias);
1716 inputs.put(realParamName, value);
1717 logger.debug("{} entry removed from inputs, added back using {}", alias, realParamName);
1719 // enhanced - check if it's in the Environment (note: that method
1720 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1722 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1723 parm.getParamName());
1725 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1726 if (missingParams == null) {
1727 missingParams = parm.getParamName();
1729 missingParams += "," + parm.getParamName();
1733 paramList.add(parm.getParamName());
1737 if (missingParams != null) {
1738 // Problem - missing one or more required parameters
1739 if (checkRequiredParameters) {
1740 String error = "Update VNF: Missing Required inputs: " + missingParams;
1741 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams, OPENSTACK,
1742 ErrorCode.DataError.getValue(), error);
1743 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1745 logger.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1749 // Just submit the envt entry as received from the database
1750 String newEnvironmentString = null;
1752 newEnvironmentString = mhee.getRawEntry().toString();
1754 // Remove any extraneous parameters (don't throw an error)
1755 if (inputs != null) {
1756 List<String> extraParams = new ArrayList<>();
1757 extraParams.addAll(inputs.keySet());
1758 // This is not a valid parameter for this template
1759 extraParams.removeAll(paramList);
1760 if (!extraParams.isEmpty()) {
1761 logger.warn(LoggingAnchor.SIX, MessageEnum.RA_VNF_EXTRA_PARAM.toString(), vnfType,
1762 extraParams.toString(), OPENSTACK, ErrorCode.DataError.getValue(), "Extra params");
1763 inputs.keySet().removeAll(extraParams);
1766 Map<String, Object> goldenInputs = copyStringInputs(inputs);
1767 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
1768 Map<String, Object> inputsTwo = null;
1769 if (hasJson && jsonParams.size() > 0) {
1770 inputsTwo = new HashMap<>();
1771 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
1772 String keyParamName = entry.getKey();
1773 Object value = entry.getValue();
1774 if (jsonParams.containsKey(keyParamName)) {
1775 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
1777 inputsTwo.put(keyParamName, value);
1780 goldenInputs = inputsTwo;
1783 // "Fix" the template if it has CR/LF (getting this from Oracle)
1784 String template = heatTemplate.getHeatTemplate();
1785 template = template.replaceAll("\r\n", "\n");
1787 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1788 boolean failRequestOnValetFailure =
1789 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1790 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1791 if (isVolumeRequest) {
1792 isValetEnabled = false;
1793 logger.debug("never send a volume request to valet");
1795 boolean sendResponseToValet = false;
1796 if (isValetEnabled) {
1797 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1798 String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1799 // Make sure it is set to something.
1800 if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) {
1801 parsedVfModuleName = "unknown";
1803 sendResponseToValet = this.valetUpdateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
1804 nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, goldenInputs,
1805 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1806 if (sendResponseToValet) {
1807 goldenInputs = valetModifiedParamsHolder.value;
1811 // Have the tenant. Now deploy the stack itself
1812 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1813 // because we already checked for those.
1815 heatStack = heatU.updateStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, template, goldenInputs, true,
1816 heatTemplate.getTimeoutMinutes(), newEnvironmentString,
1817 // heatEnvironmentString,
1818 nestedTemplatesChecked, heatFilesObjects);
1819 } catch (MsoException me) {
1820 me.addContext("UpdateVFModule");
1821 String error = "Update VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1823 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_UPDATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1824 cloudSiteId, tenantId, OPENSTACK, ErrorCode.DataError.getValue(), "Exception - " + error, me);
1825 if (isValetEnabled && sendResponseToValet) {
1826 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1828 GenericValetResponse<ValetRollbackResponse> gvr =
1829 this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage());
1830 // Nothing to really do here whether it succeeded or not other than log it.
1831 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1832 } catch (Exception e) {
1833 logger.error("Exception encountered while sending Rollback to Valet ", e);
1836 throw new VnfException(me);
1840 // Reach this point if updateStack is successful.
1841 // Populate remaining rollback info and response parameters.
1842 vfRollback.setVnfId(heatStack.getCanonicalName());
1843 vfRollback.setVnfCreated(true);
1845 if (isValetEnabled && sendResponseToValet) {
1846 logger.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id");
1848 GenericValetResponse<ValetConfirmResponse> gvr =
1849 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1850 // Nothing to really do here whether it succeeded or not other than log it.
1851 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1852 } catch (Exception e) {
1853 logger.error("Exception encountered while sending Confirm to Valet ", e);
1857 outputs.value = copyStringOutputs(heatStack.getOutputs());
1858 rollback.value = vfRollback;
1861 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
1862 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
1863 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
1864 if (vfModuleStackId == null)
1866 int index = vfModuleStackId.lastIndexOf('/');
1869 String vfModuleName = null;
1871 vfModuleName = vfModuleStackId.substring(0, index);
1872 } catch (Exception e) {
1873 logger.debug("Exception", e);
1874 vfModuleName = null;
1876 return vfModuleName;
1880 * Helper method to check a boolean property value - on error return provided default
1882 private boolean checkBooleanProperty(String propertyName, boolean defaultValue) {
1883 boolean property = defaultValue;
1885 String propertyString = this.environment.getProperty(propertyName);
1886 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1888 } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1891 } catch (Exception e) {
1892 logger.debug("An exception occured trying to get property {} - defaulting to ", propertyName, defaultValue,
1894 property = defaultValue;
1900 * Helper method to combine getFiles and nestedTemplates in to a single Map
1902 private Map<String, Object> combineGetFilesAndNestedTemplates(Map<String, Object> getFiles,
1903 Map<String, Object> nestedTemplates) {
1904 boolean haveGetFiles = true;
1905 boolean haveNestedTemplates = true;
1906 Map<String, Object> files = new HashMap<>();
1907 if (getFiles == null || getFiles.isEmpty()) {
1908 haveGetFiles = false;
1910 if (nestedTemplates == null || nestedTemplates.isEmpty()) {
1911 haveNestedTemplates = false;
1913 if (haveGetFiles && haveNestedTemplates) {
1914 for (String keyString : getFiles.keySet()) {
1915 files.put(keyString, getFiles.get(keyString));
1917 for (String keyString : nestedTemplates.keySet()) {
1918 files.put(keyString, nestedTemplates.get(keyString));
1921 // Handle if we only have one or neither:
1925 if (haveNestedTemplates) {
1926 files = nestedTemplates;
1933 * Valet Create request
1935 private boolean valetCreateRequest(String cloudSiteId, String cloudOwner, String tenantId,
1936 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
1937 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
1938 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure,
1939 Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
1940 boolean valetSucceeded = false;
1941 String valetErrorMessage = "more detail not available";
1943 String keystoneUrl = msoHeatUtils.getCloudSiteKeystoneUrl(cloudSiteId);
1944 Map<String, Object> files =
1945 this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked);
1946 HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(),
1947 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
1948 GenericValetResponse<ValetCreateResponse> createReq = this.vci.callValetCreateRequest(
1949 msoRequest.getRequestId(), cloudSiteId, cloudOwner, tenantId, msoRequest.getServiceInstanceId(),
1950 (String) inputs.get("vnf_id"), (String) inputs.get("vnf_name"), (String) inputs.get("vf_module_id"),
1951 (String) inputs.get("vf_module_name"), keystoneUrl, heatRequest);
1952 ValetCreateResponse vcr = createReq.getReturnObject();
1953 if (vcr != null && createReq.getStatusCode() == 200) {
1954 ValetStatus status = vcr.getStatus();
1955 if (status != null) {
1956 String statusCode = status.getStatus(); // "ok" or "failed"
1957 if ("ok".equalsIgnoreCase(statusCode)) {
1958 Map<String, Object> newInputs = vcr.getParameters();
1959 if (newInputs != null) {
1960 Map<String, Object> oldGold = goldenInputs;
1961 logger.debug("parameters before being modified by valet:{}", oldGold.toString());
1962 goldenInputs = new HashMap<>();
1963 for (String key : newInputs.keySet()) {
1964 goldenInputs.put(key, newInputs.get(key));
1966 valetModifiedParamsHolder.value = goldenInputs;
1967 logger.debug("parameters after being modified by valet:{}", goldenInputs.toString());
1968 valetSucceeded = true;
1971 valetErrorMessage = status.getMessage();
1975 logger.debug("Got a bad response back from valet");
1976 valetErrorMessage = "Bad response back from Valet";
1977 valetSucceeded = false;
1979 } catch (Exception e) {
1980 logger.error("An exception occurred trying to call valet ...", e);
1981 valetSucceeded = false;
1982 valetErrorMessage = e.getMessage();
1984 if (failRequestOnValetFailure && !valetSucceeded) {
1985 // The valet request failed - and property says to fail the request
1986 // TODO Create a new exception class for valet?
1987 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
1989 return valetSucceeded;
1993 * Valet update request
1996 private boolean valetUpdateRequest(String cloudSiteId, String cloudOwnerId, String tenantId,
1997 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
1998 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
1999 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure,
2000 Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2002 boolean valetSucceeded = false;
2003 String valetErrorMessage = "more detail not available";
2005 String keystoneUrl = msoHeatUtils.getCloudSiteKeystoneUrl(cloudSiteId);
2006 Map<String, Object> files =
2007 this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked);
2008 HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(),
2009 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2010 // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now
2011 GenericValetResponse<ValetUpdateResponse> updateReq =
2012 this.vci.callValetUpdateRequest(msoRequest.getRequestId(), cloudSiteId, cloudOwnerId, tenantId,
2013 msoRequest.getServiceInstanceId(), (String) inputs.get("vnf_id"), vfModuleName,
2014 (String) inputs.get("vf_module_id"), vfModuleName, keystoneUrl, heatRequest);
2015 ValetUpdateResponse vur = updateReq.getReturnObject();
2016 if (vur != null && updateReq.getStatusCode() == 200) {
2017 ValetStatus status = vur.getStatus();
2018 if (status != null) {
2019 String statusCode = status.getStatus(); // "ok" or "failed"
2020 if ("ok".equalsIgnoreCase(statusCode)) {
2021 Map<String, Object> newInputs = vur.getParameters();
2022 if (newInputs != null) {
2023 Map<String, Object> oldGold = goldenInputs;
2024 logger.debug("parameters before being modified by valet:{}", oldGold);
2025 goldenInputs = new HashMap<>();
2026 for (String key : newInputs.keySet()) {
2027 goldenInputs.put(key, newInputs.get(key));
2029 valetModifiedParamsHolder.value = goldenInputs;
2030 logger.debug("parameters after being modified by valet:{}", goldenInputs);
2031 valetSucceeded = true;
2034 valetErrorMessage = status.getMessage();
2038 logger.debug("Got a bad response back from valet");
2039 valetErrorMessage = "Got a bad response back from valet";
2040 valetSucceeded = false;
2042 } catch (Exception e) {
2043 logger.error("An exception occurred trying to call valet - will continue processing for now...", e);
2044 valetErrorMessage = e.getMessage();
2045 valetSucceeded = false;
2047 if (failRequestOnValetFailure && !valetSucceeded) {
2048 // The valet request failed - and property says to fail the request
2049 // TODO Create a new exception class for valet?
2050 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2052 return valetSucceeded;
2056 * Valet delete request
2058 private boolean valetDeleteRequest(String cloudSiteId, String cloudOwnerId, String tenantId, String vnfName,
2059 MsoRequest msoRequest, boolean failRequestOnValetFailure) {
2060 boolean valetDeleteRequestSucceeded = false;
2061 String valetErrorMessage = "more detail not available";
2063 String vfModuleId = vnfName;
2064 String vfModuleName = vnfName;
2066 vfModuleName = vnfName.substring(0, vnfName.indexOf('/'));
2067 vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1);
2068 } catch (Exception e) {
2069 // do nothing - send what we got for vnfName for both to valet
2070 logger.error("An exception occurred trying to call MsoVnfAdapterImpl.valetDeleteRequest() method", e);
2072 GenericValetResponse<ValetDeleteResponse> deleteReq = this.vci.callValetDeleteRequest(
2073 msoRequest.getRequestId(), cloudSiteId, cloudOwnerId, tenantId, vfModuleId, vfModuleName);
2074 ValetDeleteResponse vdr = deleteReq.getReturnObject();
2075 if (vdr != null && deleteReq.getStatusCode() == 200) {
2076 ValetStatus status = vdr.getStatus();
2077 if (status != null) {
2078 String statusCode = status.getStatus(); // "ok" or "failed"
2079 if ("ok".equalsIgnoreCase(statusCode)) {
2080 logger.debug("delete request to valet returned success");
2081 valetDeleteRequestSucceeded = true;
2083 logger.debug("delete request to valet returned failure");
2084 valetDeleteRequestSucceeded = false;
2085 valetErrorMessage = status.getMessage();
2089 logger.debug("Got a bad response back from valet - delete request failed");
2090 valetDeleteRequestSucceeded = false;
2091 valetErrorMessage = "Got a bad response back from valet - delete request failed";
2093 } catch (Exception e) {
2094 logger.error("An exception occurred trying to call valet - valetDeleteRequest failed", e);
2095 valetDeleteRequestSucceeded = false;
2096 valetErrorMessage = e.getMessage();
2098 if (!valetDeleteRequestSucceeded && failRequestOnValetFailure) {
2099 logger.error("ValetDeleteRequestFailed - del req still will be sent to openstack",
2100 new VnfException("ValetDeleteRequestFailedError"));
2102 return valetDeleteRequestSucceeded;