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.onap.so.logger.LoggingAnchor;
40 import org.apache.commons.collections.CollectionUtils;
41 import org.onap.so.adapters.valet.GenericValetResponse;
42 import org.onap.so.adapters.valet.ValetClient;
43 import org.onap.so.adapters.valet.beans.HeatRequest;
44 import org.onap.so.adapters.valet.beans.ValetConfirmResponse;
45 import org.onap.so.adapters.valet.beans.ValetCreateResponse;
46 import org.onap.so.adapters.valet.beans.ValetDeleteResponse;
47 import org.onap.so.adapters.valet.beans.ValetRollbackResponse;
48 import org.onap.so.adapters.valet.beans.ValetStatus;
49 import org.onap.so.adapters.valet.beans.ValetUpdateResponse;
50 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
51 import org.onap.so.adapters.vnf.exceptions.VnfException;
52 import org.onap.so.adapters.vnf.exceptions.VnfNotFound;
53 import org.onap.so.client.aai.AAIResourcesClient;
54 import org.onap.so.cloud.CloudConfig;
55 import org.onap.so.db.catalog.beans.CloudIdentity;
56 import org.onap.so.db.catalog.beans.CloudSite;
57 import org.onap.so.db.catalog.beans.HeatEnvironment;
58 import org.onap.so.db.catalog.beans.HeatFiles;
59 import org.onap.so.db.catalog.beans.HeatTemplate;
60 import org.onap.so.db.catalog.beans.HeatTemplateParam;
61 import org.onap.so.db.catalog.beans.VfModule;
62 import org.onap.so.db.catalog.beans.VfModuleCustomization;
63 import org.onap.so.db.catalog.beans.VnfResource;
64 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
65 import org.onap.so.db.catalog.data.repository.VnfResourceRepository;
66 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
67 import org.onap.so.entity.MsoRequest;
68 import org.onap.so.heatbridge.HeatBridgeApi;
69 import org.onap.so.heatbridge.HeatBridgeImpl;
70 import org.onap.so.logger.ErrorCode;
71 import org.onap.so.logger.MessageEnum;
72 import org.onap.so.openstack.beans.HeatStatus;
73 import org.onap.so.openstack.beans.StackInfo;
74 import org.onap.so.openstack.beans.VnfRollback;
75 import org.onap.so.openstack.beans.VnfStatus;
76 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
77 import org.onap.so.openstack.exceptions.MsoException;
78 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
79 import org.onap.so.openstack.exceptions.MsoHeatNotFoundException;
80 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
81 import org.onap.so.openstack.utils.MsoHeatUtils;
82 import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85 import org.springframework.beans.factory.annotation.Autowired;
86 import org.springframework.core.env.Environment;
87 import org.springframework.stereotype.Component;
88 import org.springframework.transaction.annotation.Transactional;
89 import com.fasterxml.jackson.core.JsonParseException;
90 import com.fasterxml.jackson.databind.JsonNode;
91 import com.fasterxml.jackson.databind.ObjectMapper;
92 import org.openstack4j.model.compute.Flavor;
93 import org.openstack4j.model.compute.Image;
94 import org.openstack4j.model.compute.Server;
95 import org.openstack4j.model.heat.Resource;
97 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
98 targetNamespace = "http://org.onap.so/vnf")
101 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
104 private CloudConfig cloudConfig;
107 private Environment environment;
109 private static final Logger logger = LoggerFactory.getLogger(MsoVnfAdapterImpl.class);
112 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
113 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
114 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq";
115 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
116 private static final String VALET_ENABLED = "org.onap.so.adapters.vnf.valet_enabled";
117 private static final String FAIL_REQUESTS_ON_VALET_FAILURE =
118 "org.onap.so.adapters.vnf.fail_requests_on_valet_failure";
119 private static final String OPENSTACK = "OpenStack";
120 private static final String DELETE_VNF = "DeleteVNF";
121 private static final String QUERY_STACK = "QueryStack";
122 private static final String CREATE_VFM_MODULE = "CreateVFModule";
123 private static final String CREATE_VF_STACK = "Create VF: Stack";
124 private static final String STACK = "Stack";
125 private static final String USER_ERROR = "USER ERROR";
126 private static final String VERSION_MIN = "VersionMin";
127 private static final String VERSION_MAX = "VersionMax";
130 private VFModuleCustomizationRepository vfModuleCustomRepo;
132 private VnfResourceRepository vnfResourceRepo;
134 private MsoHeatUtilsWithUpdate heatU;
136 private MsoHeatUtils heat;
138 private ValetClient vci;
141 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
143 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
145 public MsoVnfAdapterImpl() {
147 // DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
151 * Health Check web method. Does nothing but return to show the adapter is deployed.
154 public void healthCheck() {
155 logger.debug("Health check call in VNF Adapter");
159 * This is the "Create VNF" web service implementation. It will create a new VNF of the requested type in the
160 * specified cloud and tenant. The tenant must exist before this service is called.
162 * If a VNF with the same name already exists, this can be considered a success or failure, depending on the value
163 * of the 'failIfExists' parameter.
165 * All VNF types will be defined in the MSO catalog. The caller must request one of these pre-defined types or an
166 * error will be returned. Within the catalog, each VNF type references (among other things) a Heat template which
167 * is used to deploy the required VNF artifacts (VMs, networks, etc.) to the cloud.
169 * Depending on the Heat template, a variable set of input parameters will be defined, some of which are required.
170 * The caller is responsible to pass the necessary input data for the VNF or an error will be thrown.
172 * The method returns the vnfId (the canonical name), a Map of VNF output attributes, and a VnfRollback object. This
173 * last object can be passed as-is to the rollbackVnf operation to undo everything that was created for the VNF.
174 * This is useful if a VNF is successfully created but the orchestrator fails on a subsequent operation.
176 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
177 * @param cloudOwner cloud owner of the cloud region in which to create the VNF
178 * @param tenantId Openstack tenant identifier
179 * @param vnfType VNF type key, should match a VNF definition in catalog DB
180 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
181 * @param vnfName Name to be assigned to the new VNF
182 * @param inputs Map of key=value inputs for VNF stack creation
183 * @param failIfExists Flag whether already existing VNF should be considered a success or failure
184 * @param msoRequest Request tracking information for logs
185 * @param vnfId Holder for output VNF Openstack ID
186 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
187 * @param rollback Holder for returning VnfRollback object
190 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
191 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
192 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
193 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
194 // parameters used for multicloud adapter
195 String genericVnfId = "";
196 String vfModuleId = "";
197 // Create a hook here to catch shortcut createVf requests:
198 if (requestType != null && requestType.startsWith("VFMOD")) {
199 logger.debug("Calling createVfModule from createVnf -- requestType={}", requestType);
200 String newRequestType = requestType.substring(5);
201 String vfVolGroupHeatStackId = "";
202 String vfBaseHeatStackId = "";
204 if (volumeGroupHeatStackId != null) {
205 vfVolGroupHeatStackId =
206 volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf('|'));
207 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf('|') + 1);
209 } catch (Exception e) {
210 // might be ok - both are just blank
211 logger.debug("ERROR trying to parse the volumeGroupHeatStackId {}", volumeGroupHeatStackId, e);
213 this.createVfModule(cloudSiteId, cloudOwner, tenantId, vnfType, vnfVersion, genericVnfId, vnfName,
214 vfModuleId, newRequestType, vfVolGroupHeatStackId, vfBaseHeatStackId, null, inputs, failIfExists,
215 backout, enableBridge, msoRequest, vnfId, outputs, rollback);
218 // createVf will know if the requestType starts with "X" that it's the "old" way
219 StringBuilder newRequestTypeSb = new StringBuilder("X");
220 String vfVolGroupHeatStackId = "";
221 String vfBaseHeatStackId = "";
222 if (requestType != null) {
223 newRequestTypeSb.append(requestType);
225 this.createVfModule(cloudSiteId, cloudOwner, tenantId, vnfType, vnfVersion, genericVnfId, vnfName, vfModuleId,
226 newRequestTypeSb.toString(), vfVolGroupHeatStackId, vfBaseHeatStackId, null, inputs, failIfExists,
227 backout, enableBridge, msoRequest, vnfId, outputs, rollback);
229 // End createVf shortcut
233 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
234 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
235 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
236 throws VnfException {
237 // As of 1707 - this method should no longer be called
238 logger.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
242 * This is the "Query VNF" web service implementation. It will look up a VNF by name or ID in the specified cloud
245 * The method returns an indicator that the VNF exists, its Openstack internal ID, its status, and the set of
246 * outputs (from when the stack was created).
248 * @param cloudSiteId CLLI code of the cloud site in which to query
249 * @param tenantId Openstack tenant identifier
250 * @param vnfName VNF Name or Openstack ID
251 * @param msoRequest Request tracking information for logs
252 * @param vnfExists Flag reporting the result of the query
253 * @param vnfId Holder for output VNF Openstack ID
254 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
257 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
258 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
259 Holder<Map<String, String>> outputs) throws VnfException {
261 logger.debug("Querying VNF {} in {}/{}", vnfName, cloudSiteId, tenantId);
263 // Will capture execution time for metrics
267 heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vnfName);
268 } catch (MsoException me) {
269 me.addContext("QueryVNF");
270 // Failed to query the Stack due to an openstack exception.
271 // Convert to a generic VnfException
273 "Query VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
274 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudSiteId, tenantId,
275 OPENSTACK, "QueryVNF", ErrorCode.DataError.getValue(), "Exception - " + QUERY_STACK, me);
277 throw new VnfException(me);
280 // Populate the outputs based on the returned Stack information
282 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
284 vnfExists.value = Boolean.FALSE;
285 status.value = VnfStatus.NOTFOUND;
287 outputs.value = new HashMap<>(); // Return as an empty map
289 logger.debug("VNF {} not found", vnfName);
291 vnfExists.value = Boolean.TRUE;
292 status.value = stackStatusToVnfStatus(heatStack.getStatus());
293 vnfId.value = heatStack.getCanonicalName();
294 outputs.value = copyStringOutputs(heatStack.getOutputs());
296 logger.debug("VNF {} found, ID = {}", vnfName, vnfId.value);
302 * This is the "Delete VNF" web service implementation. It will delete a VNF by name or ID in the specified cloud
305 * The method has no outputs.
307 * @param cloudSiteId CLLI code of the cloud site in which to delete
308 * @param cloudOwner cloud owner of the cloud region in which to delete
309 * @param tenantId Openstack tenant identifier
310 * @param vnfName VNF Name or Openstack ID
311 * @param msoRequest Request tracking information for logs
314 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
315 throws VnfException {
317 logger.debug("Deleting VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
320 heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true);
321 } catch (MsoException me) {
322 me.addContext(DELETE_VNF);
323 // Failed to query the Stack due to an openstack exception.
324 // Convert to a generic VnfException
326 "Delete VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
327 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
328 tenantId, OPENSTACK, DELETE_VNF, ErrorCode.DataError.getValue(), "Exception - " + DELETE_VNF, me);
330 throw new VnfException(me);
333 // On success, nothing is returned.
338 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
339 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
340 * to undo the creation.
343 public void rollbackVnf(VnfRollback rollback) throws VnfException {
344 // rollback may be null (e.g. if stack already existed when Create was called)
345 if (rollback == null) {
346 logger.info(MessageEnum.RA_ROLLBACK_NULL.toString(), OPENSTACK, "rollbackVnf");
350 // Get the elements of the VnfRollback object for easier access
351 String cloudSiteId = rollback.getCloudSiteId();
352 String cloudOwner = rollback.getCloudOwner();
353 String tenantId = rollback.getTenantId();
354 String vnfId = rollback.getVnfId();
356 logger.debug("Rolling Back VNF {} in {}", vnfId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
358 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
359 // The possible outcomes of deleteStack are a StackInfo object with status
360 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
363 heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfId, true);
364 } catch (MsoException me) {
365 // Failed to rollback the Stack due to an openstack exception.
366 // Convert to a generic VnfException
367 me.addContext("RollbackVNF");
369 "Rollback VNF: " + vnfId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
370 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfId, cloudOwner, cloudSiteId,
371 tenantId, OPENSTACK, "DeleteStack", ErrorCode.DataError.getValue(), "Exception - DeleteStack", me);
373 throw new VnfException(me);
378 private VnfStatus stackStatusToVnfStatus(HeatStatus stackStatus) {
379 switch (stackStatus) {
381 return VnfStatus.ACTIVE;
383 return VnfStatus.ACTIVE;
385 return VnfStatus.FAILED;
387 return VnfStatus.UNKNOWN;
391 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
392 Map<String, String> stringOutputs = new HashMap<>();
393 for (Map.Entry<String, Object> entry : stackOutputs.entrySet()) {
394 String key = entry.getKey();
395 Object value = entry.getValue();
397 stringOutputs.put(key, value.toString());
398 } catch (Exception e) {
399 StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs");
400 if (value instanceof Integer) { // nothing to add to the message
401 } else if (value instanceof JsonNode) {
402 msg.append(" - exception converting JsonNode");
403 } else if (value instanceof java.util.LinkedHashMap) {
404 msg.append(" exception converting LinkedHashMap");
406 msg.append(" - unable to call .toString() " + e.getMessage());
408 logger.debug(msg.toString(), e);
411 return stringOutputs;
414 private Map<String, Object> copyStringInputs(Map<String, Object> stringInputs) {
415 return new HashMap<>(stringInputs);
418 protected boolean callHeatbridge(String heatStackId) {
419 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
420 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
421 long waitTimeMs = 10000L;
423 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password,
424 tenant, region, owner, heatStackId};
425 String[] envp = null;
426 File dir = new File(executionDir);
427 logger.debug("Calling HeatBridgeMain.py in {} with arguments {}", dir, Arrays.toString(cmdarray));
428 Runtime r = Runtime.getRuntime();
429 Process p = r.exec(cmdarray, envp, dir);
430 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
432 logger.debug(" HeatBridgeMain.py returned {} with code {}", wait, p.exitValue());
433 return wait && p.exitValue() == 0;
434 } catch (IOException e) {
435 logger.debug(" HeatBridgeMain.py failed with IO Exception! {}", e);
437 } catch (RuntimeException e) {
438 logger.debug(" HeatBridgeMain.py failed during runtime! {}", e);
440 } catch (Exception e) {
441 logger.debug(" HeatBridgeMain.py failed for unknown reasons! {}", e);
446 private void heatbridge(StackInfo heatStack, String cloudOwner, String cloudSiteId, String tenantId,
447 String genericVnfName, String vfModuleId) {
449 CloudSite cloudSite =
450 cloudConfig.getCloudSite(cloudSiteId).orElseThrow(() -> new MsoCloudSiteNotFound(cloudSiteId));
451 CloudIdentity cloudIdentity = cloudSite.getIdentityService();
452 String heatStackId = heatStack.getCanonicalName().split("/")[1];
454 List<String> oobMgtNetNames = new ArrayList<>();
456 HeatBridgeApi heatBridgeClient =
457 new HeatBridgeImpl(new AAIResourcesClient(), cloudIdentity, cloudOwner, cloudSiteId, tenantId);
459 List<Resource> stackResources = heatBridgeClient.queryNestedHeatStackResources(heatStackId);
461 List<Server> osServers = heatBridgeClient.getAllOpenstackServers(stackResources);
463 List<Image> osImages = heatBridgeClient.extractOpenstackImagesFromServers(osServers);
465 List<Flavor> osFlavors = heatBridgeClient.extractOpenstackFlavorsFromServers(osServers);
467 logger.debug("Successfully queried heat stack{} for resources.", heatStackId);
469 if (osImages != null && !osImages.isEmpty()) {
470 heatBridgeClient.buildAddImagesToAaiAction(osImages);
471 logger.debug("Successfully built AAI actions to add images.");
473 logger.debug("No images to update to AAI.");
476 if (osFlavors != null && !osFlavors.isEmpty()) {
477 heatBridgeClient.buildAddFlavorsToAaiAction(osFlavors);
478 logger.debug("Successfully built AAI actions to add flavors.");
480 logger.debug("No flavors to update to AAI.");
484 heatBridgeClient.buildAddVserversToAaiAction(genericVnfName, vfModuleId, osServers);
485 logger.debug("Successfully queried compute resources and built AAI vserver actions.");
488 List<String> oobMgtNetIds = new ArrayList<>();
490 // if no network-id list is provided, however network-name list is
491 if (!CollectionUtils.isEmpty(oobMgtNetNames)) {
492 oobMgtNetIds = heatBridgeClient.extractNetworkIds(oobMgtNetNames);
494 heatBridgeClient.buildAddVserverLInterfacesToAaiAction(stackResources, oobMgtNetIds);
496 "Successfully queried neutron resources and built AAI actions to add l-interfaces to vservers.");
499 heatBridgeClient.submitToAai();
500 } catch (Exception ex) {
501 logger.debug("Heatbrige failed for stackId: " + heatStack.getCanonicalName(), ex);
505 private String convertNode(final JsonNode node) {
507 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
508 return JSON_MAPPER.writeValueAsString(obj);
509 } catch (JsonParseException jpe) {
510 logger.debug("Error converting json to string: {}", jpe.getMessage(), jpe);
511 } catch (Exception e) {
512 logger.debug("Error converting json to string: {}", e.getMessage(), e);
514 return "[Error converting json to string]";
517 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
518 if (objectMap == null) {
521 Map<String, String> stringMap = new HashMap<>();
522 for (String key : objectMap.keySet()) {
523 if (!stringMap.containsKey(key)) {
524 Object obj = objectMap.get(key);
525 if (obj instanceof String) {
526 stringMap.put(key, (String) objectMap.get(key));
527 } else if (obj instanceof JsonNode) {
528 // This is a bit of mess - but I think it's the least impacting
529 // let's convert it BACK to a string - then it will get converted back later
531 String str = this.convertNode((JsonNode) obj);
532 stringMap.put(key, str);
533 } catch (Exception e) {
534 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
535 // okay in this instance - only string values (fqdn) are expected to be needed
537 } else if (obj instanceof java.util.LinkedHashMap) {
538 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
540 String str = JSON_MAPPER.writeValueAsString(obj);
541 stringMap.put(key, str);
542 } catch (Exception e) {
543 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
545 } else if (obj instanceof Integer) {
547 String str = "" + obj;
548 stringMap.put(key, str);
549 } catch (Exception e) {
550 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
554 String str = obj.toString();
555 stringMap.put(key, str);
556 } catch (Exception e) {
558 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")",
569 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
570 String vnfVersion, String genericVnfName, String vnfName, String vfModuleId, String requestType,
571 String volumeGroupHeatStackId, String baseVfHeatStackId, String modelCustomizationUuid,
572 Map<String, Object> inputs, Boolean failIfExists, Boolean backout, Boolean enableBridge,
573 MsoRequest msoRequest, Holder<String> vnfId, Holder<Map<String, String>> outputs,
574 Holder<VnfRollback> rollback) throws VnfException {
575 String vfModuleName = vnfName;
576 String vfModuleType = vnfType;
577 String vfVersion = vnfVersion;
578 String mcu = modelCustomizationUuid;
579 boolean useMCUuid = false;
580 if (mcu != null && !mcu.isEmpty()) {
581 if ("null".equalsIgnoreCase(mcu)) {
582 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: "
583 + modelCustomizationUuid);
587 logger.debug("Found modelCustomizationUuid! Will use that: {}", mcu);
592 String requestTypeString = "";
593 if (requestType != null && !"".equals(requestType)) {
594 requestTypeString = requestType;
596 String nestedStackId = null;
597 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)
598 && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
599 nestedStackId = volumeGroupHeatStackId;
601 String nestedBaseStackId = null;
602 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
603 nestedBaseStackId = baseVfHeatStackId;
606 // This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
607 boolean oldWay = false;
608 if (requestTypeString.startsWith("X")) {
610 logger.debug("orchestrating a VNF - *NOT* a module!");
611 requestTypeString = requestTypeString.substring(1);
614 // let's parse out the request type we're being sent
615 boolean isBaseRequest = false;
616 boolean isVolumeRequest = false;
617 if (requestTypeString.startsWith("VOLUME")) {
618 isVolumeRequest = true;
621 logger.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId
622 + ", nestedBaseStackId = " + nestedBaseStackId);
624 // Build a default rollback object (no actions performed)
625 VnfRollback vfRollback = new VnfRollback();
626 vfRollback.setCloudSiteId(cloudSiteId);
627 vfRollback.setCloudOwner(cloudOwner);
628 vfRollback.setTenantId(tenantId);
629 vfRollback.setMsoRequest(msoRequest);
630 vfRollback.setRequestType(requestTypeString);
631 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
632 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
633 vfRollback.setIsBase(isBaseRequest);
634 vfRollback.setModelCustomizationUuid(mcu);
636 // Put data into A&AI through Heatstack
637 if (enableBridge != null && enableBridge) {
638 callHeatbridge(baseVfHeatStackId);
641 StackInfo heatStack = null;
643 heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName);
644 } catch (MsoException me) {
645 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
646 + tenantId + ": " + me;
647 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
648 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
649 "Exception - " + QUERY_STACK, 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 throw new VnfException(me);
656 // more precise handling/messaging if the stack already exists
657 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
658 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
659 HeatStatus status = heatStack.getStatus();
660 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING
661 || status == HeatStatus.UPDATING) {
662 // fail - it's in progress - return meaningful error
663 String error = CREATE_VF_STACK + " " + vfModuleName + " already exists and has status "
664 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
665 + "; please wait for it to complete, or fix manually.";
666 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
667 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
668 STACK + " " + vfModuleName + " already exists");
670 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
671 heatStack.getCanonicalName());
673 if (status == HeatStatus.FAILED) {
674 // fail - it exists and is in a FAILED state
675 String error = CREATE_VF_STACK + " " + vfModuleName + " already exists and is in FAILED state in "
676 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
677 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
678 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
679 STACK + " " + vfModuleName + " already exists and is " + "in FAILED state");
681 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
682 heatStack.getCanonicalName());
684 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
685 // fail - it exists and is in a FAILED state
686 String error = CREATE_VF_STACK + " " + vfModuleName + " already exists and has status "
687 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
688 + "; requires manual intervention.";
689 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner,
690 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
691 STACK + " " + vfModuleName + " already exists and is " + "in UPDATED or UNKNOWN state");
693 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
694 heatStack.getCanonicalName());
696 if (status == HeatStatus.CREATED) {
698 if (failIfExists != null && failIfExists) {
699 String error = CREATE_VF_STACK + " " + vfModuleName + " already exists in " + cloudOwner + "/"
700 + cloudSiteId + "/" + tenantId;
701 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
702 cloudOwner, cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
703 STACK + " " + vfModuleName + " already exists");
705 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
706 heatStack.getCanonicalName());
708 logger.debug("Found Existing stack, status={}", heatStack.getStatus());
709 // Populate the outputs from the existing stack.
710 vnfId.value = heatStack.getCanonicalName();
711 outputs.value = copyStringOutputs(heatStack.getOutputs());
712 rollback.value = vfRollback; // Default rollback - no updates performed
719 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
720 StackInfo nestedHeatStack = null;
722 Map<String, Object> nestedVolumeOutputs = null;
723 if (nestedStackId != null) {
725 logger.debug("Querying for nestedStackId = {}", nestedStackId);
726 nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
727 } catch (MsoException me) {
728 // Failed to query the Stack due to an openstack exception.
729 // Convert to a generic VnfException
730 me.addContext(CREATE_VFM_MODULE);
731 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner
732 + "/" + cloudSiteId + "/" + tenantId + ": " + me;
733 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
734 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcesssError.getValue(),
735 "MsoException trying to query nested stack", me);
736 logger.debug("ERROR trying to query nested stack= {}", error);
737 throw new VnfException(me);
739 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
740 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in "
741 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
742 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
743 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK,
744 ErrorCode.BusinessProcesssError.getValue(),
745 "Create VFModule: Attached heatStack ID " + "DOES NOT EXIST");
747 throw new VnfException(error, MsoExceptionCategory.USERDATA);
749 logger.debug("Found nested volume heat stack - copying values to inputs *later*");
750 nestedVolumeOutputs = nestedHeatStack.getOutputs();
754 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
755 StackInfo nestedBaseHeatStack = null;
756 Map<String, Object> baseStackOutputs = null;
757 if (nestedBaseStackId != null) {
759 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
760 nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
761 } catch (MsoException me) {
762 // Failed to query the Stack due to an openstack exception.
763 // Convert to a generic VnfException
764 me.addContext(CREATE_VFM_MODULE);
765 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in "
766 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
767 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
768 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcesssError.getValue(),
769 "MsoException trying to query nested base stack", me);
770 logger.debug("ERROR trying to query nested base stack= {}", error);
771 throw new VnfException(me);
773 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
774 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId
775 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
776 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
777 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK,
778 ErrorCode.BusinessProcesssError.getValue(),
779 "Create VFModule: Attached base heatStack ID DOES NOT EXIST");
780 logger.debug("Exception occurred", error);
781 throw new VnfException(error, MsoExceptionCategory.USERDATA);
783 logger.debug("Found nested base heat stack - these values will be copied to inputs *later*");
784 baseStackOutputs = nestedBaseHeatStack.getOutputs();
791 VnfResource vnfResource = null;
792 VfModuleCustomization vfmc = null;
794 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(mcu);
796 vf = vfmc.getVfModule();
800 // this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
802 logger.debug("Unable to find vfModuleCust with modelCustomizationUuid={}", mcu);
804 "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
805 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
806 "VF Module ModelCustomizationUuid", modelCustomizationUuid, OPENSTACK,
807 ErrorCode.DataError.getValue(),
808 "Create VF Module: Unable to find vfModule with " + "modelCustomizationUuid=" + mcu);
810 throw new VnfException(error, MsoExceptionCategory.USERDATA);
812 logger.trace("Found vfModuleCust entry {}", vfmc.toString());
814 if (vf.getIsBase()) {
815 isBaseRequest = true;
816 logger.debug("This is a BASE VF request!");
818 logger.debug("This is *not* a BASE VF request!");
819 if (!isVolumeRequest && nestedBaseStackId == null) {
821 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
826 else { // This is to support gamma only - get info from vnf_resource table
827 if (vfVersion != null && !vfVersion.isEmpty()) {
828 vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion);
830 vnfResource = vnfResourceRepo.findByModelName(vnfType);
832 if (vnfResource == null) {
833 String error = "Create VNF: Unknown VNF Type: " + vnfType;
834 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VNF Type", vnfType,
835 OPENSTACK, ErrorCode.DataError.getValue(), "Create VNF: Unknown VNF Type");
837 throw new VnfException(error, MsoExceptionCategory.USERDATA);
839 logger.debug("Got VNF module definition from Catalog: {}", vnfResource.toString());
841 // By here - we have either a vf or vnfResource
844 // First - see if it's in the VnfResource record
845 // if we have a vf Module - then we have to query to get the VnfResource record.
848 vnfResource = vf.getVnfResources();
850 if (vnfResource == null) {
851 logger.debug("Unable to find vnfResource will not error for now...");
854 String minVersionVnf = null;
855 String maxVersionVnf = null;
856 if (vnfResource != null) {
858 minVersionVnf = vnfResource.getAicVersionMin();
859 maxVersionVnf = vnfResource.getAicVersionMax();
860 } catch (Exception e) {
861 logger.debug("Unable to pull min/max version for this VNF Resource entry", e);
862 minVersionVnf = null;
863 maxVersionVnf = null;
865 if (minVersionVnf != null && "".equals(minVersionVnf)) {
866 minVersionVnf = null;
868 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
869 maxVersionVnf = null;
872 if (minVersionVnf != null && maxVersionVnf != null) {
873 MavenLikeVersioning aicV = new MavenLikeVersioning();
876 if (this.cloudConfig != null) {
877 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
878 if (cloudSiteOpt.isPresent()) {
879 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
880 // Add code to handle unexpected values in here
881 boolean moreThanMin = true;
882 boolean equalToMin = true;
883 boolean moreThanMax = true;
884 boolean equalToMax = true;
885 boolean doNotTest = false;
887 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
888 equalToMin = aicV.isTheSameVersion(minVersionVnf);
889 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
890 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
891 } catch (Exception e) {
893 "An exception occurred while trying to test Cloud Version {} - will default to not check",
898 if ((moreThanMin || equalToMin) // aic >= min
899 && (equalToMax || !(moreThanMax))) { // aic <= max
900 logger.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid="
901 + vnfResource.getModelUUID() + " " + VERSION_MIN + " =" + minVersionVnf + " "
902 + VERSION_MAX + " :" + maxVersionVnf + " supported on Cloud: " + cloudSiteId
903 + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion());
906 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
907 + vnfResource.getModelUUID() + " " + VERSION_MIN + " =" + minVersionVnf + " "
908 + VERSION_MAX + " :" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId
909 + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion();
910 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK,
911 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
913 throw new VnfException(error, MsoExceptionCategory.USERDATA);
916 logger.debug("bypassing testing Cloud version...");
918 } // let this error out downstream to avoid introducing uncertainty at this stage
920 logger.debug("cloudConfig is NULL - cannot check cloud site version");
924 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
925 HeatTemplate heatTemplate = null;
926 HeatEnvironment heatEnvironment = null;
928 // This will handle old Gamma BrocadeVCE VNF
929 heatTemplate = vnfResource.getHeatTemplates();
932 if (isVolumeRequest) {
933 heatTemplate = vf.getVolumeHeatTemplate();
934 heatEnvironment = vfmc.getVolumeHeatEnv();
936 heatTemplate = vf.getModuleHeatTemplate();
937 heatEnvironment = vfmc.getHeatEnvironment();
942 if (heatTemplate == null) {
943 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
944 + ", modelCustomizationUuid=" + mcu + ", vfModuleUuid="
945 + (vf != null ? vf.getModelUUID() : "null") + ", vnfResourceModelUuid="
946 + vnfResource.getModelUUID() + ", reqType=" + requestTypeString;
947 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template " + "ID",
948 vfModuleType, OPENSTACK, ErrorCode.DataError.getValue(), error);
950 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
952 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
956 // This will handle old Gamma BrocadeVCE VNF
957 logger.debug("No environment parameter found for this Type " + vfModuleType);
959 if (heatEnvironment == null) {
960 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
961 + ", modelCustomizationUuid=" + mcu + ", vfModuleUuid="
962 + (vf != null ? vf.getModelUUID() : "null") + ", vnfResourceModelUuid="
963 + vnfResource.getModelUUID() + ", reqType=" + requestTypeString;
964 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
965 "Heat " + "Environment ID", OPENSTACK, ErrorCode.DataError.getValue(), error);
967 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
969 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
973 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
974 + heatTemplate.getArtifactUuid());
977 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
978 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
979 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
980 // for debugging print them out
981 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
982 for (HeatTemplate entry : nestedTemplates) {
983 nestedTemplatesChecked.put(entry.getTemplateName(), entry.getTemplateBody());
984 logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody());
987 logger.debug("No nested templates found - nothing to do here");
988 nestedTemplatesChecked = null;
991 // Also add the files: for any get_files associated with this vnf_resource_id
992 // *if* there are any
993 List<HeatFiles> heatFiles = null;
995 Map<String, Object> heatFilesObjects = new HashMap<>();
997 // Add ability to turn on adding get_files with volume requests (by property).
998 boolean addGetFilesOnVolumeReq = false;
1000 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1001 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1002 addGetFilesOnVolumeReq = true;
1003 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
1005 } catch (Exception e) {
1006 logger.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1007 + " - default to false", e);
1010 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1012 logger.debug("In MsoVnfAdapterImpl createVfModule, this should not happen, no heat files!");
1014 // now use VF_MODULE_TO_HEAT_FILES table
1016 "In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1017 + vf.getModelUUID());
1018 heatFiles = vf.getHeatFiles();
1020 if (heatFiles != null && !heatFiles.isEmpty()) {
1021 // add these to stack - to be done in createStack
1022 // here, we will map them to Map<String, Object> from
1023 // Map<String, HeatFiles>
1024 // this will match the nested templates format
1025 logger.debug("Contents of heatFiles - to be added to files: on stack");
1027 for (HeatFiles heatfile : heatFiles) {
1028 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
1029 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1032 logger.debug("No heat files found -nothing to do here");
1033 heatFilesObjects = null;
1037 // Check that required parameters have been supplied
1038 String missingParams = null;
1039 List<String> paramList = new ArrayList<>();
1041 // consult the PARAM_ALIAS field to see if we've been
1042 // supplied an alias. Only check if we don't find it initially.
1043 // don't flag missing parameters if there's an environment - because they might be there.
1044 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1046 boolean checkRequiredParameters = true;
1048 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1049 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1050 checkRequiredParameters = false;
1051 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1052 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1054 } catch (Exception e) {
1055 // No problem - default is true
1056 logger.debug("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1058 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1059 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1060 // Note this also removes any comments
1061 MsoHeatEnvironmentEntry mhee = null;
1062 if (heatEnvironment != null && heatEnvironment.getEnvironment() != null
1063 && heatEnvironment.getEnvironment().contains("parameters:")) {
1065 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1067 mhee = new MsoHeatEnvironmentEntry(sb);
1068 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1069 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1070 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1072 if (!mhee.isValid()) {
1073 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1075 sb2.append("\nEnvironment:");
1076 sb2.append(mhee.toFullString());
1078 logger.debug(sb2.toString());
1080 logger.debug("NO ENVIRONMENT for this entry");
1082 // all variables converted to their native object types
1083 Map<String, Object> goldenInputs = null;
1085 ArrayList<String> parameterNames = new ArrayList<>();
1086 HashMap<String, String> aliasToParam = new HashMap<>();
1087 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1090 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1091 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1092 parameterNames.add(htp.getParamName());
1093 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1094 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1095 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1099 logger.debug(sb.toString());
1100 } catch (Exception e) {
1101 logger.debug("??An exception occurred trying to go through Parameter Names {}", e.getMessage(), e);
1103 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1104 // Map<String, Object> - where the object matches the param type identified in the template
1105 // This will also not copy over params that aren't identified in the template
1106 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1107 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1108 logger.debug("Now add in the base stack outputs if applicable");
1109 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1110 // Step 3 - add the volume inputs if any
1111 logger.debug("Now add in the volume stack outputs if applicable");
1112 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1114 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1115 logger.debug("Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias="
1116 + parm.getParamAlias());
1118 if (parm.isRequired() && (goldenInputs == null || !goldenInputs.containsKey(parm.getParamName()))) {
1119 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the
1120 // Map<String, String> to Map<String, Object>
1121 logger.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check "
1123 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1124 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1125 parm.getParamName());
1127 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1128 if (missingParams == null) {
1129 missingParams = parm.getParamName();
1131 missingParams += "," + parm.getParamName();
1135 paramList.add(parm.getParamName());
1137 if (missingParams != null) {
1138 if (checkRequiredParameters) {
1139 // Problem - missing one or more required parameters
1140 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1141 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams, OPENSTACK,
1142 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1143 logger.debug(error);
1144 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1146 logger.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1149 logger.debug("No missing parameters found - ok to proceed");
1151 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1152 // and it causes problems with json that has arrays
1153 String newEnvironmentString = null;
1155 newEnvironmentString = mhee.getRawEntry().toString();
1158 // "Fix" the template if it has CR/LF (getting this from Oracle)
1159 String template = heatTemplate.getHeatTemplate();
1160 template = template.replaceAll("\r\n", "\n");
1163 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1164 boolean failRequestOnValetFailure =
1165 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1166 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1167 if (oldWay || isVolumeRequest) {
1168 isValetEnabled = false;
1169 logger.debug("do not send to valet for volume requests or brocade");
1171 boolean sendResponseToValet = false;
1172 if (isValetEnabled) {
1173 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1174 sendResponseToValet = this.valetCreateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
1175 nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs,
1176 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1177 if (sendResponseToValet) {
1178 goldenInputs = valetModifiedParamsHolder.value;
1182 // Have the tenant. Now deploy the stack itself
1183 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1184 // because we already checked for those.
1186 if (backout == null) {
1191 heatStack = heat.createStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, null, template,
1192 goldenInputs, true, heatTemplate.getTimeoutMinutes(), newEnvironmentString,
1193 nestedTemplatesChecked, heatFilesObjects, backout.booleanValue());
1195 throw new MsoHeatNotFoundException();
1197 } catch (MsoException me) {
1198 me.addContext(CREATE_VFM_MODULE);
1199 logger.error("Error creating Stack", me);
1200 if (isValetEnabled && sendResponseToValet) {
1201 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1203 GenericValetResponse<ValetRollbackResponse> gvr = this.vci
1204 .callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage());
1205 // Nothing to really do here whether it succeeded or not other than log it.
1206 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1207 } catch (Exception e) {
1208 logger.error("Exception encountered while sending Rollback to Valet ", e);
1211 throw new VnfException(me);
1212 } catch (NullPointerException npe) {
1213 logger.error("Error creating Stack", npe);
1214 throw new VnfException("NullPointerException during heat.createStack");
1215 } catch (Exception e) {
1216 logger.error("Error creating Stack", e);
1217 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1219 // Reach this point if createStack is successful.
1220 // Populate remaining rollback info and response parameters.
1221 vfRollback.setVnfId(heatStack.getCanonicalName());
1222 vfRollback.setVnfCreated(true);
1224 vnfId.value = heatStack.getCanonicalName();
1225 outputs.value = copyStringOutputs(heatStack.getOutputs());
1226 rollback.value = vfRollback;
1227 if (isValetEnabled && sendResponseToValet) {
1228 logger.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id");
1230 GenericValetResponse<ValetConfirmResponse> gvr =
1231 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1232 // Nothing to really do here whether it succeeded or not other than log it.
1233 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1234 } catch (Exception e) {
1235 logger.error("Exception encountered while sending Confirm to Valet ", e);
1238 logger.debug("VF Module {} successfully created", vfModuleName);
1240 heatbridge(heatStack, cloudOwner, cloudSiteId, tenantId, genericVnfName, vfModuleId);
1241 } catch (Exception e) {
1242 logger.debug("unhandled exception in create VF", e);
1243 throw new VnfException("Exception during create VF " + e.getMessage());
1248 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1249 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1251 logger.debug("Deleting VF {} in ", vnfName, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1252 // Will capture execution time for metrics
1254 // 1702 capture the output parameters on a delete
1255 // so we'll need to query first
1256 Map<String, Object> stackOutputs;
1258 stackOutputs = heat.queryStackForOutputs(cloudSiteId, cloudOwner, tenantId, vnfName);
1259 } catch (MsoException me) {
1260 // Failed to query the Stack due to an openstack exception.
1261 // Convert to a generic VnfException
1262 me.addContext("DeleteVFModule");
1263 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1264 + "/" + tenantId + ": " + me;
1265 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1266 tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), "Exception - " + QUERY_STACK, me);
1267 logger.debug(error);
1268 throw new VnfException(me);
1270 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1272 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1274 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1275 boolean failRequestOnValetFailure =
1276 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1277 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1278 boolean valetDeleteRequestSucceeded = false;
1279 if (isValetEnabled) {
1280 valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, cloudOwner, tenantId, vnfName,
1281 msoRequest, failRequestOnValetFailure);
1285 heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true);
1286 } catch (MsoException me) {
1287 me.addContext(DELETE_VNF);
1288 // Failed to query the Stack due to an openstack exception.
1289 // Convert to a generic VnfException
1291 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1292 logger.error(LoggingAnchor.NINE, MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1293 tenantId, OPENSTACK, "DeleteStack", ErrorCode.DataError.getValue(), "Exception - deleteStack", me);
1294 logger.debug(error);
1295 if (isValetEnabled && valetDeleteRequestSucceeded) {
1296 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1298 GenericValetResponse<ValetRollbackResponse> gvr = this.vci
1299 .callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage());
1300 // Nothing to really do here whether it succeeded or not other than log it.
1301 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1302 } catch (Exception e) {
1303 logger.error("Exception encountered while sending Rollback to Valet ", e);
1306 throw new VnfException(me);
1308 if (isValetEnabled && valetDeleteRequestSucceeded) {
1309 // only if the original request succeeded do we send a confirm
1310 logger.debug("valet is enabled, the delete succeeded - now send confirm to valet");
1312 GenericValetResponse<ValetConfirmResponse> gvr =
1313 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName);
1314 // Nothing to really do here whether it succeeded or not other than log it.
1315 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1316 } catch (Exception e) {
1317 logger.error("Exception encountered while sending Confirm to Valet ", e);
1321 // On success, nothing is returned.
1326 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1327 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1328 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1329 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1330 throws VnfException {
1331 String vfModuleName = vnfName;
1332 String vfModuleType = vnfType;
1333 String methodName = "updateVfModule";
1334 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1336 StringBuilder sbInit = new StringBuilder();
1337 sbInit.append("updateVfModule: \n");
1338 sbInit.append("cloudOwner=" + cloudOwner + "\n");
1339 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1340 sbInit.append("tenantId=" + tenantId + "\n");
1341 sbInit.append("vnfType=" + vnfType + "\n");
1342 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1343 sbInit.append("vnfName=" + vnfName + "\n");
1344 sbInit.append("requestType=" + requestType + "\n");
1345 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1346 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1347 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1348 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1349 logger.debug(sbInit.toString());
1351 String mcu = modelCustomizationUuid;
1352 boolean useMCUuid = false;
1353 if (mcu != null && !mcu.isEmpty()) {
1354 if ("null".equalsIgnoreCase(mcu)) {
1355 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: {}",
1356 modelCustomizationUuid);
1360 logger.debug("Found modelCustomizationUuid! Will use that: {}", mcu);
1365 String requestTypeString = "";
1366 if (requestType != null && !"".equals(requestType)) {
1367 requestTypeString = requestType;
1370 String nestedStackId = null;
1371 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)
1372 && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1373 nestedStackId = volumeGroupHeatStackId;
1375 String nestedBaseStackId = null;
1376 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
1377 nestedBaseStackId = baseVfHeatStackId;
1380 if (inputs == null) {
1381 // Create an empty set of inputs
1382 inputs = new HashMap<>();
1383 logger.debug("inputs == null - setting to empty");
1386 boolean isBaseRequest = false;
1387 boolean isVolumeRequest = false;
1388 if (requestTypeString.startsWith("VOLUME")) {
1389 isVolumeRequest = true;
1391 if ((vfModuleName == null || "".equals(vfModuleName.trim())) && vfModuleStackId != null) {
1392 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1395 logger.debug("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudOwner + "/"
1396 + cloudSiteId + "/" + tenantId);
1397 logger.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId
1398 + ", nestedBaseStackId = " + nestedBaseStackId);
1400 // Build a default rollback object (no actions performed)
1401 VnfRollback vfRollback = new VnfRollback();
1402 vfRollback.setCloudSiteId(cloudSiteId);
1403 vfRollback.setCloudOwner(cloudOwner);
1404 vfRollback.setTenantId(tenantId);
1405 vfRollback.setMsoRequest(msoRequest);
1406 vfRollback.setRequestType(requestTypeString);
1407 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1408 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1409 vfRollback.setIsBase(isBaseRequest);
1410 vfRollback.setVfModuleStackId(vfModuleStackId);
1411 vfRollback.setModelCustomizationUuid(mcu);
1413 StackInfo heatStack;
1414 logger.debug("UpdateVfModule - querying for {}", vfModuleName);
1416 heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName);
1417 } catch (MsoException me) {
1418 // Failed to query the Stack due to an openstack exception.
1419 // Convert to a generic VnfException
1420 me.addContext("UpdateVFModule");
1421 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
1422 + tenantId + ": " + me;
1423 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
1424 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
1425 "Exception - " + QUERY_STACK, me);
1426 logger.debug(error);
1427 throw new VnfException(me);
1430 // TODO - do we need to check for the other status possibilities?
1431 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
1433 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudOwner + "/" + cloudSiteId
1435 logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_NOT_EXIST.toString(), vfModuleName, cloudOwner,
1436 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), error);
1437 throw new VnfNotFound(cloudSiteId, cloudOwner, tenantId, vfModuleName);
1439 logger.debug("Found Existing stack, status={}", heatStack.getStatus());
1440 // Populate the outputs from the existing stack.
1441 outputs.value = copyStringOutputs(heatStack.getOutputs());
1442 rollback.value = vfRollback; // Default rollback - no updates performed
1445 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1446 StackInfo nestedHeatStack = null;
1447 Map<String, Object> nestedVolumeOutputs = null;
1448 if (nestedStackId != null) {
1450 logger.debug("Querying for nestedStackId = {}", nestedStackId);
1451 nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
1452 } catch (MsoException me) {
1453 // Failed to query the Stack due to an openstack exception.
1454 // Convert to a generic VnfException
1455 me.addContext("UpdateVFModule");
1456 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner + "/"
1457 + cloudSiteId + "/" + tenantId + ": " + me;
1458 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1459 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
1460 "Exception - " + error, me);
1461 logger.debug("ERROR trying to query nested stack= {}", error);
1462 throw new VnfException(me);
1464 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1465 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in "
1466 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
1467 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1468 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), error);
1469 logger.debug(error);
1470 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1472 logger.debug("Found nested heat stack - copying values to inputs *later*");
1473 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1474 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1477 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1478 StackInfo nestedBaseHeatStack = null;
1479 Map<String, Object> baseStackOutputs = null;
1480 if (nestedBaseStackId != null) {
1482 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
1483 nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
1484 } catch (MsoException me) {
1485 // Failed to query the Stack due to an openstack exception.
1486 // Convert to a generic VnfException
1487 me.addContext("UpdateVfModule");
1488 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in "
1489 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1490 logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
1491 cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(),
1492 "Exception - " + error, me);
1493 logger.debug("ERROR trying to query nested base stack= {}", error);
1494 throw new VnfException(me);
1496 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1497 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId
1498 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR;
1499 logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner,
1500 cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), error);
1501 logger.debug(error);
1502 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1504 logger.debug("Found nested base heat stack - copying values to inputs *later*");
1505 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1506 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1510 // Ready to deploy the new VNF
1514 // Retrieve the VF definition
1515 VnfResource vnfResource = null;
1517 VfModuleCustomization vfmc = null;
1519 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
1520 vf = vfmc != null ? vfmc.getVfModule() : null;
1522 logger.debug("Unable to find a vfModule matching modelCustomizationUuid={}", mcu);
1525 logger.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1528 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1529 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VF Module Type", vfModuleType,
1530 OPENSTACK, ErrorCode.DataError.getValue(), error);
1531 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1533 logger.debug("Got VF module definition from Catalog: {}", vf.toString());
1534 if (vf.getIsBase()) {
1535 isBaseRequest = true;
1536 logger.debug("This a BASE update request");
1538 logger.debug("This is *not* a BASE VF update request");
1539 if (!isVolumeRequest && nestedBaseStackId == null) {
1541 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1545 // 1607 - Add version check
1546 // First - see if it's in the VnfResource record
1547 // if we have a vf Module - then we have to query to get the VnfResource record.
1548 if (vf.getModelUUID() != null) {
1549 String vnfResourceModelUuid = vf.getModelUUID();
1551 vnfResource = vf.getVnfResources();
1552 if (vnfResource == null) {
1553 logger.debug("Unable to find vnfResource at ? will not error for now...", vnfResourceModelUuid);
1557 String minVersionVnf = null;
1558 String maxVersionVnf = null;
1559 if (vnfResource != null) {
1561 minVersionVnf = vnfResource.getAicVersionMin();
1562 maxVersionVnf = vnfResource.getAicVersionMax();
1563 } catch (Exception e) {
1564 logger.debug("Unable to pull min/max version for this VNF Resource entry", e);
1565 minVersionVnf = null;
1566 maxVersionVnf = null;
1568 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1569 minVersionVnf = null;
1571 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1572 maxVersionVnf = null;
1575 if (minVersionVnf != null && maxVersionVnf != null) {
1576 MavenLikeVersioning aicV = new MavenLikeVersioning();
1579 if (this.cloudConfig != null) {
1580 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1581 if (cloudSiteOpt.isPresent()) {
1582 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
1583 boolean moreThanMin = true;
1584 boolean equalToMin = true;
1585 boolean moreThanMax = true;
1586 boolean equalToMax = true;
1587 boolean doNotTest = false;
1589 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1590 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1591 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1592 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1593 } catch (Exception e) {
1595 "An exception occured while trying to test AIC Version {} - will default to not check",
1600 if ((moreThanMin || equalToMin) // aic >= min
1601 && ((equalToMax) || !(moreThanMax))) { // aic <= max
1602 logger.debug("VNF Resource " + vnfResource.getModelName() + " " + VERSION_MIN + " ="
1603 + minVersionVnf + " " + VERSION_MAX + " :" + maxVersionVnf + " supported on Cloud: "
1604 + cloudSiteId + " with AIC_Version:" + aicV);
1607 String error = "VNF Resource type: " + vnfResource.getModelName() + " " + VERSION_MIN + " ="
1608 + minVersionVnf + " " + VERSION_MAX + " :" + maxVersionVnf
1609 + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + aicV;
1610 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK,
1611 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
1612 logger.debug(error);
1613 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1616 logger.debug("bypassing testing AIC version...");
1618 } // let this error out downstream to avoid introducing uncertainty at this stage
1620 logger.debug("cloudConfig is NULL - cannot check cloud site version");
1624 logger.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1626 // End Version check 1607
1628 HeatTemplate heatTemplate = null;
1629 HeatEnvironment heatEnvironment = null;
1630 if (isVolumeRequest) {
1631 heatTemplate = vf.getVolumeHeatTemplate();
1632 heatEnvironment = vfmc.getVolumeHeatEnv();
1634 heatTemplate = vf.getModuleHeatTemplate();
1635 heatEnvironment = vfmc.getHeatEnvironment();
1638 if (heatTemplate == null) {
1639 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
1640 + ", modelCustomizationUuid=" + mcu + ", vfModuleUuid=" + vf.getModelUUID() + ", reqType="
1641 + requestTypeString;
1642 logger.error(LoggingAnchor.SIX, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
1643 vfModuleType, OPENSTACK, ErrorCode.DataError.getValue(), error);
1644 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1646 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
1649 if (heatEnvironment == null) {
1650 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + ", modelCustomizationUuid="
1651 + mcu + ", vfModuleUuid=" + vf.getModelUUID() + ", reqType=" + requestTypeString;
1652 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
1653 OPENSTACK, ErrorCode.DataError.getValue(), error);
1654 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1656 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
1659 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId={}",
1660 heatTemplate.getArtifactUuid());
1663 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1664 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1665 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1666 // for debugging print them out
1667 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
1668 for (HeatTemplate entry : nestedTemplates) {
1670 nestedTemplatesChecked.put(entry.getTemplateName(), entry.getTemplateBody());
1671 logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody());
1674 logger.debug("No nested templates found - nothing to do here");
1675 nestedTemplatesChecked = null;
1678 // Also add the files: for any get_files associated with this VfModule
1679 // *if* there are any
1680 logger.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId={}",
1683 List<HeatFiles> heatFiles = null;
1684 Map<String, Object> heatFilesObjects = new HashMap<>();
1686 // Add ability to turn on adding get_files with volume requests (by property).
1687 boolean addGetFilesOnVolumeReq = false;
1689 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1690 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1691 addGetFilesOnVolumeReq = true;
1692 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
1694 } catch (Exception e) {
1695 logger.debug("An error occured trying to get property {} - default to false",
1696 MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, e);
1698 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1699 logger.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec "
1700 + "vfModuleId={}", vf.getModelUUID());
1702 heatFiles = vf.getHeatFiles();
1703 if (heatFiles != null && !heatFiles.isEmpty()) {
1704 // add these to stack - to be done in createStack
1705 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1706 // this will match the nested templates format
1707 logger.debug("Contents of heatFiles - to be added to files: on stack:");
1708 for (HeatFiles heatfile : heatFiles) {
1709 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
1710 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1713 logger.debug("No heat files found -nothing to do here");
1714 heatFilesObjects = null;
1718 // Check that required parameters have been supplied
1719 String missingParams = null;
1720 List<String> paramList = new ArrayList<>();
1722 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1723 // supplied an alias. Only check if we don't find it initially.
1724 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1725 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1727 boolean checkRequiredParameters = true;
1729 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1730 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1731 checkRequiredParameters = false;
1732 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking...",
1733 MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1735 } catch (Exception e) {
1736 // No problem - default is true
1737 logger.debug("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1739 // 1604 - Add enhanced environment & parameter checking
1740 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1741 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1742 // Note this also removes any comments
1743 MsoHeatEnvironmentEntry mhee = null;
1744 if (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase().contains("parameters:")) {
1745 logger.debug("Enhanced environment checking enabled - 1604");
1746 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1747 mhee = new MsoHeatEnvironmentEntry(sb);
1748 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1749 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1750 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1752 if (!mhee.isValid()) {
1753 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1755 sb2.append("\nEnvironment:");
1756 sb2.append(mhee.toFullString());
1758 logger.debug(sb2.toString());
1760 logger.debug("NO ENVIRONMENT for this entry");
1762 // New for 1607 - support params of json type
1763 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1764 boolean hasJson = false;
1766 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1767 logger.debug("Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias="
1768 + parm.getParamAlias());
1770 String parameterType = parm.getParamType();
1771 if (parameterType == null || "".equals(parameterType.trim())) {
1772 parameterType = "String";
1774 JsonNode jsonNode = null;
1775 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1776 if (inputs.containsKey(parm.getParamName())) {
1778 String jsonString = null;
1780 jsonString = JSON_MAPPER.writeValueAsString(inputs.get(parm.getParamName()));
1781 jsonNode = JSON_MAPPER.readTree(jsonString);
1782 } catch (JsonParseException jpe) {
1783 // TODO - what to do here?
1784 // for now - send the error to debug
1785 logger.debug("Json Error Converting {} - {}", parm.getParamName(), jpe.getMessage(), jpe);
1788 } catch (Exception e) {
1790 logger.debug("Json Error Converting {} {}", parm.getParamName(), e.getMessage(), e);
1794 if (jsonNode != null) {
1795 jsonParams.put(parm.getParamName(), jsonNode);
1797 } else if (inputs.containsKey(parm.getParamAlias())) {
1799 String jsonString = null;
1801 jsonString = (String) inputs.get(parm.getParamAlias());
1802 jsonNode = JSON_MAPPER.readTree(jsonString);
1803 } catch (JsonParseException jpe) {
1804 // TODO - what to do here?
1805 // for now - send the error to debug, but just leave it as a String
1806 String errorMessage = jpe.getMessage();
1807 logger.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1810 } catch (Exception e) {
1812 logger.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1816 if (jsonNode != null) {
1817 // Notice here - we add it to the jsonParams hashMap with the actual name -
1818 // then manipulate the inputs so when we check for aliases below - it will not
1820 jsonParams.put(parm.getParamName(), jsonNode);
1821 inputs.remove(parm.getParamAlias());
1822 inputs.put(parm.getParamName(), jsonString);
1824 } // TODO add a check for the parameter in the env file
1827 if (parm.isRequired() && (inputs == null || !inputs.containsKey(parm.getParamName()))) {
1828 if (inputs.containsKey(parm.getParamAlias())) {
1829 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1830 String realParamName = parm.getParamName();
1831 String alias = parm.getParamAlias();
1832 Object value = inputs.get(alias);
1833 logger.debug("*Found an Alias: paramName=" + realParamName + ",alias=" + alias + ",value=" + value);
1834 inputs.remove(alias);
1835 inputs.put(realParamName, value);
1836 logger.debug("{} entry removed from inputs, added back using {}", alias, realParamName);
1838 // enhanced - check if it's in the Environment (note: that method
1839 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1841 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1842 parm.getParamName());
1844 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1845 if (missingParams == null) {
1846 missingParams = parm.getParamName();
1848 missingParams += "," + parm.getParamName();
1852 paramList.add(parm.getParamName());
1856 if (missingParams != null) {
1857 // Problem - missing one or more required parameters
1858 if (checkRequiredParameters) {
1859 String error = "Update VNF: Missing Required inputs: " + missingParams;
1860 logger.error(LoggingAnchor.FIVE, MessageEnum.RA_MISSING_PARAM.toString(), missingParams, OPENSTACK,
1861 ErrorCode.DataError.getValue(), error);
1862 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1864 logger.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1868 // Just submit the envt entry as received from the database
1869 String newEnvironmentString = null;
1871 newEnvironmentString = mhee.getRawEntry().toString();
1873 // Remove any extraneous parameters (don't throw an error)
1874 if (inputs != null) {
1875 List<String> extraParams = new ArrayList<>();
1876 extraParams.addAll(inputs.keySet());
1877 // This is not a valid parameter for this template
1878 extraParams.removeAll(paramList);
1879 if (!extraParams.isEmpty()) {
1880 logger.warn(LoggingAnchor.SIX, MessageEnum.RA_VNF_EXTRA_PARAM.toString(), vnfType,
1881 extraParams.toString(), OPENSTACK, ErrorCode.DataError.getValue(), "Extra params");
1882 inputs.keySet().removeAll(extraParams);
1885 Map<String, Object> goldenInputs = copyStringInputs(inputs);
1886 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
1887 Map<String, Object> inputsTwo = null;
1888 if (hasJson && jsonParams.size() > 0) {
1889 inputsTwo = new HashMap<>();
1890 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
1891 String keyParamName = entry.getKey();
1892 Object value = entry.getValue();
1893 if (jsonParams.containsKey(keyParamName)) {
1894 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
1896 inputsTwo.put(keyParamName, value);
1899 goldenInputs = inputsTwo;
1902 // "Fix" the template if it has CR/LF (getting this from Oracle)
1903 String template = heatTemplate.getHeatTemplate();
1904 template = template.replaceAll("\r\n", "\n");
1906 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1907 boolean failRequestOnValetFailure =
1908 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1909 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1910 if (isVolumeRequest) {
1911 isValetEnabled = false;
1912 logger.debug("never send a volume request to valet");
1914 boolean sendResponseToValet = false;
1915 if (isValetEnabled) {
1916 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1917 String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1918 // Make sure it is set to something.
1919 if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) {
1920 parsedVfModuleName = "unknown";
1922 sendResponseToValet = this.valetUpdateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
1923 nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString,
1924 (HashMap<String, Object>) goldenInputs, msoRequest, inputs, failRequestOnValetFailure,
1925 valetModifiedParamsHolder);
1926 if (sendResponseToValet) {
1927 goldenInputs = valetModifiedParamsHolder.value;
1931 // Have the tenant. Now deploy the stack itself
1932 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1933 // because we already checked for those.
1935 heatStack = heatU.updateStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, template, goldenInputs, true,
1936 heatTemplate.getTimeoutMinutes(), newEnvironmentString,
1937 // heatEnvironmentString,
1938 nestedTemplatesChecked, heatFilesObjects);
1939 } catch (MsoException me) {
1940 me.addContext("UpdateVFModule");
1941 String error = "Update VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
1943 logger.error(LoggingAnchor.EIGHT, MessageEnum.RA_UPDATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
1944 cloudSiteId, tenantId, OPENSTACK, ErrorCode.DataError.getValue(), "Exception - " + error, me);
1945 if (isValetEnabled && sendResponseToValet) {
1946 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1948 GenericValetResponse<ValetRollbackResponse> gvr =
1949 this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage());
1950 // Nothing to really do here whether it succeeded or not other than log it.
1951 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1952 } catch (Exception e) {
1953 logger.error("Exception encountered while sending Rollback to Valet ", e);
1956 throw new VnfException(me);
1960 // Reach this point if updateStack is successful.
1961 // Populate remaining rollback info and response parameters.
1962 vfRollback.setVnfId(heatStack.getCanonicalName());
1963 vfRollback.setVnfCreated(true);
1965 if (isValetEnabled && sendResponseToValet) {
1966 logger.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id");
1968 GenericValetResponse<ValetConfirmResponse> gvr =
1969 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1970 // Nothing to really do here whether it succeeded or not other than log it.
1971 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1972 } catch (Exception e) {
1973 logger.error("Exception encountered while sending Confirm to Valet ", e);
1977 outputs.value = copyStringOutputs(heatStack.getOutputs());
1978 rollback.value = vfRollback;
1981 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
1982 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
1983 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
1984 if (vfModuleStackId == null)
1986 int index = vfModuleStackId.lastIndexOf('/');
1989 String vfModuleName = null;
1991 vfModuleName = vfModuleStackId.substring(0, index);
1992 } catch (Exception e) {
1993 logger.debug("Exception", e);
1994 vfModuleName = null;
1996 return vfModuleName;
2000 * Helper method to check a boolean property value - on error return provided default
2002 private boolean checkBooleanProperty(String propertyName, boolean defaultValue) {
2003 boolean property = defaultValue;
2005 String propertyString = this.environment.getProperty(propertyName);
2006 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
2008 } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
2011 } catch (Exception e) {
2012 logger.debug("An exception occured trying to get property {} - defaulting to ", propertyName, defaultValue,
2014 property = defaultValue;
2020 * Helper method to combine getFiles and nestedTemplates in to a single Map
2022 private Map<String, Object> combineGetFilesAndNestedTemplates(Map<String, Object> getFiles,
2023 Map<String, Object> nestedTemplates) {
2024 boolean haveGetFiles = true;
2025 boolean haveNestedTemplates = true;
2026 Map<String, Object> files = new HashMap<>();
2027 if (getFiles == null || getFiles.isEmpty()) {
2028 haveGetFiles = false;
2030 if (nestedTemplates == null || nestedTemplates.isEmpty()) {
2031 haveNestedTemplates = false;
2033 if (haveGetFiles && haveNestedTemplates) {
2034 for (String keyString : getFiles.keySet()) {
2035 files.put(keyString, getFiles.get(keyString));
2037 for (String keyString : nestedTemplates.keySet()) {
2038 files.put(keyString, nestedTemplates.get(keyString));
2041 // Handle if we only have one or neither:
2045 if (haveNestedTemplates) {
2046 files = nestedTemplates;
2053 * Valet Create request
2055 private boolean valetCreateRequest(String cloudSiteId, String cloudOwner, String tenantId,
2056 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
2057 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
2058 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure,
2059 Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2060 boolean valetSucceeded = false;
2061 String valetErrorMessage = "more detail not available";
2063 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2064 Map<String, Object> files =
2065 this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked);
2066 HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(),
2067 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2068 GenericValetResponse<ValetCreateResponse> createReq = this.vci.callValetCreateRequest(
2069 msoRequest.getRequestId(), cloudSiteId, cloudOwner, tenantId, msoRequest.getServiceInstanceId(),
2070 (String) inputs.get("vnf_id"), (String) inputs.get("vnf_name"), (String) inputs.get("vf_module_id"),
2071 (String) inputs.get("vf_module_name"), keystoneUrl, heatRequest);
2072 ValetCreateResponse vcr = createReq.getReturnObject();
2073 if (vcr != null && createReq.getStatusCode() == 200) {
2074 ValetStatus status = vcr.getStatus();
2075 if (status != null) {
2076 String statusCode = status.getStatus(); // "ok" or "failed"
2077 if ("ok".equalsIgnoreCase(statusCode)) {
2078 Map<String, Object> newInputs = vcr.getParameters();
2079 if (newInputs != null) {
2080 Map<String, Object> oldGold = goldenInputs;
2081 logger.debug("parameters before being modified by valet:{}", oldGold.toString());
2082 goldenInputs = new HashMap<>();
2083 for (String key : newInputs.keySet()) {
2084 goldenInputs.put(key, newInputs.get(key));
2086 valetModifiedParamsHolder.value = goldenInputs;
2087 logger.debug("parameters after being modified by valet:{}", goldenInputs.toString());
2088 valetSucceeded = true;
2091 valetErrorMessage = status.getMessage();
2095 logger.debug("Got a bad response back from valet");
2096 valetErrorMessage = "Bad response back from Valet";
2097 valetSucceeded = false;
2099 } catch (Exception e) {
2100 logger.error("An exception occurred trying to call valet ...", e);
2101 valetSucceeded = false;
2102 valetErrorMessage = e.getMessage();
2104 if (failRequestOnValetFailure && !valetSucceeded) {
2105 // The valet request failed - and property says to fail the request
2106 // TODO Create a new exception class for valet?
2107 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2109 return valetSucceeded;
2113 * Valet update request
2116 private boolean valetUpdateRequest(String cloudSiteId, String cloudOwnerId, String tenantId,
2117 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
2118 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
2119 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure,
2120 Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2122 boolean valetSucceeded = false;
2123 String valetErrorMessage = "more detail not available";
2125 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2126 Map<String, Object> files =
2127 this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked);
2128 HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(),
2129 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2130 // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now
2131 GenericValetResponse<ValetUpdateResponse> updateReq =
2132 this.vci.callValetUpdateRequest(msoRequest.getRequestId(), cloudSiteId, cloudOwnerId, tenantId,
2133 msoRequest.getServiceInstanceId(), (String) inputs.get("vnf_id"), vfModuleName,
2134 (String) inputs.get("vf_module_id"), vfModuleName, keystoneUrl, heatRequest);
2135 ValetUpdateResponse vur = updateReq.getReturnObject();
2136 if (vur != null && updateReq.getStatusCode() == 200) {
2137 ValetStatus status = vur.getStatus();
2138 if (status != null) {
2139 String statusCode = status.getStatus(); // "ok" or "failed"
2140 if ("ok".equalsIgnoreCase(statusCode)) {
2141 Map<String, Object> newInputs = vur.getParameters();
2142 if (newInputs != null) {
2143 Map<String, Object> oldGold = goldenInputs;
2144 logger.debug("parameters before being modified by valet:{}", oldGold);
2145 goldenInputs = new HashMap<>();
2146 for (String key : newInputs.keySet()) {
2147 goldenInputs.put(key, newInputs.get(key));
2149 valetModifiedParamsHolder.value = goldenInputs;
2150 logger.debug("parameters after being modified by valet:{}", goldenInputs);
2151 valetSucceeded = true;
2154 valetErrorMessage = status.getMessage();
2158 logger.debug("Got a bad response back from valet");
2159 valetErrorMessage = "Got a bad response back from valet";
2160 valetSucceeded = false;
2162 } catch (Exception e) {
2163 logger.error("An exception occurred trying to call valet - will continue processing for now...", e);
2164 valetErrorMessage = e.getMessage();
2165 valetSucceeded = false;
2167 if (failRequestOnValetFailure && !valetSucceeded) {
2168 // The valet request failed - and property says to fail the request
2169 // TODO Create a new exception class for valet?
2170 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2172 return valetSucceeded;
2176 * Valet delete request
2178 private boolean valetDeleteRequest(String cloudSiteId, String cloudOwnerId, String tenantId, String vnfName,
2179 MsoRequest msoRequest, boolean failRequestOnValetFailure) {
2180 boolean valetDeleteRequestSucceeded = false;
2181 String valetErrorMessage = "more detail not available";
2183 String vfModuleId = vnfName;
2184 String vfModuleName = vnfName;
2186 vfModuleName = vnfName.substring(0, vnfName.indexOf('/'));
2187 vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1);
2188 } catch (Exception e) {
2189 // do nothing - send what we got for vnfName for both to valet
2190 logger.error("An exception occurred trying to call MsoVnfAdapterImpl.valetDeleteRequest() method", e);
2192 GenericValetResponse<ValetDeleteResponse> deleteReq = this.vci.callValetDeleteRequest(
2193 msoRequest.getRequestId(), cloudSiteId, cloudOwnerId, tenantId, vfModuleId, vfModuleName);
2194 ValetDeleteResponse vdr = deleteReq.getReturnObject();
2195 if (vdr != null && deleteReq.getStatusCode() == 200) {
2196 ValetStatus status = vdr.getStatus();
2197 if (status != null) {
2198 String statusCode = status.getStatus(); // "ok" or "failed"
2199 if ("ok".equalsIgnoreCase(statusCode)) {
2200 logger.debug("delete request to valet returned success");
2201 valetDeleteRequestSucceeded = true;
2203 logger.debug("delete request to valet returned failure");
2204 valetDeleteRequestSucceeded = false;
2205 valetErrorMessage = status.getMessage();
2209 logger.debug("Got a bad response back from valet - delete request failed");
2210 valetDeleteRequestSucceeded = false;
2211 valetErrorMessage = "Got a bad response back from valet - delete request failed";
2213 } catch (Exception e) {
2214 logger.error("An exception occurred trying to call valet - valetDeleteRequest failed", e);
2215 valetDeleteRequestSucceeded = false;
2216 valetErrorMessage = e.getMessage();
2218 if (!valetDeleteRequestSucceeded && failRequestOnValetFailure) {
2219 logger.error("ValetDeleteRequestFailed - del req still will be sent to openstack",
2220 new VnfException("ValetDeleteRequestFailedError"));
2222 return valetDeleteRequestSucceeded;