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 * ================================================================================
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 * ============LICENSE_END=========================================================
24 package org.onap.so.adapters.vnf;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashMap;
32 import java.util.List;
34 import java.util.Optional;
35 import java.util.concurrent.TimeUnit;
36 import javax.jws.WebService;
37 import javax.xml.ws.Holder;
38 import org.apache.commons.collections.CollectionUtils;
39 import org.onap.so.adapters.valet.GenericValetResponse;
40 import org.onap.so.adapters.valet.ValetClient;
41 import org.onap.so.adapters.valet.beans.HeatRequest;
42 import org.onap.so.adapters.valet.beans.ValetConfirmResponse;
43 import org.onap.so.adapters.valet.beans.ValetCreateResponse;
44 import org.onap.so.adapters.valet.beans.ValetDeleteResponse;
45 import org.onap.so.adapters.valet.beans.ValetRollbackResponse;
46 import org.onap.so.adapters.valet.beans.ValetStatus;
47 import org.onap.so.adapters.valet.beans.ValetUpdateResponse;
48 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
49 import org.onap.so.adapters.vnf.exceptions.VnfException;
50 import org.onap.so.adapters.vnf.exceptions.VnfNotFound;
51 import org.onap.so.client.aai.AAIResourcesClient;
52 import org.onap.so.cloud.CloudConfig;
53 import org.onap.so.db.catalog.beans.CloudIdentity;
54 import org.onap.so.db.catalog.beans.CloudSite;
55 import org.onap.so.db.catalog.beans.HeatEnvironment;
56 import org.onap.so.db.catalog.beans.HeatFiles;
57 import org.onap.so.db.catalog.beans.HeatTemplate;
58 import org.onap.so.db.catalog.beans.HeatTemplateParam;
59 import org.onap.so.db.catalog.beans.VfModule;
60 import org.onap.so.db.catalog.beans.VfModuleCustomization;
61 import org.onap.so.db.catalog.beans.VnfResource;
62 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
63 import org.onap.so.db.catalog.data.repository.VnfResourceRepository;
64 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
65 import org.onap.so.entity.MsoRequest;
66 import org.onap.so.logger.ErrorCode;
67 import org.onap.so.heatbridge.HeatBridgeApi;
68 import org.onap.so.heatbridge.HeatBridgeImpl;
69 import org.onap.so.heatbridge.openstack.api.OpenstackClient;
70 import org.onap.so.logger.MessageEnum;
71 import org.onap.so.openstack.beans.HeatStatus;
72 import org.onap.so.openstack.beans.StackInfo;
73 import org.onap.so.openstack.beans.VnfRollback;
74 import org.onap.so.openstack.beans.VnfStatus;
75 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
76 import org.onap.so.openstack.exceptions.MsoException;
77 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
78 import org.onap.so.openstack.exceptions.MsoHeatNotFoundException;
79 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
80 import org.onap.so.openstack.utils.MsoHeatUtils;
81 import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate;
82 import org.openstack4j.model.compute.Flavor;
83 import org.openstack4j.model.compute.Image;
84 import org.openstack4j.model.compute.Server;
85 import org.openstack4j.model.heat.Resource;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88 import org.springframework.beans.factory.annotation.Autowired;
89 import org.springframework.core.env.Environment;
90 import org.springframework.stereotype.Component;
91 import org.springframework.transaction.annotation.Transactional;
92 import com.fasterxml.jackson.core.JsonParseException;
93 import com.fasterxml.jackson.databind.JsonNode;
94 import com.fasterxml.jackson.databind.ObjectMapper;
96 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter",
97 targetNamespace = "http://org.onap.so/vnf")
100 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
103 private CloudConfig cloudConfig;
106 private Environment environment;
108 private static final Logger logger = LoggerFactory.getLogger(MsoVnfAdapterImpl.class);
110 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
111 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
112 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
113 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq";
114 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
115 private static final String VALET_ENABLED = "org.onap.so.adapters.vnf.valet_enabled";
116 private static final String FAIL_REQUESTS_ON_VALET_FAILURE =
117 "org.onap.so.adapters.vnf.fail_requests_on_valet_failure";
118 private static final String SUCCESS_MSG = "Successfully received response from Open Stack";
121 private VFModuleCustomizationRepository vfModuleCustomRepo;
125 private VnfResourceRepository vnfResourceRepo;
128 private MsoHeatUtilsWithUpdate heatU;
130 private MsoHeatUtils heat;
132 private ValetClient vci;
135 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
137 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
139 public MsoVnfAdapterImpl() {
141 // DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
145 * Health Check web method. Does nothing but return to show the adapter is deployed.
148 public void healthCheck() {
149 logger.debug("Health check call in VNF Adapter");
153 * This is the "Create VNF" web service implementation. It will create a new VNF of the requested type in the
154 * specified cloud and tenant. The tenant must exist before this service is called.
156 * If a VNF with the same name already exists, this can be considered a success or failure, depending on the value
157 * of the 'failIfExists' parameter.
159 * All VNF types will be defined in the MSO catalog. The caller must request one of these pre-defined types or an
160 * error will be returned. Within the catalog, each VNF type references (among other things) a Heat template which
161 * is used to deploy the required VNF artifacts (VMs, networks, etc.) to the cloud.
163 * Depending on the Heat template, a variable set of input parameters will be defined, some of which are required.
164 * The caller is responsible to pass the necessary input data for the VNF or an error will be thrown.
166 * The method returns the vnfId (the canonical name), a Map of VNF output attributes, and a VnfRollback object. This
167 * last object can be passed as-is to the rollbackVnf operation to undo everything that was created for the VNF.
168 * This is useful if a VNF is successfully created but the orchestrator fails on a subsequent operation.
170 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
171 * @param cloudOwner cloud owner of the cloud region in which to create the VNF
172 * @param tenantId Openstack tenant identifier
173 * @param vnfType VNF type key, should match a VNF definition in catalog DB
174 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
175 * @param vnfName Name to be assigned to the new VNF
176 * @param inputs Map of key=value inputs for VNF stack creation
177 * @param failIfExists Flag whether already existing VNF should be considered a success or failure
178 * @param msoRequest Request tracking information for logs
179 * @param vnfId Holder for output VNF Openstack ID
180 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
181 * @param rollback Holder for returning VnfRollback object
184 public void createVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
185 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
186 Boolean failIfExists, Boolean backout, Boolean enableBridge, MsoRequest msoRequest, Holder<String> vnfId,
187 Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback) throws VnfException {
188 // parameters used for multicloud adapter
189 String genericVnfId = "";
190 String vfModuleId = "";
191 // Create a hook here to catch shortcut createVf requests:
192 if (requestType != null && requestType.startsWith("VFMOD")) {
193 logger.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
194 String newRequestType = requestType.substring(5);
195 String vfVolGroupHeatStackId = "";
196 String vfBaseHeatStackId = "";
198 if (volumeGroupHeatStackId != null) {
199 vfVolGroupHeatStackId =
200 volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf('|'));
201 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf('|') + 1);
203 } catch (Exception e) {
204 // might be ok - both are just blank
205 logger.debug("ERROR trying to parse the volumeGroupHeatStackId {}", volumeGroupHeatStackId, e);
207 this.createVfModule(cloudSiteId, cloudOwner, tenantId, vnfType, vnfVersion, genericVnfId, vnfName,
208 vfModuleId, newRequestType, vfVolGroupHeatStackId, vfBaseHeatStackId, null, inputs, failIfExists,
209 backout, enableBridge, msoRequest, vnfId, outputs, rollback);
212 // createVf will know if the requestType starts with "X" that it's the "old" way
213 StringBuilder newRequestTypeSb = new StringBuilder("X");
214 String vfVolGroupHeatStackId = "";
215 String vfBaseHeatStackId = "";
216 if (requestType != null) {
217 newRequestTypeSb.append(requestType);
219 this.createVfModule(cloudSiteId, cloudOwner, tenantId, vnfType, vnfVersion, genericVnfId, vnfName, vfModuleId,
220 newRequestTypeSb.toString(), vfVolGroupHeatStackId, vfBaseHeatStackId, null, inputs, failIfExists,
221 backout, enableBridge, msoRequest, vnfId, outputs, rollback);
223 // End createVf shortcut
227 public void updateVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfType, String vnfVersion,
228 String vnfName, String requestType, String volumeGroupHeatStackId, Map<String, Object> inputs,
229 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
230 throws VnfException {
231 // As of 1707 - this method should no longer be called
232 logger.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
236 * This is the "Query VNF" web service implementation. It will look up a VNF by name or ID in the specified cloud
239 * The method returns an indicator that the VNF exists, its Openstack internal ID, its status, and the set of
240 * outputs (from when the stack was created).
242 * @param cloudSiteId CLLI code of the cloud site in which to query
243 * @param tenantId Openstack tenant identifier
244 * @param vnfName VNF Name or Openstack ID
245 * @param msoRequest Request tracking information for logs
246 * @param vnfExists Flag reporting the result of the query
247 * @param vnfId Holder for output VNF Openstack ID
248 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
251 public void queryVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest,
252 Holder<Boolean> vnfExists, Holder<String> vnfId, Holder<VnfStatus> status,
253 Holder<Map<String, String>> outputs) throws VnfException {
255 logger.debug("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
257 // Will capture execution time for metrics
258 long startTime = System.currentTimeMillis();
260 StackInfo heatStack = null;
261 long subStartTime = System.currentTimeMillis();
263 heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vnfName);
264 } catch (MsoException me) {
265 me.addContext("QueryVNF");
266 // Failed to query the Stack due to an openstack exception.
267 // Convert to a generic VnfException
269 "Query VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
270 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudSiteId,
271 tenantId, "OpenStack", "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryStack", me);
273 throw new VnfException(me);
276 // Populate the outputs based on the returned Stack information
278 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
280 vnfExists.value = Boolean.FALSE;
281 status.value = VnfStatus.NOTFOUND;
283 outputs.value = new HashMap<>(); // Return as an empty map
285 logger.debug("VNF {} not found", vnfName);
287 vnfExists.value = Boolean.TRUE;
288 status.value = stackStatusToVnfStatus(heatStack.getStatus());
289 vnfId.value = heatStack.getCanonicalName();
290 outputs.value = copyStringOutputs(heatStack.getOutputs());
292 logger.debug("VNF {} found, ID = {}", vnfName, vnfId.value);
298 * This is the "Delete VNF" web service implementation. It will delete a VNF by name or ID in the specified cloud
301 * The method has no outputs.
303 * @param cloudSiteId CLLI code of the cloud site in which to delete
304 * @param cloudOwner cloud owner of the cloud region in which to delete
305 * @param tenantId Openstack tenant identifier
306 * @param vnfName VNF Name or Openstack ID
307 * @param msoRequest Request tracking information for logs
310 public void deleteVnf(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, MsoRequest msoRequest)
311 throws VnfException {
313 logger.debug("Deleting VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
314 // Will capture execution time for metrics
315 long startTime = System.currentTimeMillis();
317 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
318 // The possible outcomes of deleteStack are a StackInfo object with status
319 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
321 long subStartTime = System.currentTimeMillis();
323 heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true);
324 } catch (MsoException me) {
325 me.addContext("DeleteVNF");
326 // Failed to query the Stack due to an openstack exception.
327 // Convert to a generic VnfException
329 "Delete VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
330 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner,
331 cloudSiteId, tenantId, "OpenStack", "DeleteVNF", ErrorCode.DataError.getValue(),
332 "Exception - DeleteVNF", me);
334 throw new VnfException(me);
337 // On success, nothing is returned.
342 * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
343 * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
344 * to undo the creation.
347 public void rollbackVnf(VnfRollback rollback) throws VnfException {
348 long startTime = System.currentTimeMillis();
349 // rollback may be null (e.g. if stack already existed when Create was called)
350 if (rollback == null) {
351 logger.info(MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
355 // Get the elements of the VnfRollback object for easier access
356 String cloudSiteId = rollback.getCloudSiteId();
357 String cloudOwner = rollback.getCloudOwner();
358 String tenantId = rollback.getTenantId();
359 String vnfId = rollback.getVnfId();
361 logger.debug("Rolling Back VNF {} in {}", vnfId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
363 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
364 // The possible outcomes of deleteStack are a StackInfo object with status
365 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
368 heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfId, true);
369 } catch (MsoException me) {
370 // Failed to rollback the Stack due to an openstack exception.
371 // Convert to a generic VnfException
372 me.addContext("RollbackVNF");
374 "Rollback VNF: " + vnfId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
375 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfId, cloudOwner,
376 cloudSiteId, tenantId, "OpenStack", "DeleteStack", ErrorCode.DataError.getValue(),
377 "Exception - DeleteStack", me);
379 throw new VnfException(me);
384 private VnfStatus stackStatusToVnfStatus(HeatStatus stackStatus) {
385 switch (stackStatus) {
387 return VnfStatus.ACTIVE;
389 return VnfStatus.ACTIVE;
391 return VnfStatus.FAILED;
393 return VnfStatus.UNKNOWN;
397 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
398 Map<String, String> stringOutputs = new HashMap<>();
399 for (Map.Entry<String, Object> entry : stackOutputs.entrySet()) {
400 String key = entry.getKey();
401 Object value = entry.getValue();
403 stringOutputs.put(key, value.toString());
404 } catch (Exception e) {
405 StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs");
406 if (value instanceof Integer) { // nothing to add to the message
407 } else if (value instanceof JsonNode) {
408 msg.append(" - exception converting JsonNode");
409 } else if (value instanceof java.util.LinkedHashMap) {
410 msg.append(" exception converting LinkedHashMap");
412 msg.append(" - unable to call .toString() " + e.getMessage());
414 logger.debug(msg.toString(), e);
417 return stringOutputs;
420 private Map<String, Object> copyStringInputs(Map<String, Object> stringInputs) {
421 return new HashMap<>(stringInputs);
424 protected boolean callHeatbridge(String heatStackId) {
425 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
426 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
427 long waitTimeMs = 10000L;
429 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password,
430 tenant, region, owner, heatStackId};
431 String[] envp = null;
432 File dir = new File(executionDir);
433 logger.debug("Calling HeatBridgeMain.py in {} with arguments {}", dir, Arrays.toString(cmdarray));
434 Runtime r = Runtime.getRuntime();
435 Process p = r.exec(cmdarray, envp, dir);
436 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
438 logger.debug(" HeatBridgeMain.py returned {} with code {}", wait, p.exitValue());
439 return wait && p.exitValue() == 0;
440 } catch (IOException e) {
441 logger.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
443 } catch (RuntimeException e) {
444 logger.debug(" HeatBridgeMain.py failed during runtime!" + e);
446 } catch (Exception e) {
447 logger.debug(" HeatBridgeMain.py failed for unknown reasons! " + e);
452 private void heatbridge(StackInfo heatStack, String cloudOwner, String cloudSiteId, String tenantId,
453 String genericVnfName, String vfModuleId) {
455 CloudSite cloudSite =
456 cloudConfig.getCloudSite(cloudSiteId).orElseThrow(() -> new MsoCloudSiteNotFound(cloudSiteId));
457 CloudIdentity cloudIdentity = cloudSite.getIdentityService();
458 String heatStackId = heatStack.getCanonicalName().split("/")[1];
460 List<String> oobMgtNetNames = new ArrayList<>();
462 HeatBridgeApi heatBridgeClient =
463 new HeatBridgeImpl(new AAIResourcesClient(), cloudIdentity, cloudOwner, cloudSiteId, tenantId);
465 OpenstackClient openstackClient = heatBridgeClient.authenticate();
466 List<Resource> stackResources = heatBridgeClient.queryNestedHeatStackResources(heatStackId);
468 List<Server> osServers = heatBridgeClient.getAllOpenstackServers(stackResources);
470 List<Image> osImages = heatBridgeClient.extractOpenstackImagesFromServers(osServers);
472 List<Flavor> osFlavors = heatBridgeClient.extractOpenstackFlavorsFromServers(osServers);
474 logger.debug("Successfully queried heat stack{} for resources.", heatStackId);
476 if (osImages != null && !osImages.isEmpty()) {
477 heatBridgeClient.buildAddImagesToAaiAction(osImages);
478 logger.debug("Successfully built AAI actions to add images.");
480 logger.debug("No images to update to AAI.");
483 if (osFlavors != null && !osFlavors.isEmpty()) {
484 heatBridgeClient.buildAddFlavorsToAaiAction(osFlavors);
485 logger.debug("Successfully built AAI actions to add flavors.");
487 logger.debug("No flavors to update to AAI.");
491 heatBridgeClient.buildAddVserversToAaiAction(genericVnfName, vfModuleId, osServers);
492 logger.debug("Successfully queried compute resources and built AAI vserver actions.");
495 List<String> oobMgtNetIds = new ArrayList<>();
497 // if no network-id list is provided, however network-name list is
498 if (!CollectionUtils.isEmpty(oobMgtNetNames)) {
499 oobMgtNetIds = heatBridgeClient.extractNetworkIds(oobMgtNetNames);
501 heatBridgeClient.buildAddVserverLInterfacesToAaiAction(stackResources, oobMgtNetIds);
503 "Successfully queried neutron resources and built AAI actions to add l-interfaces to vservers.");
506 heatBridgeClient.submitToAai();
507 } catch (Exception ex) {
508 logger.debug("Heatbrige failed for stackId: " + heatStack.getCanonicalName(), ex);
512 private String convertNode(final JsonNode node) {
514 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
515 return JSON_MAPPER.writeValueAsString(obj);
516 } catch (JsonParseException jpe) {
517 logger.debug("Error converting json to string: {}", jpe.getMessage(), jpe);
518 } catch (Exception e) {
519 logger.debug("Error converting json to string: {}", e.getMessage(), e);
521 return "[Error converting json to string]";
524 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
525 if (objectMap == null) {
528 Map<String, String> stringMap = new HashMap<>();
529 for (String key : objectMap.keySet()) {
530 if (!stringMap.containsKey(key)) {
531 Object obj = objectMap.get(key);
532 if (obj instanceof String) {
533 stringMap.put(key, (String) objectMap.get(key));
534 } else if (obj instanceof JsonNode) {
535 // This is a bit of mess - but I think it's the least impacting
536 // let's convert it BACK to a string - then it will get converted back later
538 String str = this.convertNode((JsonNode) obj);
539 stringMap.put(key, str);
540 } catch (Exception e) {
541 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
542 // okay in this instance - only string values (fqdn) are expected to be needed
544 } else if (obj instanceof java.util.LinkedHashMap) {
545 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
547 String str = JSON_MAPPER.writeValueAsString(obj);
548 stringMap.put(key, str);
549 } catch (Exception e) {
550 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
552 } else if (obj instanceof Integer) {
554 String str = "" + obj;
555 stringMap.put(key, str);
556 } catch (Exception e) {
557 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
561 String str = obj.toString();
562 stringMap.put(key, str);
563 } catch (Exception e) {
565 "DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")",
576 public void createVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
577 String vnfVersion, String genericVnfName, String vnfName, String vfModuleId, String requestType,
578 String volumeGroupHeatStackId, String baseVfHeatStackId, String modelCustomizationUuid,
579 Map<String, Object> inputs, Boolean failIfExists, Boolean backout, Boolean enableBridge,
580 MsoRequest msoRequest, Holder<String> vnfId, Holder<Map<String, String>> outputs,
581 Holder<VnfRollback> rollback) throws VnfException {
582 String vfModuleName = vnfName;
583 String vfModuleType = vnfType;
584 String vfVersion = vnfVersion;
585 String mcu = modelCustomizationUuid;
586 boolean useMCUuid = false;
587 if (mcu != null && !mcu.isEmpty()) {
588 if ("null".equalsIgnoreCase(mcu)) {
589 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: "
590 + modelCustomizationUuid);
594 logger.debug("Found modelCustomizationUuid! Will use that: " + mcu);
599 String requestTypeString = "";
600 if (requestType != null && !"".equals(requestType)) {
601 requestTypeString = requestType;
603 String nestedStackId = null;
604 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)
605 && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
606 nestedStackId = volumeGroupHeatStackId;
608 String nestedBaseStackId = null;
609 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
610 nestedBaseStackId = baseVfHeatStackId;
613 // This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
614 boolean oldWay = false;
615 if (requestTypeString.startsWith("X")) {
617 logger.debug("orchestrating a VNF - *NOT* a module!");
618 requestTypeString = requestTypeString.substring(1);
621 // 1607 - let's parse out the request type we're being sent
622 boolean isBaseRequest = false;
623 boolean isVolumeRequest = false;
624 if (requestTypeString.startsWith("VOLUME")) {
625 isVolumeRequest = true;
628 logger.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId
629 + ", nestedBaseStackId = " + nestedBaseStackId);
630 // Will capture execution time for metrics
631 long startTime = System.currentTimeMillis();
633 // Build a default rollback object (no actions performed)
634 VnfRollback vfRollback = new VnfRollback();
635 vfRollback.setCloudSiteId(cloudSiteId);
636 vfRollback.setCloudOwner(cloudOwner);
637 vfRollback.setTenantId(tenantId);
638 vfRollback.setMsoRequest(msoRequest);
639 vfRollback.setRequestType(requestTypeString);
640 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
641 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
642 vfRollback.setIsBase(isBaseRequest);
643 vfRollback.setModelCustomizationUuid(mcu);
645 // Put data into A&AI through Heatstack
646 if (enableBridge != null && enableBridge) {
647 callHeatbridge(baseVfHeatStackId);
650 StackInfo heatStack = null;
651 long subStartTime1 = System.currentTimeMillis();
653 heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName);
654 } catch (MsoException me) {
655 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
656 + tenantId + ": " + me;
657 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
658 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
659 "Exception - queryStack", me);
661 // Failed to query the Stack due to an openstack exception.
662 // Convert to a generic VnfException
663 me.addContext("CreateVFModule");
664 throw new VnfException(me);
666 // New with 1607 - more precise handling/messaging if the stack already exists
667 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
668 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
669 HeatStatus status = heatStack.getStatus();
670 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING
671 || status == HeatStatus.UPDATING) {
672 // fail - it's in progress - return meaningful error
673 String error = "Create VF: Stack " + vfModuleName + " already exists and has status "
674 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
675 + "; please wait for it to complete, or fix manually.";
676 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
677 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
678 "Stack " + vfModuleName + " already exists");
680 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
681 heatStack.getCanonicalName());
683 if (status == HeatStatus.FAILED) {
684 // fail - it exists and is in a FAILED state
685 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in "
686 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
687 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
688 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
689 "Stack " + vfModuleName + " already exists and is " + "in FAILED state");
691 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
692 heatStack.getCanonicalName());
694 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
695 // fail - it exists and is in a FAILED state
696 String error = "Create VF: Stack " + vfModuleName + " already exists and has status "
697 + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
698 + "; requires manual intervention.";
699 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
700 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
701 "Stack " + vfModuleName + " already exists and is " + "in UPDATED or UNKNOWN state");
703 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
704 heatStack.getCanonicalName());
706 if (status == HeatStatus.CREATED) {
708 if (failIfExists != null && failIfExists) {
709 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudOwner + "/"
710 + cloudSiteId + "/" + tenantId;
711 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(),
712 vfModuleName, cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack",
713 ErrorCode.DataError.getValue(), "Stack " + vfModuleName + " already exists");
715 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId,
716 heatStack.getCanonicalName());
718 logger.debug("Found Existing stack, status={}", heatStack.getStatus());
719 // Populate the outputs from the existing stack.
720 vnfId.value = heatStack.getCanonicalName();
721 outputs.value = copyStringOutputs(heatStack.getOutputs());
722 rollback.value = vfRollback; // Default rollback - no updates performed
729 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
730 StackInfo nestedHeatStack = null;
731 long subStartTime2 = System.currentTimeMillis();
732 Map<String, Object> nestedVolumeOutputs = null;
733 if (nestedStackId != null) {
735 logger.debug("Querying for nestedStackId = {}", nestedStackId);
736 nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
737 } catch (MsoException me) {
738 // Failed to query the Stack due to an openstack exception.
739 // Convert to a generic VnfException
740 me.addContext("CreateVFModule");
741 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner
742 + "/" + cloudSiteId + "/" + tenantId + ": " + me;
743 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
744 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack",
745 ErrorCode.BusinessProcesssError.getValue(), "MsoException trying to query nested stack", me);
746 logger.debug("ERROR trying to query nested stack= {}", error);
747 throw new VnfException(me);
749 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
750 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in "
751 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
752 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
753 cloudOwner, cloudSiteId, tenantId, error, "OpenStack", "queryStack",
754 ErrorCode.BusinessProcesssError.getValue(),
755 "Create VFModule: Attached heatStack ID " + "DOES NOT EXIST");
757 throw new VnfException(error, MsoExceptionCategory.USERDATA);
759 logger.debug("Found nested volume heat stack - copying values to inputs *later*");
760 nestedVolumeOutputs = nestedHeatStack.getOutputs();
764 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
765 StackInfo nestedBaseHeatStack = null;
766 long subStartTime3 = System.currentTimeMillis();
767 Map<String, Object> baseStackOutputs = null;
768 if (nestedBaseStackId != null) {
770 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
771 nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
772 } catch (MsoException me) {
773 // Failed to query the Stack due to an openstack exception.
774 // Convert to a generic VnfException
775 me.addContext("CreateVFModule");
776 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in "
777 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
778 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
779 cloudOwner, cloudSiteId, tenantId, "OpenStack", "QueryStack",
780 ErrorCode.BusinessProcesssError.getValue(), "MsoException trying to query nested base stack",
782 logger.debug("ERROR trying to query nested base stack= {}", error);
783 throw new VnfException(me);
785 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
786 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId
787 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
788 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
789 cloudOwner, cloudSiteId, tenantId, error, "OpenStack", "QueryStack",
790 ErrorCode.BusinessProcesssError.getValue(),
791 "Create VFModule: Attached base heatStack ID DOES NOT EXIST");
792 logger.debug("Exception occurred", error);
793 throw new VnfException(error, MsoExceptionCategory.USERDATA);
795 logger.debug("Found nested base heat stack - these values will be copied to inputs *later*");
796 baseStackOutputs = nestedBaseHeatStack.getOutputs();
800 // Ready to deploy the new VNF
807 VnfResource vnfResource = null;
808 VfModuleCustomization vfmc = null;
809 logger.debug("version: {}", vfVersion);
811 // 1707 - db refactoring
812 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(mcu);
814 vf = vfmc.getVfModule();
818 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
820 logger.debug("Unable to find vfModuleCust with modelCustomizationUuid={}", mcu);
822 "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
823 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
824 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack",
825 ErrorCode.DataError.getValue(),
826 "Create VF Module: Unable to find vfModule with " + "modelCustomizationUuid=" + mcu);
828 throw new VnfException(error, MsoExceptionCategory.USERDATA);
830 logger.trace("Found vfModuleCust entry {}", vfmc.toString());
832 if (vf.getIsBase()) {
833 isBaseRequest = true;
834 logger.debug("This is a BASE VF request!");
836 logger.debug("This is *not* a BASE VF request!");
837 if (!isVolumeRequest && nestedBaseStackId == null) {
839 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
844 else { // This is to support gamma only - get info from vnf_resource table
845 if (vfVersion != null && !vfVersion.isEmpty()) {
846 vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion);
848 vnfResource = vnfResourceRepo.findByModelName(vnfType);
850 if (vnfResource == null) {
851 String error = "Create VNF: Unknown VNF Type: " + vnfType;
852 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VNF Type", vnfType,
853 "OpenStack", ErrorCode.DataError.getValue(), "Create VNF: Unknown VNF Type");
855 throw new VnfException(error, MsoExceptionCategory.USERDATA);
857 logger.debug("Got VNF module definition from Catalog: {}", vnfResource.toString());
859 // By here - we have either a vf or vnfResource
861 // 1607 - Add version check
862 // First - see if it's in the VnfResource record
863 // if we have a vf Module - then we have to query to get the VnfResource record.
864 if (!oldWay && vf.getVnfResources() != null) {
865 vnfResource = vf.getVnfResources();
866 if (vnfResource == null) {
867 logger.debug("Unable to find vnfResource will not error for now...");
870 String minVersionVnf = null;
871 String maxVersionVnf = null;
872 if (vnfResource != null) {
874 minVersionVnf = vnfResource.getAicVersionMin();
875 maxVersionVnf = vnfResource.getAicVersionMax();
876 } catch (Exception e) {
877 logger.debug("Unable to pull min/max version for this VNF Resource entry", e);
878 minVersionVnf = null;
879 maxVersionVnf = null;
881 if (minVersionVnf != null && "".equals(minVersionVnf)) {
882 minVersionVnf = null;
884 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
885 maxVersionVnf = null;
888 if (minVersionVnf != null && maxVersionVnf != null) {
889 MavenLikeVersioning aicV = new MavenLikeVersioning();
892 if (this.cloudConfig != null) {
893 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
894 if (cloudSiteOpt.isPresent()) {
895 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
896 // Add code to handle unexpected values in here
897 boolean moreThanMin = true;
898 boolean equalToMin = true;
899 boolean moreThanMax = true;
900 boolean equalToMax = true;
901 boolean doNotTest = false;
903 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
904 equalToMin = aicV.isTheSameVersion(minVersionVnf);
905 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
906 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
907 } catch (Exception e) {
909 "An exception occurred while trying to test AIC Version {} - will default to not check",
914 if ((moreThanMin || equalToMin) // aic >= min
915 && (equalToMax || !(moreThanMax))) { // aic <= max
916 logger.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid="
917 + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:"
918 + maxVersionVnf + " supported on Cloud: " + cloudSiteId + " with AIC_Version:"
919 + cloudSiteOpt.get().getCloudVersion());
922 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid="
923 + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:"
924 + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId
925 + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion();
926 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
927 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
929 throw new VnfException(error, MsoExceptionCategory.USERDATA);
932 logger.debug("bypassing testing AIC version...");
934 } // let this error out downstream to avoid introducing uncertainty at this stage
936 logger.debug("cloudConfig is NULL - cannot check cloud site version");
940 "AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked"
943 // End Version check 1607
947 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
948 HeatTemplate heatTemplate = null;
949 HeatEnvironment heatEnvironment = null;
951 // This will handle old Gamma BrocadeVCE VNF
952 heatTemplate = vnfResource.getHeatTemplates();
955 if (isVolumeRequest) {
956 heatTemplate = vf.getVolumeHeatTemplate();
957 heatEnvironment = vfmc.getVolumeHeatEnv();
959 heatTemplate = vf.getModuleHeatTemplate();
960 heatEnvironment = vfmc.getHeatEnvironment();
965 if (heatTemplate == null) {
966 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
967 + ", reqType=" + requestTypeString;
968 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
969 vfModuleType, "OpenStack", ErrorCode.DataError.getValue(), error);
971 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
973 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
977 // This will handle old Gamma BrocadeVCE VNF
978 logger.debug("No environment parameter found for this Type " + vfModuleType);
980 if (heatEnvironment == null) {
981 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
982 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
983 "OpenStack", ErrorCode.DataError.getValue(), error);
985 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
987 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
991 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
992 + heatTemplate.getArtifactUuid());
995 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
996 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
997 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
998 // for debugging print them out
999 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
1000 for (HeatTemplate entry : nestedTemplates) {
1001 nestedTemplatesChecked.put(entry.getTemplateName(), entry.getTemplateBody());
1002 logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody());
1005 logger.debug("No nested templates found - nothing to do here");
1006 nestedTemplatesChecked = null;
1009 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1010 // *if* there are any
1011 List<HeatFiles> heatFiles = null;
1013 Map<String, Object> heatFilesObjects = new HashMap<>();
1015 // Add ability to turn on adding get_files with volume requests (by property).
1016 boolean addGetFilesOnVolumeReq = false;
1018 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1019 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1020 addGetFilesOnVolumeReq = true;
1021 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
1023 } catch (Exception e) {
1024 logger.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1025 + " - default to false", e);
1028 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1031 "In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat "
1034 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1036 "In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1037 + vf.getModelUUID());
1038 heatFiles = vf.getHeatFiles();
1040 if (heatFiles != null && !heatFiles.isEmpty()) {
1041 // add these to stack - to be done in createStack
1042 // here, we will map them to Map<String, Object> from
1043 // Map<String, HeatFiles>
1044 // this will match the nested templates format
1045 logger.debug("Contents of heatFiles - to be added to files: on stack");
1047 for (HeatFiles heatfile : heatFiles) {
1048 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
1049 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1052 logger.debug("No heat files found -nothing to do here");
1053 heatFilesObjects = null;
1057 // Check that required parameters have been supplied
1058 String missingParams = null;
1059 List<String> paramList = new ArrayList<>();
1061 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1062 // supplied an alias. Only check if we don't find it initially.
1063 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1064 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1066 boolean checkRequiredParameters = true;
1068 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1069 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1070 checkRequiredParameters = false;
1071 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1072 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1074 } catch (Exception e) {
1075 // No problem - default is true
1076 logger.debug("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1078 // 1604 - Add enhanced environment & parameter checking
1079 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1080 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1081 // Note this also removes any comments
1082 MsoHeatEnvironmentEntry mhee = null;
1083 if (heatEnvironment != null && heatEnvironment.getEnvironment() != null
1084 && heatEnvironment.getEnvironment().contains("parameters:")) {
1086 logger.debug("Enhanced environment checking enabled - 1604");
1087 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1089 mhee = new MsoHeatEnvironmentEntry(sb);
1090 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1091 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1092 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1094 if (!mhee.isValid()) {
1095 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1097 sb2.append("\nEnvironment:");
1098 sb2.append(mhee.toFullString());
1100 logger.debug(sb2.toString());
1102 logger.debug("NO ENVIRONMENT for this entry");
1104 // New with 1707 - all variables converted to their native object types
1105 Map<String, Object> goldenInputs = null;
1107 logger.debug("Now handle the inputs....first convert");
1108 ArrayList<String> parameterNames = new ArrayList<>();
1109 HashMap<String, String> aliasToParam = new HashMap<>();
1110 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1113 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1114 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1115 parameterNames.add(htp.getParamName());
1116 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1117 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1118 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1122 logger.debug(sb.toString());
1123 } catch (Exception e) {
1124 logger.debug("??An exception occurred trying to go through Parameter Names {}", e.getMessage(), e);
1126 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1127 // Map<String, Object> - where the object matches the param type identified in the template
1128 // This will also not copy over params that aren't identified in the template
1129 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1130 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1131 logger.debug("Now add in the base stack outputs if applicable");
1132 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1133 // Step 3 - add the volume inputs if any
1134 logger.debug("Now add in the volume stack outputs if applicable");
1135 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1137 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1138 logger.debug("Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias="
1139 + parm.getParamAlias());
1141 if (parm.isRequired() && (goldenInputs == null || !goldenInputs.containsKey(parm.getParamName()))) {
1142 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the
1143 // Map<String, String> to Map<String, Object>
1144 logger.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check "
1146 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1147 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1148 parm.getParamName());
1150 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1151 if (missingParams == null) {
1152 missingParams = parm.getParamName();
1154 missingParams += "," + parm.getParamName();
1158 paramList.add(parm.getParamName());
1160 if (missingParams != null) {
1161 if (checkRequiredParameters) {
1162 // Problem - missing one or more required parameters
1163 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1164 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "OpenStack",
1165 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1166 logger.debug(error);
1167 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1169 logger.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1172 logger.debug("No missing parameters found - ok to proceed");
1174 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1175 // and it causes problems with json that has arrays
1176 String newEnvironmentString = null;
1178 newEnvironmentString = mhee.getRawEntry().toString();
1181 // "Fix" the template if it has CR/LF (getting this from Oracle)
1182 String template = heatTemplate.getHeatTemplate();
1183 template = template.replaceAll("\r\n", "\n");
1186 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1187 boolean failRequestOnValetFailure =
1188 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1189 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1190 if (oldWay || isVolumeRequest) {
1191 isValetEnabled = false;
1192 logger.debug("do not send to valet for volume requests or brocade");
1194 boolean sendResponseToValet = false;
1195 if (isValetEnabled) {
1196 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1197 sendResponseToValet = this.valetCreateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
1198 nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs,
1199 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1200 if (sendResponseToValet) {
1201 goldenInputs = valetModifiedParamsHolder.value;
1205 // Have the tenant. Now deploy the stack itself
1206 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1207 // because we already checked for those.
1208 long createStackStarttime = System.currentTimeMillis();
1210 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1211 // heatTemplate.getTimeoutMinutes());
1212 if (backout == null) {
1216 logger.debug("heat is not null!!");
1218 heatStack = heat.createStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, null, template,
1219 goldenInputs, true, heatTemplate.getTimeoutMinutes(), newEnvironmentString,
1220 nestedTemplatesChecked, heatFilesObjects, backout.booleanValue());
1222 logger.debug("heat is null!");
1223 throw new MsoHeatNotFoundException();
1225 } catch (MsoException me) {
1226 me.addContext("CreateVFModule");
1227 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1228 + tenantId + ": " + me;
1229 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1230 cloudOwner, cloudSiteId, tenantId, "OpenStack", ErrorCode.DataError.getValue(),
1231 "MsoException - createStack", me);
1232 logger.debug(error);
1233 if (isValetEnabled && sendResponseToValet) {
1234 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1236 GenericValetResponse<ValetRollbackResponse> gvr = this.vci
1237 .callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage());
1238 // Nothing to really do here whether it succeeded or not other than log it.
1239 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1240 } catch (Exception e) {
1241 logger.error("Exception encountered while sending Rollback to Valet ", e);
1244 throw new VnfException(me);
1245 } catch (NullPointerException npe) {
1246 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/"
1247 + tenantId + ": " + npe;
1248 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType,
1249 cloudOwner, cloudSiteId, tenantId, "OpenStack", ErrorCode.DataError.getValue(),
1250 "NullPointerException - createStack", npe);
1251 logger.debug(error);
1252 logger.debug("NULL POINTER EXCEPTION at heat.createStack");
1253 // npe.addContext ("CreateVNF");
1254 throw new VnfException("NullPointerException during heat.createStack");
1255 } catch (Exception e) {
1256 logger.debug("unhandled exception at heat.createStack", e);
1257 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1259 // Reach this point if createStack is successful.
1260 // Populate remaining rollback info and response parameters.
1261 vfRollback.setVnfId(heatStack.getCanonicalName());
1262 vfRollback.setVnfCreated(true);
1264 vnfId.value = heatStack.getCanonicalName();
1265 outputs.value = copyStringOutputs(heatStack.getOutputs());
1266 rollback.value = vfRollback;
1267 if (isValetEnabled && sendResponseToValet) {
1268 logger.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id");
1270 GenericValetResponse<ValetConfirmResponse> gvr =
1271 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1272 // Nothing to really do here whether it succeeded or not other than log it.
1273 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1274 } catch (Exception e) {
1275 logger.error("Exception encountered while sending Confirm to Valet ", e);
1278 logger.debug("VF Module {} successfully created", vfModuleName);
1280 heatbridge(heatStack, cloudOwner, cloudSiteId, tenantId, genericVnfName, vfModuleId);
1282 } catch (Exception e) {
1283 logger.debug("unhandled exception in create VF", e);
1284 throw new VnfException("Exception during create VF " + e.getMessage());
1289 public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName,
1290 MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException {
1292 logger.debug("Deleting VF {} in ", vnfName, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1293 // Will capture execution time for metrics
1294 long startTime = System.currentTimeMillis();
1296 // 1702 capture the output parameters on a delete
1297 // so we'll need to query first
1298 Map<String, Object> stackOutputs = null;
1300 stackOutputs = heat.queryStackForOutputs(cloudSiteId, cloudOwner, tenantId, vnfName);
1301 } catch (MsoException me) {
1302 // Failed to query the Stack due to an openstack exception.
1303 // Convert to a generic VnfException
1304 me.addContext("DeleteVFModule");
1305 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId
1306 + "/" + tenantId + ": " + me;
1307 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1308 cloudSiteId, tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(),
1309 "Exception - QueryStack", me);
1310 logger.debug(error);
1311 throw new VnfException(me);
1313 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected
1315 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1317 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1318 boolean failRequestOnValetFailure =
1319 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1320 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1321 boolean valetDeleteRequestSucceeded = false;
1322 if (isValetEnabled) {
1323 valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, cloudOwner, tenantId, vnfName,
1324 msoRequest, failRequestOnValetFailure);
1327 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1328 // The possible outcomes of deleteStack are a StackInfo object with status
1329 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1331 long subStartTime = System.currentTimeMillis();
1333 heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true);
1334 } catch (MsoException me) {
1335 me.addContext("DeleteVNF");
1336 // Failed to query the Stack due to an openstack exception.
1337 // Convert to a generic VnfException
1339 "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1340 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner,
1341 cloudSiteId, tenantId, "OpenStack", "DeleteStack", ErrorCode.DataError.getValue(),
1342 "Exception - deleteStack", me);
1343 logger.debug(error);
1344 if (isValetEnabled && valetDeleteRequestSucceeded) {
1345 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1347 GenericValetResponse<ValetRollbackResponse> gvr = this.vci
1348 .callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage());
1349 // Nothing to really do here whether it succeeded or not other than log it.
1350 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1351 } catch (Exception e) {
1352 logger.error("Exception encountered while sending Rollback to Valet ", e);
1355 throw new VnfException(me);
1357 if (isValetEnabled && valetDeleteRequestSucceeded) {
1358 // only if the original request succeeded do we send a confirm
1359 logger.debug("valet is enabled, the delete succeeded - now send confirm to valet");
1361 GenericValetResponse<ValetConfirmResponse> gvr =
1362 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName);
1363 // Nothing to really do here whether it succeeded or not other than log it.
1364 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1365 } catch (Exception e) {
1366 logger.error("Exception encountered while sending Confirm to Valet ", e);
1370 // On success, nothing is returned.
1375 public void updateVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfType,
1376 String vnfVersion, String vnfName, String requestType, String volumeGroupHeatStackId,
1377 String baseVfHeatStackId, String vfModuleStackId, String modelCustomizationUuid, Map<String, Object> inputs,
1378 MsoRequest msoRequest, Holder<Map<String, String>> outputs, Holder<VnfRollback> rollback)
1379 throws VnfException {
1380 String vfModuleName = vnfName;
1381 String vfModuleType = vnfType;
1382 String methodName = "updateVfModule";
1383 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1385 StringBuilder sbInit = new StringBuilder();
1386 sbInit.append("updateVfModule: \n");
1387 sbInit.append("cloudOwner=" + cloudOwner + "\n");
1388 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1389 sbInit.append("tenantId=" + tenantId + "\n");
1390 sbInit.append("vnfType=" + vnfType + "\n");
1391 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1392 sbInit.append("vnfName=" + vnfName + "\n");
1393 sbInit.append("requestType=" + requestType + "\n");
1394 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1395 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1396 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1397 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1398 logger.debug(sbInit.toString());
1400 String mcu = modelCustomizationUuid;
1401 boolean useMCUuid = false;
1402 if (mcu != null && !mcu.isEmpty()) {
1403 if ("null".equalsIgnoreCase(mcu)) {
1404 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: {}",
1405 modelCustomizationUuid);
1409 logger.debug("Found modelCustomizationUuid! Will use that: {}", mcu);
1414 String requestTypeString = "";
1415 if (requestType != null && !"".equals(requestType)) {
1416 requestTypeString = requestType;
1419 String nestedStackId = null;
1420 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)
1421 && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1422 nestedStackId = volumeGroupHeatStackId;
1424 String nestedBaseStackId = null;
1425 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
1426 nestedBaseStackId = baseVfHeatStackId;
1429 if (inputs == null) {
1430 // Create an empty set of inputs
1431 inputs = new HashMap<>();
1432 logger.debug("inputs == null - setting to empty");
1435 boolean isBaseRequest = false;
1436 boolean isVolumeRequest = false;
1437 if (requestTypeString.startsWith("VOLUME")) {
1438 isVolumeRequest = true;
1440 if ((vfModuleName == null || "".equals(vfModuleName.trim())) && vfModuleStackId != null) {
1441 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1444 logger.debug("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudOwner + "/"
1445 + cloudSiteId + "/" + tenantId);
1446 logger.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId
1447 + ", nestedBaseStackId = " + nestedBaseStackId);
1449 // Will capture execution time for metrics
1450 long startTime = System.currentTimeMillis();
1452 // Build a default rollback object (no actions performed)
1453 VnfRollback vfRollback = new VnfRollback();
1454 vfRollback.setCloudSiteId(cloudSiteId);
1455 vfRollback.setCloudOwner(cloudOwner);
1456 vfRollback.setTenantId(tenantId);
1457 vfRollback.setMsoRequest(msoRequest);
1458 vfRollback.setRequestType(requestTypeString);
1459 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1460 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1461 vfRollback.setIsBase(isBaseRequest);
1462 vfRollback.setVfModuleStackId(vfModuleStackId);
1463 vfRollback.setModelCustomizationUuid(mcu);
1465 StackInfo heatStack = null;
1466 long queryStackStarttime = System.currentTimeMillis();
1467 logger.debug("UpdateVfModule - querying for {}", vfModuleName);
1469 heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName);
1470 } catch (MsoException me) {
1471 // Failed to query the Stack due to an openstack exception.
1472 // Convert to a generic VnfException
1473 me.addContext("UpdateVFModule");
1474 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/"
1475 + tenantId + ": " + me;
1476 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
1477 cloudOwner, cloudSiteId, tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(),
1478 "Exception - QueryStack", me);
1479 logger.debug(error);
1480 throw new VnfException(me);
1483 // TODO - do we need to check for the other status possibilities?
1484 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
1486 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudOwner + "/" + cloudSiteId
1488 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_NOT_EXIST.toString(), vfModuleName,
1489 cloudOwner, cloudSiteId, tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(),
1491 throw new VnfNotFound(cloudSiteId, cloudOwner, tenantId, vfModuleName);
1493 logger.debug("Found Existing stack, status={}", heatStack.getStatus());
1494 // Populate the outputs from the existing stack.
1495 outputs.value = copyStringOutputs(heatStack.getOutputs());
1496 rollback.value = vfRollback; // Default rollback - no updates performed
1499 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1500 StackInfo nestedHeatStack = null;
1501 long queryStackStarttime2 = System.currentTimeMillis();
1502 Map<String, Object> nestedVolumeOutputs = null;
1503 if (nestedStackId != null) {
1505 logger.debug("Querying for nestedStackId = {}", nestedStackId);
1506 nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
1507 } catch (MsoException me) {
1508 // Failed to query the Stack due to an openstack exception.
1509 // Convert to a generic VnfException
1510 me.addContext("UpdateVFModule");
1511 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner + "/"
1512 + cloudSiteId + "/" + tenantId + ": " + me;
1513 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner,
1514 cloudSiteId, tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(),
1515 "Exception - " + error, me);
1516 logger.debug("ERROR trying to query nested stack= {}", error);
1517 throw new VnfException(me);
1519 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1520 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in "
1521 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
1522 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName,
1523 cloudOwner, cloudSiteId, tenantId, error, "OpenStack", "QueryStack",
1524 ErrorCode.DataError.getValue(), error);
1525 logger.debug(error);
1526 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1528 logger.debug("Found nested heat stack - copying values to inputs *later*");
1529 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1530 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1533 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1534 StackInfo nestedBaseHeatStack = null;
1535 Map<String, Object> baseStackOutputs = null;
1536 if (nestedBaseStackId != null) {
1537 long queryStackStarttime3 = System.currentTimeMillis();
1539 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
1540 nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
1541 } catch (MsoException me) {
1542 // Failed to query the Stack due to an openstack exception.
1543 // Convert to a generic VnfException
1544 me.addContext("UpdateVfModule");
1545 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in "
1546 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1547 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
1548 cloudOwner, cloudSiteId, tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(),
1549 "Exception - " + error, me);
1550 logger.debug("ERROR trying to query nested base stack= {}", error);
1551 throw new VnfException(me);
1553 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1554 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId
1555 + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR";
1556 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
1557 cloudOwner, cloudSiteId, tenantId, error, "OpenStack", "QueryStack",
1558 ErrorCode.DataError.getValue(), error);
1559 logger.debug(error);
1560 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1562 logger.debug("Found nested base heat stack - copying values to inputs *later*");
1563 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1564 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1568 // Ready to deploy the new VNF
1572 // Retrieve the VF definition
1573 VnfResource vnfResource = null;
1575 VfModuleCustomization vfmc = null;
1577 vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid);
1578 vf = vfmc != null ? vfmc.getVfModule() : null;
1580 logger.debug("Unable to find a vfModule matching modelCustomizationUuid={}", mcu);
1583 logger.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1586 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1587 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VF Module Type",
1588 vfModuleType, "OpenStack", ErrorCode.DataError.getValue(), error);
1589 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1591 logger.debug("Got VF module definition from Catalog: {}", vf.toString());
1592 if (vf.getIsBase()) {
1593 isBaseRequest = true;
1594 logger.debug("This a BASE update request");
1596 logger.debug("This is *not* a BASE VF update request");
1597 if (!isVolumeRequest && nestedBaseStackId == null) {
1599 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1603 // 1607 - Add version check
1604 // First - see if it's in the VnfResource record
1605 // if we have a vf Module - then we have to query to get the VnfResource record.
1606 if (vf.getModelUUID() != null) {
1607 String vnfResourceModelUuid = vf.getModelUUID();
1609 vnfResource = vf.getVnfResources();
1610 if (vnfResource == null) {
1611 logger.debug("Unable to find vnfResource at ? will not error for now...", vnfResourceModelUuid);
1615 String minVersionVnf = null;
1616 String maxVersionVnf = null;
1617 if (vnfResource != null) {
1619 minVersionVnf = vnfResource.getAicVersionMin();
1620 maxVersionVnf = vnfResource.getAicVersionMax();
1621 } catch (Exception e) {
1622 logger.debug("Unable to pull min/max version for this VNF Resource entry", e);
1623 minVersionVnf = null;
1624 maxVersionVnf = null;
1626 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1627 minVersionVnf = null;
1629 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1630 maxVersionVnf = null;
1633 if (minVersionVnf != null && maxVersionVnf != null) {
1634 MavenLikeVersioning aicV = new MavenLikeVersioning();
1637 if (this.cloudConfig != null) {
1638 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1639 if (cloudSiteOpt.isPresent()) {
1640 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
1641 boolean moreThanMin = true;
1642 boolean equalToMin = true;
1643 boolean moreThanMax = true;
1644 boolean equalToMax = true;
1645 boolean doNotTest = false;
1647 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1648 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1649 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1650 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1651 } catch (Exception e) {
1653 "An exception occured while trying to test AIC Version {} - will default to not check",
1658 if ((moreThanMin || equalToMin) // aic >= min
1659 && ((equalToMax) || !(moreThanMax))) { // aic <= max
1660 logger.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1661 + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId
1662 + " with AIC_Version:" + aicV);
1665 String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin="
1666 + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: "
1667 + cloudSiteId + " with AIC_Version:" + aicV;
1668 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
1669 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
1670 logger.debug(error);
1671 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1674 logger.debug("bypassing testing AIC version...");
1676 } // let this error out downstream to avoid introducing uncertainty at this stage
1678 logger.debug("cloudConfig is NULL - cannot check cloud site version");
1682 logger.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1684 // End Version check 1607
1686 HeatTemplate heatTemplate = null;
1687 HeatEnvironment heatEnvironment = null;
1688 if (isVolumeRequest) {
1689 heatTemplate = vf.getVolumeHeatTemplate();
1690 heatEnvironment = vfmc.getVolumeHeatEnv();
1692 heatTemplate = vf.getModuleHeatTemplate();
1693 heatEnvironment = vfmc.getHeatEnvironment();
1696 if (heatTemplate == null) {
1697 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType
1698 + ", reqType=" + requestTypeString;
1699 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID",
1700 vfModuleType, "OpenStack", ErrorCode.DataError.getValue(), error);
1701 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1703 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
1706 if (heatEnvironment == null) {
1707 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
1708 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
1709 "OpenStack", ErrorCode.DataError.getValue(), error);
1710 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1712 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
1715 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId={}",
1716 heatTemplate.getArtifactUuid());
1719 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1720 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1721 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1722 // for debugging print them out
1723 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
1724 for (HeatTemplate entry : nestedTemplates) {
1726 nestedTemplatesChecked.put(entry.getTemplateName(), entry.getTemplateBody());
1727 logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody());
1730 logger.debug("No nested templates found - nothing to do here");
1731 nestedTemplatesChecked = null;
1734 // Also add the files: for any get_files associated with this VfModule
1735 // *if* there are any
1736 logger.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId={}",
1739 List<HeatFiles> heatFiles = null;
1740 Map<String, Object> heatFilesObjects = new HashMap<>();
1742 // Add ability to turn on adding get_files with volume requests (by property).
1743 boolean addGetFilesOnVolumeReq = false;
1745 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1746 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1747 addGetFilesOnVolumeReq = true;
1748 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
1750 } catch (Exception e) {
1751 logger.debug("An error occured trying to get property {} - default to false",
1752 MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, e);
1754 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1755 logger.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec "
1756 + "vfModuleId={}", vf.getModelUUID());
1758 heatFiles = vf.getHeatFiles();
1759 if (heatFiles != null && !heatFiles.isEmpty()) {
1760 // add these to stack - to be done in createStack
1761 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1762 // this will match the nested templates format
1763 logger.debug("Contents of heatFiles - to be added to files: on stack:");
1764 for (HeatFiles heatfile : heatFiles) {
1765 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
1766 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1769 logger.debug("No heat files found -nothing to do here");
1770 heatFilesObjects = null;
1774 // Check that required parameters have been supplied
1775 String missingParams = null;
1776 List<String> paramList = new ArrayList<>();
1778 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1779 // supplied an alias. Only check if we don't find it initially.
1780 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1781 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1783 boolean checkRequiredParameters = true;
1785 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1786 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1787 checkRequiredParameters = false;
1788 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking...",
1789 MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1791 } catch (Exception e) {
1792 // No problem - default is true
1793 logger.debug("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1795 // 1604 - Add enhanced environment & parameter checking
1796 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1797 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1798 // Note this also removes any comments
1799 MsoHeatEnvironmentEntry mhee = null;
1800 if (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase().contains("parameters:")) {
1801 logger.debug("Enhanced environment checking enabled - 1604");
1802 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1803 mhee = new MsoHeatEnvironmentEntry(sb);
1804 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1805 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1806 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1808 if (!mhee.isValid()) {
1809 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1811 sb2.append("\nEnvironment:");
1812 sb2.append(mhee.toFullString());
1814 logger.debug(sb2.toString());
1816 logger.debug("NO ENVIRONMENT for this entry");
1818 // New for 1607 - support params of json type
1819 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1820 boolean hasJson = false;
1822 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1823 logger.debug("Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias="
1824 + parm.getParamAlias());
1826 String parameterType = parm.getParamType();
1827 if (parameterType == null || "".equals(parameterType.trim())) {
1828 parameterType = "String";
1830 JsonNode jsonNode = null;
1831 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1832 if (inputs.containsKey(parm.getParamName())) {
1834 String jsonString = null;
1836 jsonString = JSON_MAPPER.writeValueAsString(inputs.get(parm.getParamName()));
1837 jsonNode = JSON_MAPPER.readTree(jsonString);
1838 } catch (JsonParseException jpe) {
1839 // TODO - what to do here?
1840 // for now - send the error to debug
1841 logger.debug("Json Error Converting {} - {}", parm.getParamName(), jpe.getMessage(), jpe);
1844 } catch (Exception e) {
1846 logger.debug("Json Error Converting {} {}", parm.getParamName(), e.getMessage(), e);
1850 if (jsonNode != null) {
1851 jsonParams.put(parm.getParamName(), jsonNode);
1853 } else if (inputs.containsKey(parm.getParamAlias())) {
1855 String jsonString = null;
1857 jsonString = (String) inputs.get(parm.getParamAlias());
1858 jsonNode = JSON_MAPPER.readTree(jsonString);
1859 } catch (JsonParseException jpe) {
1860 // TODO - what to do here?
1861 // for now - send the error to debug, but just leave it as a String
1862 String errorMessage = jpe.getMessage();
1863 logger.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1866 } catch (Exception e) {
1868 logger.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1872 if (jsonNode != null) {
1873 // Notice here - we add it to the jsonParams hashMap with the actual name -
1874 // then manipulate the inputs so when we check for aliases below - it will not
1876 jsonParams.put(parm.getParamName(), jsonNode);
1877 inputs.remove(parm.getParamAlias());
1878 inputs.put(parm.getParamName(), jsonString);
1880 } // TODO add a check for the parameter in the env file
1883 if (parm.isRequired() && (inputs == null || !inputs.containsKey(parm.getParamName()))) {
1884 if (inputs.containsKey(parm.getParamAlias())) {
1885 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1886 String realParamName = parm.getParamName();
1887 String alias = parm.getParamAlias();
1888 Object value = inputs.get(alias);
1889 logger.debug("*Found an Alias: paramName=" + realParamName + ",alias=" + alias + ",value=" + value);
1890 inputs.remove(alias);
1891 inputs.put(realParamName, value);
1892 logger.debug("{} entry removed from inputs, added back using {}", alias, realParamName);
1894 // enhanced - check if it's in the Environment (note: that method
1895 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1897 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1898 parm.getParamName());
1900 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1901 if (missingParams == null) {
1902 missingParams = parm.getParamName();
1904 missingParams += "," + parm.getParamName();
1908 paramList.add(parm.getParamName());
1912 if (missingParams != null) {
1913 // Problem - missing one or more required parameters
1914 if (checkRequiredParameters) {
1915 String error = "Update VNF: Missing Required inputs: " + missingParams;
1916 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "OpenStack",
1917 ErrorCode.DataError.getValue(), error);
1918 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1920 logger.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1923 logger.debug("No missing parameters found - ok to proceed");
1926 // Just submit the envt entry as received from the database
1927 String newEnvironmentString = null;
1929 newEnvironmentString = mhee.getRawEntry().toString();
1931 // Remove any extraneous parameters (don't throw an error)
1932 if (inputs != null) {
1933 List<String> extraParams = new ArrayList<>();
1934 extraParams.addAll(inputs.keySet());
1935 // This is not a valid parameter for this template
1936 extraParams.removeAll(paramList);
1937 if (!extraParams.isEmpty()) {
1938 logger.warn("{} {} {} {} {} {}", MessageEnum.RA_VNF_EXTRA_PARAM.toString(), vnfType,
1939 extraParams.toString(), "OpenStack", ErrorCode.DataError.getValue(), "Extra params");
1940 inputs.keySet().removeAll(extraParams);
1943 Map<String, Object> goldenInputs = copyStringInputs(inputs);
1944 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
1945 Map<String, Object> inputsTwo = null;
1946 if (hasJson && jsonParams.size() > 0) {
1947 inputsTwo = new HashMap<>();
1948 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
1949 String keyParamName = entry.getKey();
1950 Object value = entry.getValue();
1951 if (jsonParams.containsKey(keyParamName)) {
1952 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
1954 inputsTwo.put(keyParamName, value);
1957 goldenInputs = inputsTwo;
1960 // "Fix" the template if it has CR/LF (getting this from Oracle)
1961 String template = heatTemplate.getHeatTemplate();
1962 template = template.replaceAll("\r\n", "\n");
1964 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1965 boolean failRequestOnValetFailure =
1966 this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1967 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1968 if (isVolumeRequest) {
1969 isValetEnabled = false;
1970 logger.debug("never send a volume request to valet");
1972 boolean sendResponseToValet = false;
1973 if (isValetEnabled) {
1974 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1975 String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1976 // Make sure it is set to something.
1977 if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) {
1978 parsedVfModuleName = "unknown";
1980 sendResponseToValet = this.valetUpdateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
1981 nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString,
1982 (HashMap<String, Object>) goldenInputs, msoRequest, inputs, failRequestOnValetFailure,
1983 valetModifiedParamsHolder);
1984 if (sendResponseToValet) {
1985 goldenInputs = valetModifiedParamsHolder.value;
1989 // Have the tenant. Now deploy the stack itself
1990 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1991 // because we already checked for those.
1992 long updateStackStarttime = System.currentTimeMillis();
1994 heatStack = heatU.updateStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, template, goldenInputs, true,
1995 heatTemplate.getTimeoutMinutes(), newEnvironmentString,
1996 // heatEnvironmentString,
1997 nestedTemplatesChecked, heatFilesObjects);
1998 } catch (MsoException me) {
1999 me.addContext("UpdateVFModule");
2000 String error = "Update VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId
2002 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_UPDATE_VNF_ERR.toString(), vfModuleType, cloudOwner,
2003 cloudSiteId, tenantId, "OpenStack", ErrorCode.DataError.getValue(), "Exception - " + error, me);
2004 if (isValetEnabled && sendResponseToValet) {
2005 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
2007 GenericValetResponse<ValetRollbackResponse> gvr =
2008 this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage());
2009 // Nothing to really do here whether it succeeded or not other than log it.
2010 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
2011 } catch (Exception e) {
2012 logger.error("Exception encountered while sending Rollback to Valet ", e);
2015 throw new VnfException(me);
2019 // Reach this point if updateStack is successful.
2020 // Populate remaining rollback info and response parameters.
2021 vfRollback.setVnfId(heatStack.getCanonicalName());
2022 vfRollback.setVnfCreated(true);
2024 if (isValetEnabled && sendResponseToValet) {
2025 logger.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id");
2027 GenericValetResponse<ValetConfirmResponse> gvr =
2028 this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
2029 // Nothing to really do here whether it succeeded or not other than log it.
2030 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
2031 } catch (Exception e) {
2032 logger.error("Exception encountered while sending Confirm to Valet ", e);
2036 outputs.value = copyStringOutputs(heatStack.getOutputs());
2037 rollback.value = vfRollback;
2041 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2042 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2043 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2044 if (vfModuleStackId == null)
2046 int index = vfModuleStackId.lastIndexOf('/');
2049 String vfModuleName = null;
2051 vfModuleName = vfModuleStackId.substring(0, index);
2052 } catch (Exception e) {
2053 logger.debug("Exception", e);
2054 vfModuleName = null;
2056 return vfModuleName;
2060 * Helper method to check a boolean property value - on error return provided default
2062 private boolean checkBooleanProperty(String propertyName, boolean defaultValue) {
2063 boolean property = defaultValue;
2065 String propertyString = this.environment.getProperty(propertyName);
2066 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
2068 } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
2071 } catch (Exception e) {
2072 logger.debug("An exception occured trying to get property {} - defaulting to ", propertyName, defaultValue,
2074 property = defaultValue;
2080 * Helper method to combine getFiles and nestedTemplates in to a single Map
2082 private Map<String, Object> combineGetFilesAndNestedTemplates(Map<String, Object> getFiles,
2083 Map<String, Object> nestedTemplates) {
2084 boolean haveGetFiles = true;
2085 boolean haveNestedTemplates = true;
2086 Map<String, Object> files = new HashMap<String, Object>();
2087 if (getFiles == null || getFiles.isEmpty()) {
2088 haveGetFiles = false;
2090 if (nestedTemplates == null || nestedTemplates.isEmpty()) {
2091 haveNestedTemplates = false;
2093 if (haveGetFiles && haveNestedTemplates) {
2094 for (String keyString : getFiles.keySet()) {
2095 files.put(keyString, getFiles.get(keyString));
2097 for (String keyString : nestedTemplates.keySet()) {
2098 files.put(keyString, nestedTemplates.get(keyString));
2101 // Handle if we only have one or neither:
2105 if (haveNestedTemplates) {
2106 files = nestedTemplates;
2113 * Valet Create request
2115 private boolean valetCreateRequest(String cloudSiteId, String cloudOwner, String tenantId,
2116 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
2117 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
2118 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure,
2119 Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2120 boolean valetSucceeded = false;
2121 String valetErrorMessage = "more detail not available";
2123 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2124 Map<String, Object> files =
2125 this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked);
2126 HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(),
2127 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2128 GenericValetResponse<ValetCreateResponse> createReq = this.vci.callValetCreateRequest(
2129 msoRequest.getRequestId(), cloudSiteId, cloudOwner, tenantId, msoRequest.getServiceInstanceId(),
2130 (String) inputs.get("vnf_id"), (String) inputs.get("vnf_name"), (String) inputs.get("vf_module_id"),
2131 (String) inputs.get("vf_module_name"), keystoneUrl, heatRequest);
2132 ValetCreateResponse vcr = createReq.getReturnObject();
2133 if (vcr != null && createReq.getStatusCode() == 200) {
2134 ValetStatus status = vcr.getStatus();
2135 if (status != null) {
2136 String statusCode = status.getStatus(); // "ok" or "failed"
2137 if ("ok".equalsIgnoreCase(statusCode)) {
2138 Map<String, Object> newInputs = vcr.getParameters();
2139 if (newInputs != null) {
2140 Map<String, Object> oldGold = goldenInputs;
2141 logger.debug("parameters before being modified by valet:{}", oldGold.toString());
2142 goldenInputs = new HashMap<String, Object>();
2143 for (String key : newInputs.keySet()) {
2144 goldenInputs.put(key, newInputs.get(key));
2146 valetModifiedParamsHolder.value = goldenInputs;
2147 logger.debug("parameters after being modified by valet:{}", goldenInputs.toString());
2148 valetSucceeded = true;
2151 valetErrorMessage = status.getMessage();
2155 logger.debug("Got a bad response back from valet");
2156 valetErrorMessage = "Bad response back from Valet";
2157 valetSucceeded = false;
2159 } catch (Exception e) {
2160 logger.error("An exception occurred trying to call valet ...", e);
2161 valetSucceeded = false;
2162 valetErrorMessage = e.getMessage();
2164 if (failRequestOnValetFailure && !valetSucceeded) {
2165 // The valet request failed - and property says to fail the request
2166 // TODO Create a new exception class for valet?
2167 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2169 return valetSucceeded;
2173 * Valet update request
2176 private boolean valetUpdateRequest(String cloudSiteId, String cloudOwnerId, String tenantId,
2177 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
2178 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
2179 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure,
2180 Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2182 boolean valetSucceeded = false;
2183 String valetErrorMessage = "more detail not available";
2185 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2186 Map<String, Object> files =
2187 this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked);
2188 HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(),
2189 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2190 // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now
2191 GenericValetResponse<ValetUpdateResponse> updateReq =
2192 this.vci.callValetUpdateRequest(msoRequest.getRequestId(), cloudSiteId, cloudOwnerId, tenantId,
2193 msoRequest.getServiceInstanceId(), (String) inputs.get("vnf_id"), vfModuleName,
2194 (String) inputs.get("vf_module_id"), vfModuleName, keystoneUrl, heatRequest);
2195 ValetUpdateResponse vur = updateReq.getReturnObject();
2196 if (vur != null && updateReq.getStatusCode() == 200) {
2197 ValetStatus status = vur.getStatus();
2198 if (status != null) {
2199 String statusCode = status.getStatus(); // "ok" or "failed"
2200 if ("ok".equalsIgnoreCase(statusCode)) {
2201 Map<String, Object> newInputs = vur.getParameters();
2202 if (newInputs != null) {
2203 Map<String, Object> oldGold = goldenInputs;
2204 logger.debug("parameters before being modified by valet:{}", oldGold.toString());
2205 goldenInputs = new HashMap<String, Object>();
2206 for (String key : newInputs.keySet()) {
2207 goldenInputs.put(key, newInputs.get(key));
2209 valetModifiedParamsHolder.value = goldenInputs;
2210 logger.debug("parameters after being modified by valet:{}", goldenInputs.toString());
2211 valetSucceeded = true;
2214 valetErrorMessage = status.getMessage();
2218 logger.debug("Got a bad response back from valet");
2219 valetErrorMessage = "Got a bad response back from valet";
2220 valetSucceeded = false;
2222 } catch (Exception e) {
2223 logger.error("An exception occurred trying to call valet - will continue processing for now...", e);
2224 valetErrorMessage = e.getMessage();
2225 valetSucceeded = false;
2227 if (failRequestOnValetFailure && !valetSucceeded) {
2228 // The valet request failed - and property says to fail the request
2229 // TODO Create a new exception class for valet?
2230 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2232 return valetSucceeded;
2236 * Valet delete request
2238 private boolean valetDeleteRequest(String cloudSiteId, String cloudOwnerId, String tenantId, String vnfName,
2239 MsoRequest msoRequest, boolean failRequestOnValetFailure) {
2240 boolean valetDeleteRequestSucceeded = false;
2241 String valetErrorMessage = "more detail not available";
2243 String vfModuleId = vnfName;
2244 String vfModuleName = vnfName;
2246 vfModuleName = vnfName.substring(0, vnfName.indexOf('/'));
2247 vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1);
2248 } catch (Exception e) {
2249 // do nothing - send what we got for vnfName for both to valet
2250 logger.error("An exception occurred trying to call MsoVnfAdapterImpl.valetDeleteRequest() method", e);
2252 GenericValetResponse<ValetDeleteResponse> deleteReq = this.vci.callValetDeleteRequest(
2253 msoRequest.getRequestId(), cloudSiteId, cloudOwnerId, tenantId, vfModuleId, vfModuleName);
2254 ValetDeleteResponse vdr = deleteReq.getReturnObject();
2255 if (vdr != null && deleteReq.getStatusCode() == 200) {
2256 ValetStatus status = vdr.getStatus();
2257 if (status != null) {
2258 String statusCode = status.getStatus(); // "ok" or "failed"
2259 if ("ok".equalsIgnoreCase(statusCode)) {
2260 logger.debug("delete request to valet returned success");
2261 valetDeleteRequestSucceeded = true;
2263 logger.debug("delete request to valet returned failure");
2264 valetDeleteRequestSucceeded = false;
2265 valetErrorMessage = status.getMessage();
2269 logger.debug("Got a bad response back from valet - delete request failed");
2270 valetDeleteRequestSucceeded = false;
2271 valetErrorMessage = "Got a bad response back from valet - delete request failed";
2273 } catch (Exception e) {
2274 logger.error("An exception occurred trying to call valet - valetDeleteRequest failed", e);
2275 valetDeleteRequestSucceeded = false;
2276 valetErrorMessage = e.getMessage();
2278 if (valetDeleteRequestSucceeded == false && failRequestOnValetFailure == true) {
2279 logger.error("ValetDeleteRequestFailed - del req still will be sent to openstack",
2280 new VnfException("ValetDeleteRequestFailedError"));
2282 return valetDeleteRequestSucceeded;