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;
37 import javax.jws.WebService;
38 import javax.xml.ws.Holder;
40 import org.apache.commons.collections.CollectionUtils;
41 import org.onap.so.adapters.valet.GenericValetResponse;
42 import org.onap.so.adapters.valet.ValetClient;
43 import org.onap.so.adapters.valet.beans.HeatRequest;
44 import org.onap.so.adapters.valet.beans.ValetConfirmResponse;
45 import org.onap.so.adapters.valet.beans.ValetCreateResponse;
46 import org.onap.so.adapters.valet.beans.ValetDeleteResponse;
47 import org.onap.so.adapters.valet.beans.ValetRollbackResponse;
48 import org.onap.so.adapters.valet.beans.ValetStatus;
49 import org.onap.so.adapters.valet.beans.ValetUpdateResponse;
50 import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
51 import org.onap.so.adapters.vnf.exceptions.VnfException;
52 import org.onap.so.adapters.vnf.exceptions.VnfNotFound;
53 import org.onap.so.client.aai.AAIResourcesClient;
54 import org.onap.so.cloud.CloudConfig;
55 import org.onap.so.db.catalog.beans.CloudIdentity;
56 import org.onap.so.db.catalog.beans.CloudSite;
57 import org.onap.so.db.catalog.beans.HeatEnvironment;
58 import org.onap.so.db.catalog.beans.HeatFiles;
59 import org.onap.so.db.catalog.beans.HeatTemplate;
60 import org.onap.so.db.catalog.beans.HeatTemplateParam;
61 import org.onap.so.db.catalog.beans.VfModule;
62 import org.onap.so.db.catalog.beans.VfModuleCustomization;
63 import org.onap.so.db.catalog.beans.VnfResource;
64 import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository;
65 import org.onap.so.db.catalog.data.repository.VnfResourceRepository;
66 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
67 import org.onap.so.entity.MsoRequest;
68 import org.onap.so.logger.ErrorCode;
69 import org.onap.so.heatbridge.HeatBridgeApi;
70 import org.onap.so.heatbridge.HeatBridgeImpl;
71 import org.onap.so.heatbridge.openstack.api.OpenstackClient;
72 import org.onap.so.logger.MessageEnum;
74 import org.onap.so.openstack.beans.HeatStatus;
75 import org.onap.so.openstack.beans.StackInfo;
76 import org.onap.so.openstack.beans.VnfRollback;
77 import org.onap.so.openstack.beans.VnfStatus;
78 import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
79 import org.onap.so.openstack.exceptions.MsoException;
80 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
81 import org.onap.so.openstack.exceptions.MsoHeatNotFoundException;
82 import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
83 import org.onap.so.openstack.utils.MsoHeatUtils;
84 import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate;
85 import org.openstack4j.model.compute.Flavor;
86 import org.openstack4j.model.compute.Image;
87 import org.openstack4j.model.compute.Server;
88 import org.openstack4j.model.heat.Resource;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91 import org.springframework.beans.factory.annotation.Autowired;
92 import org.springframework.core.env.Environment;
93 import org.springframework.stereotype.Component;
94 import org.springframework.transaction.annotation.Transactional;
96 import com.fasterxml.jackson.core.JsonParseException;
97 import com.fasterxml.jackson.databind.JsonNode;
98 import com.fasterxml.jackson.databind.ObjectMapper;
100 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf")
103 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
106 private CloudConfig cloudConfig;
109 private Environment environment;
111 private static final Logger logger = LoggerFactory.getLogger(MsoVnfAdapterImpl.class);
113 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
114 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
115 private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters";
116 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq";
117 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
118 private static final String VALET_ENABLED = "org.onap.so.adapters.vnf.valet_enabled";
119 private static final String FAIL_REQUESTS_ON_VALET_FAILURE = "org.onap.so.adapters.vnf.fail_requests_on_valet_failure";
120 private static final String SUCCESS_MSG = "Successfully received response from Open Stack";
123 private VFModuleCustomizationRepository vfModuleCustomRepo;
127 private VnfResourceRepository vnfResourceRepo;
130 private MsoHeatUtilsWithUpdate heatU;
132 private MsoHeatUtils heat;
134 private ValetClient vci;
137 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
138 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
140 public MsoVnfAdapterImpl() {
142 //DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
146 * Health Check web method. Does nothing but return to show the adapter is deployed.
149 public void healthCheck () {
150 logger.debug ("Health check call in VNF Adapter");
154 * This is the "Create VNF" web service implementation.
155 * It will create a new VNF of the requested type in the specified cloud
156 * and tenant. The tenant must exist before this service is called.
158 * If a VNF with the same name already exists, this can be considered a
159 * success or failure, depending on the value of the 'failIfExists' parameter.
161 * All VNF types will be defined in the MSO catalog. The caller must request
162 * one of these pre-defined types or an error will be returned. Within the
163 * catalog, each VNF type references (among other things) a Heat template
164 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
167 * Depending on the Heat template, a variable set of input parameters will
168 * be defined, some of which are required. The caller is responsible to
169 * pass the necessary input data for the VNF or an error will be thrown.
171 * The method returns the vnfId (the canonical name), a Map of VNF output
172 * attributes, and a VnfRollback object. This last object can be passed
173 * as-is to the rollbackVnf operation to undo everything that was created
174 * for the VNF. This is useful if a VNF is successfully created but the
175 * orchestrator fails on a subsequent operation.
177 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
178 * @param cloudOwner cloud owner of the cloud region in which to create the VNF
179 * @param tenantId Openstack tenant identifier
180 * @param vnfType VNF type key, should match a VNF definition in catalog DB
181 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
182 * @param vnfName Name to be assigned to the new VNF
183 * @param inputs Map of key=value inputs for VNF stack creation
184 * @param failIfExists Flag whether already existing VNF should be considered
185 * a success or failure
186 * @param msoRequest Request tracking information for logs
187 * @param vnfId Holder for output VNF Openstack ID
188 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
189 * @param rollback Holder for returning VnfRollback object
192 public void createVnf (String cloudSiteId,
199 String volumeGroupHeatStackId,
200 Map <String, Object> inputs,
201 Boolean failIfExists,
203 Boolean enableBridge,
204 MsoRequest msoRequest,
205 Holder <String> vnfId,
206 Holder <Map <String, String>> outputs,
207 Holder <VnfRollback> rollback) throws VnfException {
208 // parameters used for multicloud adapter
209 String genericVnfId = "";
210 String vfModuleId = "";
211 // Create a hook here to catch shortcut createVf requests:
212 if (requestType != null && requestType.startsWith("VFMOD")) {
213 logger.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
214 String newRequestType = requestType.substring(5);
215 String vfVolGroupHeatStackId = "";
216 String vfBaseHeatStackId = "";
218 if (volumeGroupHeatStackId != null) {
219 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf('|'));
220 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf('|')+1);
222 } catch (Exception e) {
223 // might be ok - both are just blank
224 logger.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
226 this.createVfModule(cloudSiteId,
235 vfVolGroupHeatStackId,
248 // createVf will know if the requestType starts with "X" that it's the "old" way
249 StringBuilder newRequestTypeSb = new StringBuilder("X");
250 String vfVolGroupHeatStackId = "";
251 String vfBaseHeatStackId = "";
252 if (requestType != null) {
253 newRequestTypeSb.append(requestType);
255 this.createVfModule(cloudSiteId,
263 newRequestTypeSb.toString(),
264 vfVolGroupHeatStackId,
276 // End createVf shortcut
280 public void updateVnf(String cloudSiteId,
287 String volumeGroupHeatStackId,
288 Map <String, Object> inputs,
289 MsoRequest msoRequest,
290 Holder <Map <String, String>> outputs,
291 Holder <VnfRollback> rollback) throws VnfException {
292 // As of 1707 - this method should no longer be called
293 logger.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
297 * This is the "Query VNF" web service implementation.
298 * It will look up a VNF by name or ID in the specified cloud and tenant.
300 * The method returns an indicator that the VNF exists, its Openstack internal
301 * ID, its status, and the set of outputs (from when the stack was created).
303 * @param cloudSiteId CLLI code of the cloud site in which to query
304 * @param tenantId Openstack tenant identifier
305 * @param vnfName VNF Name or Openstack ID
306 * @param msoRequest Request tracking information for logs
307 * @param vnfExists Flag reporting the result of the query
308 * @param vnfId Holder for output VNF Openstack ID
309 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
312 public void queryVnf (String cloudSiteId,
316 MsoRequest msoRequest,
317 Holder <Boolean> vnfExists,
318 Holder <String> vnfId,
319 Holder <VnfStatus> status,
320 Holder <Map <String, String>> outputs) throws VnfException {
322 logger.debug("Querying VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
324 // Will capture execution time for metrics
325 long startTime = System.currentTimeMillis ();
327 StackInfo heatStack = null;
328 long subStartTime = System.currentTimeMillis ();
330 heatStack = heat.queryStack (cloudSiteId, cloudOwner, tenantId, vnfName);
331 } catch (MsoException me) {
332 me.addContext ("QueryVNF");
333 // Failed to query the Stack due to an openstack exception.
334 // Convert to a generic VnfException
335 String error = "Query VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
336 logger.error("{} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudSiteId,
337 tenantId, "OpenStack", "QueryVNF", ErrorCode.DataError.getValue(), "Exception - queryStack",
340 throw new VnfException (me);
343 // Populate the outputs based on the returned Stack information
345 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
347 vnfExists.value = Boolean.FALSE;
348 status.value = VnfStatus.NOTFOUND;
350 outputs.value = new HashMap<>(); // Return as an empty map
352 logger.debug ("VNF {} not found", vnfName);
354 vnfExists.value = Boolean.TRUE;
355 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
356 vnfId.value = heatStack.getCanonicalName ();
357 outputs.value = copyStringOutputs (heatStack.getOutputs ());
359 logger.debug ("VNF {} found, ID = {}", vnfName, vnfId.value);
365 * This is the "Delete VNF" web service implementation.
366 * It will delete a VNF by name or ID in the specified cloud and tenant.
368 * The method has no outputs.
370 * @param cloudSiteId CLLI code of the cloud site in which to delete
371 * @param cloudOwner cloud owner of the cloud region in which to delete
372 * @param tenantId Openstack tenant identifier
373 * @param vnfName VNF Name or Openstack ID
374 * @param msoRequest Request tracking information for logs
377 public void deleteVnf (String cloudSiteId,
381 MsoRequest msoRequest) throws VnfException {
383 logger.debug("Deleting VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId);
384 // Will capture execution time for metrics
385 long startTime = System.currentTimeMillis ();
387 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
388 // The possible outcomes of deleteStack are a StackInfo object with status
389 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
391 long subStartTime = System.currentTimeMillis ();
393 heat.deleteStack (tenantId, cloudOwner, cloudSiteId, vnfName, true);
394 } catch (MsoException me) {
395 me.addContext ("DeleteVNF");
396 // Failed to query the Stack due to an openstack exception.
397 // Convert to a generic VnfException
398 String error = "Delete VNF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
399 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
400 tenantId, "OpenStack", "DeleteVNF", ErrorCode.DataError.getValue(), "Exception - DeleteVNF",
403 throw new VnfException (me);
406 // On success, nothing is returned.
411 * This web service endpoint will rollback a previous Create VNF operation.
412 * A rollback object is returned to the client in a successful creation
413 * response. The client can pass that object as-is back to the rollbackVnf
414 * operation to undo the creation.
417 public void rollbackVnf (VnfRollback rollback) throws VnfException {
418 long startTime = System.currentTimeMillis ();
419 // rollback may be null (e.g. if stack already existed when Create was called)
420 if (rollback == null) {
421 logger.info(MessageEnum.RA_ROLLBACK_NULL.toString(), "OpenStack", "rollbackVnf");
425 // Get the elements of the VnfRollback object for easier access
426 String cloudSiteId = rollback.getCloudSiteId ();
427 String cloudOwner = rollback.getCloudOwner ();
428 String tenantId = rollback.getTenantId ();
429 String vnfId = rollback.getVnfId ();
431 logger.debug("Rolling Back VNF {} in {}", vnfId, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
433 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
434 // The possible outcomes of deleteStack are a StackInfo object with status
435 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
438 heat.deleteStack (tenantId, cloudOwner, cloudSiteId, vnfId, true);
439 } catch (MsoException me) {
440 // Failed to rollback the Stack due to an openstack exception.
441 // Convert to a generic VnfException
442 me.addContext ("RollbackVNF");
443 String error = "Rollback VNF: " + vnfId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
444 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfId, cloudOwner, cloudSiteId,
445 tenantId, "OpenStack", "DeleteStack", ErrorCode.DataError.getValue(),
446 "Exception - DeleteStack", me);
448 throw new VnfException (me);
453 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
454 switch (stackStatus) {
456 return VnfStatus.ACTIVE;
458 return VnfStatus.ACTIVE;
460 return VnfStatus.FAILED;
462 return VnfStatus.UNKNOWN;
466 private Map <String, String> copyStringOutputs(Map <String, Object> stackOutputs) {
467 Map <String, String> stringOutputs = new HashMap <> ();
468 for (Map.Entry<String,Object> entry : stackOutputs.entrySet ()) {
469 String key = entry.getKey();
470 Object value = entry.getValue();
472 stringOutputs.put(key, value.toString());
473 } catch (Exception e) {
474 StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs");
475 if (value instanceof Integer) { // nothing to add to the message
476 } else if (value instanceof JsonNode) {
477 msg.append(" - exception converting JsonNode");
478 } else if (value instanceof java.util.LinkedHashMap) {
479 msg.append(" exception converting LinkedHashMap");
481 msg.append(" - unable to call .toString() " + e.getMessage());
483 logger.debug(msg.toString(), e);
486 return stringOutputs;
489 private Map <String, Object> copyStringInputs (Map <String, Object> stringInputs) {
490 return new HashMap <> (stringInputs);
493 protected boolean callHeatbridge(String heatStackId) {
494 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
495 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
496 long waitTimeMs = 10000L;
499 {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner,
501 String[] envp = null;
502 File dir = new File(executionDir);
503 logger.debug("Calling HeatBridgeMain.py in {} with arguments {}", dir, Arrays.toString(cmdarray));
504 Runtime r = Runtime.getRuntime();
505 Process p = r.exec(cmdarray, envp, dir);
506 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
508 logger.debug(" HeatBridgeMain.py returned {} with code {}", wait, p.exitValue());
509 return wait && p.exitValue() == 0;
510 } catch (IOException e) {
511 logger.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
513 } catch (RuntimeException e) {
514 logger.debug(" HeatBridgeMain.py failed during runtime!" + e);
517 catch (Exception e) {
518 logger.debug(" HeatBridgeMain.py failed for unknown reasons! " + e);
523 private void heatbridge(StackInfo heatStack, String cloudSiteId, String tenantId, String genericVnfName,
526 CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
527 () -> new MsoCloudSiteNotFound(cloudSiteId));
528 CloudIdentity cloudIdentity = cloudSite.getIdentityService();
529 String heatStackId = heatStack.getCanonicalName().split("/")[1];
531 String cloudOwner = "CloudOwner";//cloud owner needs to come from bpmn-adapter
532 List<String> oobMgtNetNames = new ArrayList<>();
534 HeatBridgeApi heatBridgeClient = new HeatBridgeImpl(new AAIResourcesClient(), cloudIdentity,
535 cloudOwner, cloudSiteId, tenantId);
537 OpenstackClient openstackClient = heatBridgeClient.authenticate();
538 List<Resource> stackResources = heatBridgeClient.queryNestedHeatStackResources(heatStackId);
540 List<Server> osServers = heatBridgeClient.getAllOpenstackServers(stackResources);
542 List<Image> osImages = heatBridgeClient.extractOpenstackImagesFromServers(osServers);
544 List<Flavor> osFlavors = heatBridgeClient.extractOpenstackFlavorsFromServers(osServers);
546 logger.debug("Successfully queried heat stack{} for resources.", heatStackId);
548 if (osImages != null && !osImages.isEmpty()) {
549 heatBridgeClient.buildAddImagesToAaiAction(osImages);
550 logger.debug("Successfully built AAI actions to add images.");
552 logger.debug("No images to update to AAI.");
555 if (osFlavors != null && !osFlavors.isEmpty()) {
556 heatBridgeClient.buildAddFlavorsToAaiAction(osFlavors);
557 logger.debug("Successfully built AAI actions to add flavors.");
559 logger.debug("No flavors to update to AAI.");
563 heatBridgeClient.buildAddVserversToAaiAction(genericVnfName, vfModuleId, osServers);
564 logger.debug("Successfully queried compute resources and built AAI vserver actions.");
567 List<String> oobMgtNetIds = new ArrayList<>();
569 //if no network-id list is provided, however network-name list is
570 if (!CollectionUtils.isEmpty(oobMgtNetNames)) {
571 oobMgtNetIds = heatBridgeClient.extractNetworkIds(oobMgtNetNames);
573 heatBridgeClient.buildAddVserverLInterfacesToAaiAction(stackResources, oobMgtNetIds);
575 "Successfully queried neutron resources and built AAI actions to add l-interfaces to vservers.");
578 heatBridgeClient.submitToAai();
579 } catch (Exception ex) {
580 logger.debug("Heatbrige failed for stackId: " + heatStack.getCanonicalName(), ex);
584 private String convertNode(final JsonNode node) {
586 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
587 return JSON_MAPPER.writeValueAsString(obj);
588 } catch (JsonParseException jpe) {
589 logger.debug("Error converting json to string " + jpe.getMessage(),jpe);
590 } catch (Exception e) {
591 logger.debug("Error converting json to string " + e.getMessage(),e);
593 return "[Error converting json to string]";
596 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
597 if (objectMap == null) {
600 Map<String, String> stringMap = new HashMap<>();
601 for (String key : objectMap.keySet()) {
602 if (!stringMap.containsKey(key)) {
603 Object obj = objectMap.get(key);
604 if (obj instanceof String) {
605 stringMap.put(key, (String) objectMap.get(key));
606 } else if (obj instanceof JsonNode ){
607 // This is a bit of mess - but I think it's the least impacting
608 // let's convert it BACK to a string - then it will get converted back later
610 String str = this.convertNode((JsonNode) obj);
611 stringMap.put(key, str);
612 } catch (Exception e) {
613 logger.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
614 //okay in this instance - only string values (fqdn) are expected to be needed
616 } else if (obj instanceof java.util.LinkedHashMap) {
617 logger.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
619 String str = JSON_MAPPER.writeValueAsString(obj);
620 stringMap.put(key, str);
621 } catch (Exception e) {
622 logger.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
624 } else if (obj instanceof Integer) {
626 String str = "" + obj;
627 stringMap.put(key, str);
628 } catch (Exception e) {
629 logger.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
633 String str = obj.toString();
634 stringMap.put(key, str);
635 } catch (Exception e) {
636 logger.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
646 public void createVfModule(String cloudSiteId,
651 String genericVnfName,
655 String volumeGroupHeatStackId,
656 String baseVfHeatStackId,
657 String modelCustomizationUuid,
658 Map <String, Object> inputs,
659 Boolean failIfExists,
661 Boolean enableBridge,
662 MsoRequest msoRequest,
663 Holder <String> vnfId,
664 Holder <Map <String, String>> outputs,
665 Holder <VnfRollback> rollback) throws VnfException {
666 String vfModuleName = vnfName;
667 String vfModuleType = vnfType;
668 String vfVersion = vnfVersion;
669 String mcu = modelCustomizationUuid;
670 boolean useMCUuid = false;
671 if (mcu != null && !mcu.isEmpty()) {
672 if ("null".equalsIgnoreCase(mcu)) {
673 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
677 logger.debug("Found modelCustomizationUuid! Will use that: " + mcu);
682 String requestTypeString = "";
683 if (requestType != null && !"".equals(requestType)) {
684 requestTypeString = requestType;
686 String nestedStackId = null;
687 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
688 nestedStackId = volumeGroupHeatStackId;
690 String nestedBaseStackId = null;
691 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
692 nestedBaseStackId = baseVfHeatStackId;
695 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
696 boolean oldWay = false;
697 if (requestTypeString.startsWith("X")) {
699 logger.debug("orchestrating a VNF - *NOT* a module!");
700 requestTypeString = requestTypeString.substring(1);
703 // 1607 - let's parse out the request type we're being sent
704 boolean isBaseRequest = false;
705 boolean isVolumeRequest = false;
706 if (requestTypeString.startsWith("VOLUME")) {
707 isVolumeRequest = true;
710 logger.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
711 // Will capture execution time for metrics
712 long startTime = System.currentTimeMillis ();
714 // Build a default rollback object (no actions performed)
715 VnfRollback vfRollback = new VnfRollback();
716 vfRollback.setCloudSiteId(cloudSiteId);
717 vfRollback.setCloudOwner(cloudOwner);
718 vfRollback.setTenantId(tenantId);
719 vfRollback.setMsoRequest(msoRequest);
720 vfRollback.setRequestType(requestTypeString);
721 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
722 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
723 vfRollback.setIsBase(isBaseRequest);
724 vfRollback.setModelCustomizationUuid(mcu);
726 // Put data into A&AI through Heatstack
727 if(enableBridge != null && enableBridge) {
728 callHeatbridge(baseVfHeatStackId);
731 StackInfo heatStack = null;
732 long subStartTime1 = System.currentTimeMillis ();
734 heatStack = heat.queryStack (cloudSiteId, cloudOwner, tenantId, vfModuleName);
735 } catch (MsoException me) {
736 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
737 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, cloudSiteId,
738 tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(), "Exception - queryStack",
741 // Failed to query the Stack due to an openstack exception.
742 // Convert to a generic VnfException
743 me.addContext ("CreateVFModule");
744 throw new VnfException (me);
746 // New with 1607 - more precise handling/messaging if the stack already exists
747 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
748 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
749 HeatStatus status = heatStack.getStatus();
750 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
751 // fail - it's in progress - return meaningful error
752 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
753 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
754 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
755 "Stack " + vfModuleName + " already exists");
757 throw new VnfAlreadyExists (vfModuleName, cloudOwner, cloudSiteId, tenantId, heatStack.getCanonicalName ());
759 if (status == HeatStatus.FAILED) {
760 // fail - it exists and is in a FAILED state
761 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
762 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
763 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
764 "Stack " + vfModuleName + " already exists and is " + "in FAILED state");
766 throw new VnfAlreadyExists (vfModuleName, cloudOwner, cloudSiteId, tenantId, heatStack.getCanonicalName ());
768 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
769 // fail - it exists and is in a FAILED state
771 "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in "
772 + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
773 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
774 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
775 "Stack " + vfModuleName + " already exists and is " + "in UPDATED or UNKNOWN state");
777 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId, heatStack.getCanonicalName());
779 if (status == HeatStatus.CREATED) {
781 if (failIfExists != null && failIfExists) {
783 "Create VF: Stack " + vfModuleName + " already exists in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId;
784 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName,
785 cloudOwner, cloudSiteId, tenantId, "OpenStack", "queryStack", ErrorCode.DataError.getValue(),
786 "Stack " + vfModuleName + " already exists");
788 throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId, heatStack.getCanonicalName());
790 logger.debug ("Found Existing stack, status={}", heatStack.getStatus ());
791 // Populate the outputs from the existing stack.
792 vnfId.value = heatStack.getCanonicalName ();
793 outputs.value = copyStringOutputs (heatStack.getOutputs ());
794 rollback.value = vfRollback; // Default rollback - no updates performed
801 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
802 StackInfo nestedHeatStack = null;
803 long subStartTime2 = System.currentTimeMillis ();
804 Map<String, Object> nestedVolumeOutputs = null;
805 if (nestedStackId != null) {
807 logger.debug("Querying for nestedStackId = {}", nestedStackId);
808 nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
809 } catch (MsoException me) {
810 // Failed to query the Stack due to an openstack exception.
811 // Convert to a generic VnfException
812 me.addContext ("CreateVFModule");
813 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
814 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, cloudSiteId,
815 tenantId, "OpenStack", "queryStack", ErrorCode.BusinessProcesssError.getValue(),
816 "MsoException trying to query nested stack", me);
817 logger.debug("ERROR trying to query nested stack= {}", error);
818 throw new VnfException (me);
820 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
821 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR" ;
822 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
823 cloudOwner, cloudSiteId, tenantId, error, "OpenStack", "queryStack",
824 ErrorCode.BusinessProcesssError.getValue(),
825 "Create VFModule: Attached heatStack ID " + "DOES NOT EXIST");
827 throw new VnfException (error, MsoExceptionCategory.USERDATA);
829 logger.debug("Found nested volume heat stack - copying values to inputs *later*");
830 nestedVolumeOutputs = nestedHeatStack.getOutputs();
834 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
835 StackInfo nestedBaseHeatStack = null;
836 long subStartTime3 = System.currentTimeMillis ();
837 Map<String, Object> baseStackOutputs = null;
838 if (nestedBaseStackId != null) {
840 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
841 nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
842 } catch (MsoException me) {
843 // Failed to query the Stack due to an openstack exception.
844 // Convert to a generic VnfException
845 me.addContext ("CreateVFModule");
846 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
848 .error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, cloudSiteId,
849 tenantId, "OpenStack", "QueryStack", ErrorCode.BusinessProcesssError.getValue(),
850 "MsoException trying to query nested base stack", me);
851 logger.debug("ERROR trying to query nested base stack= {}", error);
852 throw new VnfException (me);
854 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
855 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR" ;
856 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
857 cloudOwner, cloudSiteId, tenantId, error, "OpenStack", "QueryStack",
858 ErrorCode.BusinessProcesssError.getValue(),
859 "Create VFModule: Attached base heatStack ID DOES NOT EXIST");
860 logger.debug("Exception occurred", error);
861 throw new VnfException (error, MsoExceptionCategory.USERDATA);
863 logger.debug("Found nested base heat stack - these values will be copied to inputs *later*");
864 baseStackOutputs = nestedBaseHeatStack.getOutputs();
868 // Ready to deploy the new VNF
875 VnfResource vnfResource = null;
876 VfModuleCustomization vfmc = null;
877 logger.debug("version: {}", vfVersion);
879 // 1707 - db refactoring
880 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(mcu);
882 vf=vfmc.getVfModule();
886 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
888 logger.debug("Unable to find vfModuleCust with modelCustomizationUuid={}", mcu);
889 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
890 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(),
891 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack",
892 ErrorCode.DataError.getValue(),
893 "Create VF Module: Unable to find vfModule with " + "modelCustomizationUuid=" + mcu);
895 throw new VnfException(error, MsoExceptionCategory.USERDATA);
897 logger.trace("Found vfModuleCust entry {}", vfmc.toString());
899 if (vf.getIsBase()) {
900 isBaseRequest = true;
901 logger.debug("This is a BASE VF request!");
903 logger.debug("This is *not* a BASE VF request!");
904 if (!isVolumeRequest && nestedBaseStackId == null) {
905 logger.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
910 else { // This is to support gamma only - get info from vnf_resource table
911 if (vfVersion != null && !vfVersion.isEmpty()) {
912 vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion);
914 vnfResource = vnfResourceRepo.findByModelName(vnfType);
916 if (vnfResource == null) {
917 String error = "Create VNF: Unknown VNF Type: " + vnfType;
918 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VNF Type", vnfType,
919 "OpenStack", ErrorCode.DataError.getValue(), "Create VNF: Unknown VNF Type");
921 throw new VnfException(error, MsoExceptionCategory.USERDATA);
923 logger.debug("Got VNF module definition from Catalog: {}", vnfResource.toString());
925 // By here - we have either a vf or vnfResource
927 //1607 - Add version check
928 // First - see if it's in the VnfResource record
929 // if we have a vf Module - then we have to query to get the VnfResource record.
930 if (!oldWay && vf.getVnfResources() != null) {
931 vnfResource = vf.getVnfResources();
932 if (vnfResource == null) {
933 logger.debug("Unable to find vnfResource will not error for now...");
936 String minVersionVnf = null;
937 String maxVersionVnf = null;
938 if (vnfResource != null) {
940 minVersionVnf = vnfResource.getAicVersionMin();
941 maxVersionVnf = vnfResource.getAicVersionMax();
942 } catch (Exception e) {
943 logger.debug("Unable to pull min/max version for this VNF Resource entry",e);
944 minVersionVnf = null;
945 maxVersionVnf = null;
947 if (minVersionVnf != null && "".equals(minVersionVnf)) {
948 minVersionVnf = null;
950 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
951 maxVersionVnf = null;
954 if (minVersionVnf != null && maxVersionVnf != null) {
955 MavenLikeVersioning aicV = new MavenLikeVersioning();
958 if (this.cloudConfig != null) {
959 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
960 if (cloudSiteOpt.isPresent()) {
961 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
962 // Add code to handle unexpected values in here
963 boolean moreThanMin = true;
964 boolean equalToMin = true;
965 boolean moreThanMax = true;
966 boolean equalToMax = true;
967 boolean doNotTest = false;
969 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
970 equalToMin = aicV.isTheSameVersion(minVersionVnf);
971 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
972 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
973 } catch (Exception e) {
974 logger.debug("An exception occurred while trying to test AIC Version {} - will default to not check",
979 if ((moreThanMin || equalToMin) // aic >= min
980 && (equalToMax || !(moreThanMax))) { //aic <= max
982 "VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID()
983 + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: "
984 + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion());
987 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion();
988 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
989 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
991 throw new VnfException(error, MsoExceptionCategory.USERDATA);
994 logger.debug("bypassing testing AIC version...");
996 } // let this error out downstream to avoid introducing uncertainty at this stage
998 logger.debug("cloudConfig is NULL - cannot check cloud site version");
1001 logger.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked"
1004 // End Version check 1607
1009 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1010 HeatTemplate heatTemplate = null;
1011 HeatEnvironment heatEnvironment = null;
1013 //This will handle old Gamma BrocadeVCE VNF
1014 heatTemplate = vnfResource.getHeatTemplates();
1018 if (isVolumeRequest) {
1019 heatTemplate = vf.getVolumeHeatTemplate();
1020 heatEnvironment = vfmc.getVolumeHeatEnv();
1022 heatTemplate = vf.getModuleHeatTemplate();
1023 heatEnvironment = vfmc.getHeatEnvironment();
1028 if (heatTemplate == null) {
1029 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1031 .error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID", vfModuleType,
1032 "OpenStack", ErrorCode.DataError.getValue(), error);
1033 logger.debug(error);
1034 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1036 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
1040 //This will handle old Gamma BrocadeVCE VNF
1041 logger.debug("No environment parameter found for this Type " + vfModuleType);
1043 if (heatEnvironment == null) {
1044 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
1045 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
1046 "OpenStack", ErrorCode.DataError.getValue(), error);
1047 logger.debug(error);
1048 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1050 logger.debug("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
1054 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1055 + heatTemplate.getArtifactUuid ());
1058 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1059 Map <String, Object> nestedTemplatesChecked = new HashMap <> ();
1060 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1061 // for debugging print them out
1062 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
1063 for (HeatTemplate entry : nestedTemplates) {
1064 nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody());
1065 logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody());
1068 logger.debug("No nested templates found - nothing to do here");
1069 nestedTemplatesChecked = null;
1072 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1073 // *if* there are any
1074 List<HeatFiles> heatFiles = null;
1076 Map<String, Object> heatFilesObjects = new HashMap<>();
1078 // Add ability to turn on adding get_files with volume requests (by property).
1079 boolean addGetFilesOnVolumeReq = false;
1081 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1082 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1083 addGetFilesOnVolumeReq = true;
1084 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
1086 } catch (Exception e) {
1087 logger.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1088 + " - default to false", e);
1091 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1093 logger.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat "
1096 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1097 logger.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1098 + vf.getModelUUID());
1099 heatFiles = vf.getHeatFiles();
1101 if (heatFiles != null && !heatFiles.isEmpty()) {
1102 // add these to stack - to be done in createStack
1103 // here, we will map them to Map<String, Object> from
1104 // Map<String, HeatFiles>
1105 // this will match the nested templates format
1106 logger.debug("Contents of heatFiles - to be added to files: on stack");
1108 for (HeatFiles heatfile : heatFiles) {
1109 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
1110 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1113 logger.debug("No heat files found -nothing to do here");
1114 heatFilesObjects = null;
1118 // Check that required parameters have been supplied
1119 String missingParams = null;
1120 List <String> paramList = new ArrayList <> ();
1122 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1123 // supplied an alias. Only check if we don't find it initially.
1124 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1125 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1127 boolean checkRequiredParameters = true;
1129 String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1130 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1131 checkRequiredParameters = false;
1132 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1133 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1135 } catch (Exception e) {
1136 // No problem - default is true
1137 logger.debug("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1139 // 1604 - Add enhanced environment & parameter checking
1140 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1141 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1142 // Note this also removes any comments
1143 MsoHeatEnvironmentEntry mhee = null;
1144 if (heatEnvironment != null && heatEnvironment.getEnvironment() != null && heatEnvironment.getEnvironment().contains ("parameters:")) {
1146 logger.debug("Enhanced environment checking enabled - 1604");
1147 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1149 mhee = new MsoHeatEnvironmentEntry(sb);
1150 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1151 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1152 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1154 if (!mhee.isValid()) {
1155 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1157 sb2.append("\nEnvironment:");
1158 sb2.append(mhee.toFullString());
1160 logger.debug(sb2.toString());
1162 logger.debug("NO ENVIRONMENT for this entry");
1164 // New with 1707 - all variables converted to their native object types
1165 Map<String, Object> goldenInputs = null;
1167 logger.debug("Now handle the inputs....first convert");
1168 ArrayList<String> parameterNames = new ArrayList<>();
1169 HashMap<String, String> aliasToParam = new HashMap<>();
1170 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1173 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1174 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1175 parameterNames.add(htp.getParamName());
1176 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1177 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1178 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1182 logger.debug(sb.toString());
1183 } catch (Exception e) {
1184 logger.debug("??An exception occurred trying to go through Parameter Names {}", e.getMessage(),e);
1186 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1187 // Map<String, Object> - where the object matches the param type identified in the template
1188 // This will also not copy over params that aren't identified in the template
1189 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1190 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1191 logger.debug("Now add in the base stack outputs if applicable");
1192 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1193 // Step 3 - add the volume inputs if any
1194 logger.debug("Now add in the volume stack outputs if applicable");
1195 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1197 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1199 "Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias=" + parm
1202 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1203 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1204 logger.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check "
1206 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1207 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1208 parm.getParamName());
1210 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1211 if (missingParams == null) {
1212 missingParams = parm.getParamName ();
1214 missingParams += "," + parm.getParamName ();
1218 paramList.add (parm.getParamName ());
1220 if (missingParams != null) {
1221 if (checkRequiredParameters) {
1222 // Problem - missing one or more required parameters
1223 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1224 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "OpenStack",
1225 ErrorCode.DataError.getValue(), "Create VFModule: Missing Required inputs");
1226 logger.debug(error);
1227 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1229 logger.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1232 logger.debug ("No missing parameters found - ok to proceed");
1234 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1235 // and it causes problems with json that has arrays
1236 String newEnvironmentString = null;
1238 newEnvironmentString = mhee.getRawEntry().toString();
1241 // "Fix" the template if it has CR/LF (getting this from Oracle)
1242 String template = heatTemplate.getHeatTemplate ();
1243 template = template.replaceAll ("\r\n", "\n");
1246 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1247 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1248 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1249 if (oldWay || isVolumeRequest) {
1250 isValetEnabled = false;
1251 logger.debug("do not send to valet for volume requests or brocade");
1253 boolean sendResponseToValet = false;
1254 if (isValetEnabled) {
1255 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
1256 sendResponseToValet = this.valetCreateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
1257 nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs,
1258 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
1259 if (sendResponseToValet) {
1260 goldenInputs = valetModifiedParamsHolder.value;
1264 // Have the tenant. Now deploy the stack itself
1265 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1266 // because we already checked for those.
1267 long createStackStarttime = System.currentTimeMillis ();
1269 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1270 // heatTemplate.getTimeoutMinutes());
1271 if (backout == null) {
1275 logger.debug("heat is not null!!");
1277 heatStack = heat.createStack (cloudSiteId,
1285 heatTemplate.getTimeoutMinutes(),
1286 newEnvironmentString,
1287 nestedTemplatesChecked,
1289 backout.booleanValue());
1292 logger.debug("heat is null!");
1293 throw new MsoHeatNotFoundException();
1295 } catch (MsoException me) {
1296 me.addContext ("CreateVFModule");
1297 String error = "Create VF Module " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1299 .error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner, cloudSiteId,
1300 tenantId, "OpenStack", ErrorCode.DataError.getValue(), "MsoException - createStack",
1302 logger.debug(error);
1303 if (isValetEnabled && sendResponseToValet) {
1304 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1306 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage());
1307 // Nothing to really do here whether it succeeded or not other than log it.
1308 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1309 } catch (Exception e) {
1310 logger.error("Exception encountered while sending Rollback to Valet ", e);
1313 throw new VnfException (me);
1314 } catch (NullPointerException npe) {
1315 String error = "Create VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + npe;
1317 .error("{} {} {} {} {} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR.toString(), vfModuleType, cloudOwner, cloudSiteId,
1318 tenantId, "OpenStack", ErrorCode.DataError.getValue(),
1319 "NullPointerException - createStack", npe);
1320 logger.debug(error);
1321 logger.debug("NULL POINTER EXCEPTION at heat.createStack");
1322 //npe.addContext ("CreateVNF");
1323 throw new VnfException ("NullPointerException during heat.createStack");
1324 } catch (Exception e) {
1325 logger.debug("unhandled exception at heat.createStack",e);
1326 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1328 // Reach this point if createStack is successful.
1329 // Populate remaining rollback info and response parameters.
1330 vfRollback.setVnfId (heatStack.getCanonicalName ());
1331 vfRollback.setVnfCreated (true);
1333 vnfId.value = heatStack.getCanonicalName ();
1334 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1335 rollback.value = vfRollback;
1336 if (isValetEnabled && sendResponseToValet) {
1337 logger.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id");
1339 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
1340 // Nothing to really do here whether it succeeded or not other than log it.
1341 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1342 } catch (Exception e) {
1343 logger.error("Exception encountered while sending Confirm to Valet ", e);
1346 logger.debug ("VF Module {} successfully created", vfModuleName);
1348 heatbridge(heatStack, cloudSiteId, tenantId, genericVnfName, vfModuleId);
1350 } catch (Exception e) {
1351 logger.debug("unhandled exception in create VF",e);
1352 throw new VnfException("Exception during create VF " + e.getMessage());
1357 public void deleteVfModule (String cloudSiteId,
1361 MsoRequest msoRequest,
1362 Holder <Map <String, String>> outputs) throws VnfException {
1364 logger.debug("Deleting VF {} in ", vnfName, cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1365 // Will capture execution time for metrics
1366 long startTime = System.currentTimeMillis ();
1368 // 1702 capture the output parameters on a delete
1369 // so we'll need to query first
1370 Map<String, Object> stackOutputs = null;
1372 stackOutputs = heat.queryStackForOutputs(cloudSiteId, cloudOwner, tenantId, vnfName);
1373 } catch (MsoException me) {
1374 // Failed to query the Stack due to an openstack exception.
1375 // Convert to a generic VnfException
1376 me.addContext ("DeleteVFModule");
1377 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1378 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1379 tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(), "Exception - QueryStack",
1381 logger.debug(error);
1382 throw new VnfException (me);
1384 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1385 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1387 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
1388 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
1389 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
1390 boolean valetDeleteRequestSucceeded = false;
1391 if (isValetEnabled) {
1392 valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, cloudOwner, tenantId, vnfName, msoRequest, failRequestOnValetFailure);
1395 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1396 // The possible outcomes of deleteStack are a StackInfo object with status
1397 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1399 long subStartTime = System.currentTimeMillis ();
1401 heat.deleteStack (tenantId, cloudOwner, cloudSiteId, vnfName, true);
1402 } catch (MsoException me) {
1403 me.addContext ("DeleteVNF");
1404 // Failed to query the Stack due to an openstack exception.
1405 // Convert to a generic VnfException
1406 String error = "Delete VF: " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1407 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1408 tenantId, "OpenStack", "DeleteStack", ErrorCode.DataError.getValue(),
1409 "Exception - deleteStack", me);
1410 logger.debug(error);
1411 if (isValetEnabled && valetDeleteRequestSucceeded) {
1412 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
1414 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage());
1415 // Nothing to really do here whether it succeeded or not other than log it.
1416 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
1417 } catch (Exception e) {
1418 logger.error("Exception encountered while sending Rollback to Valet ", e);
1421 throw new VnfException (me);
1423 if (isValetEnabled && valetDeleteRequestSucceeded) {
1424 // only if the original request succeeded do we send a confirm
1425 logger.debug("valet is enabled, the delete succeeded - now send confirm to valet");
1427 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName);
1428 // Nothing to really do here whether it succeeded or not other than log it.
1429 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
1430 } catch (Exception e) {
1431 logger.error("Exception encountered while sending Confirm to Valet ", e);
1435 // On success, nothing is returned.
1440 public void updateVfModule (String cloudSiteId,
1447 String volumeGroupHeatStackId,
1448 String baseVfHeatStackId,
1449 String vfModuleStackId,
1450 String modelCustomizationUuid,
1451 Map <String, Object> inputs,
1452 MsoRequest msoRequest,
1453 Holder <Map <String, String>> outputs,
1454 Holder <VnfRollback> rollback) throws VnfException {
1455 String vfModuleName = vnfName;
1456 String vfModuleType = vnfType;
1457 String methodName = "updateVfModule";
1458 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1460 StringBuilder sbInit = new StringBuilder();
1461 sbInit.append("updateVfModule: \n");
1462 sbInit.append("cloudOwner=" + cloudOwner + "\n");
1463 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1464 sbInit.append("tenantId=" + tenantId + "\n");
1465 sbInit.append("vnfType=" + vnfType + "\n");
1466 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1467 sbInit.append("vnfName=" + vnfName + "\n");
1468 sbInit.append("requestType=" + requestType + "\n");
1469 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1470 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1471 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1472 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1473 logger.debug(sbInit.toString());
1475 String mcu = modelCustomizationUuid;
1476 boolean useMCUuid = false;
1477 if (mcu != null && !mcu.isEmpty()) {
1478 if ("null".equalsIgnoreCase(mcu)) {
1479 logger.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: {}",
1480 modelCustomizationUuid);
1484 logger.debug("Found modelCustomizationUuid! Will use that: {}", mcu);
1489 String requestTypeString = "";
1490 if (requestType != null && !"".equals(requestType)) {
1491 requestTypeString = requestType;
1494 String nestedStackId = null;
1495 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1496 nestedStackId = volumeGroupHeatStackId;
1498 String nestedBaseStackId = null;
1499 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) {
1500 nestedBaseStackId = baseVfHeatStackId;
1503 if (inputs == null) {
1504 // Create an empty set of inputs
1505 inputs = new HashMap<>();
1506 logger.debug("inputs == null - setting to empty");
1509 boolean isBaseRequest = false;
1510 boolean isVolumeRequest = false;
1511 if (requestTypeString.startsWith("VOLUME")) {
1512 isVolumeRequest = true;
1514 if ((vfModuleName == null || "".equals(vfModuleName.trim())) && vfModuleStackId != null) {
1515 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1518 logger.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId);
1519 logger.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1521 // Will capture execution time for metrics
1522 long startTime = System.currentTimeMillis ();
1524 // Build a default rollback object (no actions performed)
1525 VnfRollback vfRollback = new VnfRollback ();
1526 vfRollback.setCloudSiteId (cloudSiteId);
1527 vfRollback.setCloudOwner (cloudOwner);
1528 vfRollback.setTenantId (tenantId);
1529 vfRollback.setMsoRequest (msoRequest);
1530 vfRollback.setRequestType(requestTypeString);
1531 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1532 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1533 vfRollback.setIsBase(isBaseRequest);
1534 vfRollback.setVfModuleStackId(vfModuleStackId);
1535 vfRollback.setModelCustomizationUuid(mcu);
1537 StackInfo heatStack = null;
1538 long queryStackStarttime = System.currentTimeMillis ();
1539 logger.debug("UpdateVfModule - querying for {}", vfModuleName);
1541 heatStack = heat.queryStack (cloudSiteId, cloudOwner, tenantId, vfModuleName);
1542 } catch (MsoException me) {
1543 // Failed to query the Stack due to an openstack exception.
1544 // Convert to a generic VnfException
1545 me.addContext ("UpdateVFModule");
1546 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
1547 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, cloudSiteId,
1548 tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(), "Exception - QueryStack",
1550 logger.debug(error);
1551 throw new VnfException (me);
1554 //TODO - do we need to check for the other status possibilities?
1555 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1557 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId;
1558 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_VNF_NOT_EXIST.toString(), vfModuleName, cloudOwner, cloudSiteId,
1559 tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(), error);
1560 throw new VnfNotFound (cloudSiteId, cloudOwner, tenantId, vfModuleName);
1562 logger.debug("Found Existing stack, status={}", heatStack.getStatus());
1563 // Populate the outputs from the existing stack.
1564 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1565 rollback.value = vfRollback; // Default rollback - no updates performed
1568 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1569 StackInfo nestedHeatStack = null;
1570 long queryStackStarttime2 = System.currentTimeMillis ();
1571 Map<String, Object> nestedVolumeOutputs = null;
1572 if (nestedStackId != null) {
1574 logger.debug("Querying for nestedStackId = {}", nestedStackId);
1575 nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId);
1576 } catch (MsoException me) {
1577 // Failed to query the Stack due to an openstack exception.
1578 // Convert to a generic VnfException
1579 me.addContext ("UpdateVFModule");
1580 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
1581 logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1582 tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(), "Exception - " + error,
1584 logger.debug("ERROR trying to query nested stack= {}", error);
1585 throw new VnfException (me);
1587 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1588 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1589 logger.error("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vnfName, cloudOwner, cloudSiteId,
1590 tenantId, error, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(), error);
1591 logger.debug(error);
1592 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1594 logger.debug("Found nested heat stack - copying values to inputs *later*");
1595 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1596 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1599 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1600 StackInfo nestedBaseHeatStack = null;
1601 Map<String, Object> baseStackOutputs = null;
1602 if (nestedBaseStackId != null) {
1603 long queryStackStarttime3 = System.currentTimeMillis ();
1605 logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId);
1606 nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId);
1607 } catch (MsoException me) {
1608 // Failed to query the Stack due to an openstack exception.
1609 // Convert to a generic VnfException
1610 me.addContext ("UpdateVfModule");
1611 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ;
1613 .error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, cloudSiteId,
1614 tenantId, "OpenStack", "QueryStack", ErrorCode.DataError.getValue(),
1615 "Exception - " + error, me);
1616 logger.debug("ERROR trying to query nested base stack= {}", error);
1617 throw new VnfException (me);
1619 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1620 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1621 logger.error ("{} {} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName,
1622 cloudOwner, cloudSiteId, tenantId, error, "OpenStack",
1623 "QueryStack", ErrorCode.DataError.getValue(), error);
1624 logger.debug(error);
1625 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1627 logger.debug("Found nested base heat stack - copying values to inputs *later*");
1628 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1629 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1633 // Ready to deploy the new VNF
1637 // Retrieve the VF definition
1638 VnfResource vnfResource = null;
1640 VfModuleCustomization vfmc = null;
1642 vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid);
1643 vf = vfmc != null ? vfmc.getVfModule() : null;
1645 logger.debug("Unable to find a vfModule matching modelCustomizationUuid={}", mcu);
1648 logger.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1651 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1652 logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "VF Module Type",
1653 vfModuleType, "OpenStack", ErrorCode.DataError.getValue(), error);
1654 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1656 logger.debug("Got VF module definition from Catalog: {}", vf.toString());
1657 if (vf.getIsBase()) {
1658 isBaseRequest = true;
1659 logger.debug("This a BASE update request");
1661 logger.debug("This is *not* a BASE VF update request");
1662 if (!isVolumeRequest && nestedBaseStackId == null) {
1663 logger.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1667 //1607 - Add version check
1668 // First - see if it's in the VnfResource record
1669 // if we have a vf Module - then we have to query to get the VnfResource record.
1670 if (vf.getModelUUID() != null) {
1671 String vnfResourceModelUuid = vf.getModelUUID();
1673 vnfResource = vf.getVnfResources();
1674 if (vnfResource == null) {
1675 logger.debug("Unable to find vnfResource at ? will not error for now...", vnfResourceModelUuid);
1679 String minVersionVnf = null;
1680 String maxVersionVnf = null;
1681 if (vnfResource != null) {
1683 minVersionVnf = vnfResource.getAicVersionMin();
1684 maxVersionVnf = vnfResource.getAicVersionMax();
1685 } catch (Exception e) {
1686 logger.debug("Unable to pull min/max version for this VNF Resource entry",e);
1687 minVersionVnf = null;
1688 maxVersionVnf = null;
1690 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1691 minVersionVnf = null;
1693 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1694 maxVersionVnf = null;
1697 if (minVersionVnf != null && maxVersionVnf != null) {
1698 MavenLikeVersioning aicV = new MavenLikeVersioning();
1701 if (this.cloudConfig != null) {
1702 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1703 if (cloudSiteOpt.isPresent()) {
1704 aicV.setVersion(cloudSiteOpt.get().getCloudVersion());
1705 boolean moreThanMin = true;
1706 boolean equalToMin = true;
1707 boolean moreThanMax = true;
1708 boolean equalToMax = true;
1709 boolean doNotTest = false;
1711 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1712 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1713 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1714 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1715 } catch (Exception e) {
1716 logger.debug("An exception occured while trying to test AIC Version {} - will default to not check",
1721 if ((moreThanMin || equalToMin) // aic >= min
1722 && ((equalToMax) || !(moreThanMax))) { // aic <= max
1724 "VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:"
1725 + maxVersionVnf + " supported on Cloud: " + cloudSiteId + " with AIC_Version:" + aicV);
1728 String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin="
1729 + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: "
1730 + cloudSiteId + " with AIC_Version:" + aicV;
1731 logger.error("{} {} {} {} {}", MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack",
1732 ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion");
1733 logger.debug(error);
1734 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1737 logger.debug("bypassing testing AIC version...");
1739 } // let this error out downstream to avoid introducing uncertainty at this stage
1741 logger.debug("cloudConfig is NULL - cannot check cloud site version");
1745 logger.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1747 // End Version check 1607
1749 HeatTemplate heatTemplate = null;
1750 HeatEnvironment heatEnvironment = null;
1751 if (isVolumeRequest) {
1752 heatTemplate = vf.getVolumeHeatTemplate();
1753 heatEnvironment = vfmc.getVolumeHeatEnv();
1755 heatTemplate = vf.getModuleHeatTemplate();
1756 heatEnvironment = vfmc.getHeatEnvironment();
1759 if (heatTemplate == null) {
1760 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1762 .error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID", vfModuleType,
1763 "OpenStack", ErrorCode.DataError.getValue(), error);
1764 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1766 logger.debug("Got HEAT Template from DB: {}", heatTemplate.getHeatTemplate());
1769 if (heatEnvironment == null) {
1770 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType;
1771 logger.error("{} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Environment ID",
1772 "OpenStack", ErrorCode.DataError.getValue(), error);
1773 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1775 logger.debug ("Got Heat Environment from DB: {}", heatEnvironment.getEnvironment());
1778 logger.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId={}",
1779 heatTemplate.getArtifactUuid());
1782 List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates();
1783 Map <String, Object> nestedTemplatesChecked = new HashMap <> ();
1784 if (nestedTemplates != null && !nestedTemplates.isEmpty()) {
1785 // for debugging print them out
1786 logger.debug("Contents of nestedTemplates - to be added to files: on stack:");
1787 for (HeatTemplate entry : nestedTemplates) {
1789 nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody());
1790 logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody());
1793 logger.debug("No nested templates found - nothing to do here");
1794 nestedTemplatesChecked = null;
1797 // Also add the files: for any get_files associated with this VfModule
1798 // *if* there are any
1799 logger.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId={}",
1802 List<HeatFiles> heatFiles = null;
1803 Map <String, Object> heatFilesObjects = new HashMap <> ();
1805 // Add ability to turn on adding get_files with volume requests (by property).
1806 boolean addGetFilesOnVolumeReq = false;
1808 String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ);
1809 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1810 addGetFilesOnVolumeReq = true;
1811 logger.debug("AddGetFilesOnVolumeReq - setting to true! {}", propertyString);
1813 } catch (Exception e) {
1814 logger.debug("An error occured trying to get property {} - default to false",
1815 MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, e);
1817 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1818 logger.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec "
1819 + "vfModuleId={}", vf.getModelUUID());
1821 heatFiles = vf.getHeatFiles();
1822 if (heatFiles != null && !heatFiles.isEmpty()) {
1823 // add these to stack - to be done in createStack
1824 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1825 // this will match the nested templates format
1826 logger.debug("Contents of heatFiles - to be added to files: on stack:");
1827 for (HeatFiles heatfile : heatFiles) {
1828 logger.debug(heatfile.getFileName() + " -> " + heatfile.getFileBody());
1829 heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody());
1832 logger.debug("No heat files found -nothing to do here");
1833 heatFilesObjects = null;
1837 // Check that required parameters have been supplied
1838 String missingParams = null;
1839 List <String> paramList = new ArrayList <> ();
1841 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1842 // supplied an alias. Only check if we don't find it initially.
1843 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1844 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1846 boolean checkRequiredParameters = true;
1848 String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1849 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1850 checkRequiredParameters = false;
1851 logger.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking...",
1852 MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1854 } catch (Exception e) {
1855 // No problem - default is true
1856 logger.debug ("An exception occured trying to get property {}", MsoVnfAdapterImpl.CHECK_REQD_PARAMS,
1859 // 1604 - Add enhanced environment & parameter checking
1860 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1861 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1862 // Note this also removes any comments
1863 MsoHeatEnvironmentEntry mhee = null;
1864 if (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase ().contains ("parameters:")) {
1865 logger.debug("Enhanced environment checking enabled - 1604");
1866 StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment());
1867 mhee = new MsoHeatEnvironmentEntry(sb);
1868 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1869 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1870 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1872 if (!mhee.isValid()) {
1873 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1875 sb2.append("\nEnvironment:");
1876 sb2.append(mhee.toFullString());
1878 logger.debug(sb2.toString());
1880 logger.debug("NO ENVIRONMENT for this entry");
1882 // New for 1607 - support params of json type
1883 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1884 boolean hasJson = false;
1886 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1887 logger.debug ("Parameter:'" + parm.getParamName ()
1889 + parm.isRequired ()
1891 + parm.getParamAlias ());
1893 String parameterType = parm.getParamType();
1894 if (parameterType == null || "".equals(parameterType.trim())) {
1895 parameterType = "String";
1897 JsonNode jsonNode = null;
1898 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1899 if (inputs.containsKey(parm.getParamName()) ) {
1901 String jsonString = null;
1903 jsonString = JSON_MAPPER.writeValueAsString(inputs.get(parm.getParamName()));
1904 jsonNode = JSON_MAPPER.readTree(jsonString);
1905 } catch (JsonParseException jpe) {
1906 //TODO - what to do here?
1907 //for now - send the error to debug, but just leave it as a String
1908 String errorMessage = jpe.getMessage();
1909 logger.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
1912 } catch (Exception e) {
1914 logger.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1918 if (jsonNode != null) {
1919 jsonParams.put(parm.getParamName(), jsonNode);
1921 } else if (inputs.containsKey(parm.getParamAlias())) {
1923 String jsonString = null;
1925 jsonString = (String)inputs.get(parm.getParamAlias());
1926 jsonNode = JSON_MAPPER.readTree(jsonString);
1927 } catch (JsonParseException jpe) {
1928 //TODO - what to do here?
1929 //for now - send the error to debug, but just leave it as a String
1930 String errorMessage = jpe.getMessage();
1931 logger.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
1934 } catch (Exception e) {
1936 logger.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1940 if (jsonNode != null) {
1941 // Notice here - we add it to the jsonParams hashMap with the actual name -
1942 // then manipulate the inputs so when we check for aliases below - it will not
1944 jsonParams.put(parm.getParamName(), jsonNode);
1945 inputs.remove(parm.getParamAlias());
1946 inputs.put(parm.getParamName(), jsonString);
1948 } //TODO add a check for the parameter in the env file
1951 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
1952 if (inputs.containsKey (parm.getParamAlias ())) {
1953 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1954 String realParamName = parm.getParamName ();
1955 String alias = parm.getParamAlias ();
1956 Object value = inputs.get (alias);
1957 logger.debug ("*Found an Alias: paramName=" + realParamName
1962 inputs.remove (alias);
1963 inputs.put (realParamName, value);
1964 logger.debug ("{} entry removed from inputs, added back using {}", alias, realParamName);
1966 // enhanced - check if it's in the Environment (note: that method
1967 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1969 logger.debug("Required parameter {} appears to be in environment - do not count as missing",
1970 parm.getParamName());
1973 logger.debug("adding to missing parameters list: {}", parm.getParamName());
1974 if (missingParams == null) {
1975 missingParams = parm.getParamName ();
1977 missingParams += "," + parm.getParamName ();
1981 paramList.add (parm.getParamName ());
1985 if (missingParams != null) {
1986 // Problem - missing one or more required parameters
1987 if (checkRequiredParameters) {
1988 String error = "Update VNF: Missing Required inputs: " + missingParams;
1989 logger.error("{} {} {} {} {}", MessageEnum.RA_MISSING_PARAM.toString(), missingParams, "OpenStack",
1990 ErrorCode.DataError.getValue(), error);
1991 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1993 logger.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1996 logger.debug("No missing parameters found - ok to proceed");
1999 // Just submit the envt entry as received from the database
2000 String newEnvironmentString = null;
2002 newEnvironmentString = mhee.getRawEntry().toString();
2004 // Remove any extraneous parameters (don't throw an error)
2005 if (inputs != null) {
2006 List <String> extraParams = new ArrayList <> ();
2007 extraParams.addAll (inputs.keySet ());
2008 // This is not a valid parameter for this template
2009 extraParams.removeAll (paramList);
2010 if (!extraParams.isEmpty ()) {
2011 logger.warn("{} {} {} {} {} {}", MessageEnum.RA_VNF_EXTRA_PARAM.toString(), vnfType,
2012 extraParams.toString(), "OpenStack", ErrorCode.DataError.getValue(), "Extra params");
2013 inputs.keySet ().removeAll (extraParams);
2016 Map<String, Object> goldenInputs = copyStringInputs(inputs);
2017 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2018 Map<String, Object> inputsTwo = null;
2019 if (hasJson && jsonParams.size() > 0) {
2020 inputsTwo = new HashMap<>();
2021 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
2022 String keyParamName = entry.getKey();
2023 Object value = entry.getValue();
2024 if (jsonParams.containsKey(keyParamName)) {
2025 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2027 inputsTwo.put(keyParamName, value);
2030 goldenInputs = inputsTwo;
2033 // "Fix" the template if it has CR/LF (getting this from Oracle)
2034 String template = heatTemplate.getHeatTemplate ();
2035 template = template.replaceAll ("\r\n", "\n");
2037 boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false);
2038 boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false);
2039 logger.debug("isValetEnabled={}, failRequestsOnValetFailure={}", isValetEnabled, failRequestOnValetFailure);
2040 if (isVolumeRequest) {
2041 isValetEnabled = false;
2042 logger.debug("never send a volume request to valet");
2044 boolean sendResponseToValet = false;
2045 if (isValetEnabled) {
2046 Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>();
2047 String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
2048 // Make sure it is set to something.
2049 if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) {
2050 parsedVfModuleName = "unknown";
2052 sendResponseToValet = this.valetUpdateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects,
2053 nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, (HashMap<String, Object>) goldenInputs,
2054 msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder);
2055 if (sendResponseToValet) {
2056 goldenInputs = valetModifiedParamsHolder.value;
2060 // Have the tenant. Now deploy the stack itself
2061 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2062 // because we already checked for those.
2063 long updateStackStarttime = System.currentTimeMillis ();
2065 heatStack = heatU.updateStack(
2073 heatTemplate.getTimeoutMinutes(),
2074 newEnvironmentString,
2075 //heatEnvironmentString,
2076 nestedTemplatesChecked,
2079 } catch (MsoException me) {
2080 me.addContext ("UpdateVFModule");
2081 String error = "Update VFModule " + vfModuleType + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me;
2083 .error("{} {} {} {} {} {} {} {}", MessageEnum.RA_UPDATE_VNF_ERR.toString(), vfModuleType, cloudOwner, cloudSiteId,
2084 tenantId, "OpenStack", ErrorCode.DataError.getValue(), "Exception - " + error, me);
2085 if (isValetEnabled && sendResponseToValet) {
2086 logger.debug("valet is enabled, the orchestration failed - now sending rollback to valet");
2088 GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage());
2089 // Nothing to really do here whether it succeeded or not other than log it.
2090 logger.debug("Return code from Rollback response is {}", gvr.getStatusCode());
2091 } catch (Exception e) {
2092 logger.error("Exception encountered while sending Rollback to Valet ", e);
2095 throw new VnfException (me);
2099 // Reach this point if updateStack is successful.
2100 // Populate remaining rollback info and response parameters.
2101 vfRollback.setVnfId (heatStack.getCanonicalName ());
2102 vfRollback.setVnfCreated (true);
2104 if (isValetEnabled && sendResponseToValet) {
2105 logger.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id");
2107 GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName());
2108 // Nothing to really do here whether it succeeded or not other than log it.
2109 logger.debug("Return code from Confirm response is {}", gvr.getStatusCode());
2110 } catch (Exception e) {
2111 logger.error("Exception encountered while sending Confirm to Valet ", e);
2115 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2116 rollback.value = vfRollback;
2120 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2121 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2122 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2123 if (vfModuleStackId == null)
2125 int index = vfModuleStackId.lastIndexOf('/');
2128 String vfModuleName = null;
2130 vfModuleName = vfModuleStackId.substring(0, index);
2131 } catch (Exception e) {
2132 logger.debug("Exception", e);
2133 vfModuleName = null;
2135 return vfModuleName;
2139 * Helper method to check a boolean property value - on error return provided default
2141 private boolean checkBooleanProperty(String propertyName, boolean defaultValue) {
2142 boolean property = defaultValue;
2144 String propertyString = this.environment.getProperty(propertyName);
2145 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
2147 } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
2150 } catch (Exception e) {
2151 logger.debug("An exception occured trying to get property {} - defaulting to ", propertyName, defaultValue, e);
2152 property = defaultValue;
2158 * Helper method to combine getFiles and nestedTemplates in to a single Map
2160 private Map<String, Object> combineGetFilesAndNestedTemplates(Map<String, Object> getFiles, Map<String, Object> nestedTemplates) {
2161 boolean haveGetFiles = true;
2162 boolean haveNestedTemplates = true;
2163 Map<String, Object> files = new HashMap<String, Object>();
2164 if (getFiles == null || getFiles.isEmpty()) {
2165 haveGetFiles = false;
2167 if (nestedTemplates == null || nestedTemplates.isEmpty()) {
2168 haveNestedTemplates = false;
2170 if (haveGetFiles && haveNestedTemplates) {
2171 for (String keyString : getFiles.keySet ()) {
2172 files.put (keyString, getFiles.get (keyString));
2174 for (String keyString : nestedTemplates.keySet ()) {
2175 files.put (keyString, nestedTemplates.get (keyString));
2178 // Handle if we only have one or neither:
2182 if (haveNestedTemplates) {
2183 files = nestedTemplates;
2190 * Valet Create request
2192 private boolean valetCreateRequest(String cloudSiteId, String cloudOwner, String tenantId, Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked,
2193 String vfModuleName, boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs,
2194 MsoRequest msoRequest, Map<String, Object> inputs, boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2195 boolean valetSucceeded = false;
2196 String valetErrorMessage = "more detail not available";
2198 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2199 Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects,
2200 nestedTemplatesChecked);
2201 HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(),
2202 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2203 GenericValetResponse<ValetCreateResponse> createReq = this.vci.callValetCreateRequest(msoRequest.getRequestId(),
2204 cloudSiteId, cloudOwner, tenantId, msoRequest.getServiceInstanceId(), (String)inputs.get("vnf_id"),
2205 (String)inputs.get("vnf_name"), (String)inputs.get("vf_module_id"), (String)inputs.get("vf_module_name"), keystoneUrl,
2207 ValetCreateResponse vcr = createReq.getReturnObject();
2208 if (vcr != null && createReq.getStatusCode() == 200) {
2209 ValetStatus status = vcr.getStatus();
2210 if (status != null) {
2211 String statusCode = status.getStatus(); // "ok" or "failed"
2212 if ("ok".equalsIgnoreCase(statusCode)) {
2213 Map<String, Object> newInputs = vcr.getParameters();
2214 if (newInputs != null) {
2215 Map<String, Object> oldGold = goldenInputs;
2216 logger.debug("parameters before being modified by valet:{}", oldGold.toString());
2217 goldenInputs = new HashMap<String, Object>();
2218 for (String key : newInputs.keySet()) {
2219 goldenInputs.put(key, newInputs.get(key));
2221 valetModifiedParamsHolder.value = goldenInputs;
2222 logger.debug("parameters after being modified by valet:{}", goldenInputs.toString());
2223 valetSucceeded = true;
2226 valetErrorMessage = status.getMessage();
2230 logger.debug("Got a bad response back from valet");
2231 valetErrorMessage = "Bad response back from Valet";
2232 valetSucceeded = false;
2234 } catch (Exception e) {
2235 logger.error("An exception occurred trying to call valet ...", e);
2236 valetSucceeded = false;
2237 valetErrorMessage = e.getMessage();
2239 if (failRequestOnValetFailure && !valetSucceeded) {
2240 // The valet request failed - and property says to fail the request
2241 //TODO Create a new exception class for valet?
2242 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2244 return valetSucceeded;
2248 * Valet update request
2251 private boolean valetUpdateRequest(String cloudSiteId, String cloudOwnerId, String tenantId,
2252 Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName,
2253 boolean backout, HeatTemplate heatTemplate, String newEnvironmentString,
2254 Map<String, Object> goldenInputs, MsoRequest msoRequest, Map<String, Object> inputs,
2255 boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException {
2257 boolean valetSucceeded = false;
2258 String valetErrorMessage = "more detail not available";
2260 String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId);
2261 Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects,
2262 nestedTemplatesChecked);
2263 HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(),
2264 heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs);
2265 // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now
2266 GenericValetResponse<ValetUpdateResponse> updateReq = this.vci.callValetUpdateRequest(msoRequest.getRequestId(),
2267 cloudSiteId, cloudOwnerId, tenantId, msoRequest.getServiceInstanceId(), (String)inputs.get("vnf_id"),
2268 vfModuleName, (String)inputs.get("vf_module_id"), vfModuleName, keystoneUrl,
2270 ValetUpdateResponse vur = updateReq.getReturnObject();
2271 if (vur != null && updateReq.getStatusCode() == 200) {
2272 ValetStatus status = vur.getStatus();
2273 if (status != null) {
2274 String statusCode = status.getStatus(); // "ok" or "failed"
2275 if ("ok".equalsIgnoreCase(statusCode)) {
2276 Map<String, Object> newInputs = vur.getParameters();
2277 if (newInputs != null) {
2278 Map<String, Object> oldGold = goldenInputs;
2279 logger.debug("parameters before being modified by valet:{}", oldGold.toString());
2280 goldenInputs = new HashMap<String, Object>();
2281 for (String key : newInputs.keySet()) {
2282 goldenInputs.put(key, newInputs.get(key));
2284 valetModifiedParamsHolder.value = goldenInputs;
2285 logger.debug("parameters after being modified by valet:{}", goldenInputs.toString());
2286 valetSucceeded = true;
2289 valetErrorMessage = status.getMessage();
2293 logger.debug("Got a bad response back from valet");
2294 valetErrorMessage = "Got a bad response back from valet";
2295 valetSucceeded = false;
2297 } catch (Exception e) {
2298 logger.error("An exception occurred trying to call valet - will continue processing for now...", e);
2299 valetErrorMessage = e.getMessage();
2300 valetSucceeded = false;
2302 if (failRequestOnValetFailure && !valetSucceeded) {
2303 // The valet request failed - and property says to fail the request
2304 // TODO Create a new exception class for valet?
2305 throw new VnfException("A failure occurred with Valet: " + valetErrorMessage);
2307 return valetSucceeded;
2311 * Valet delete request
2313 private boolean valetDeleteRequest(String cloudSiteId, String cloudOwnerId, String tenantId, String vnfName,
2314 MsoRequest msoRequest, boolean failRequestOnValetFailure) {
2315 boolean valetDeleteRequestSucceeded = false;
2316 String valetErrorMessage = "more detail not available";
2318 String vfModuleId = vnfName;
2319 String vfModuleName = vnfName;
2321 vfModuleName = vnfName.substring(0, vnfName.indexOf('/'));
2322 vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1);
2323 } catch (Exception e) {
2324 // do nothing - send what we got for vnfName for both to valet
2325 logger.error("An exception occurred trying to call MsoVnfAdapterImpl.valetDeleteRequest() method", e);
2327 GenericValetResponse<ValetDeleteResponse> deleteReq = this.vci.callValetDeleteRequest(msoRequest.getRequestId(),
2328 cloudSiteId, cloudOwnerId, tenantId, vfModuleId, vfModuleName);
2329 ValetDeleteResponse vdr = deleteReq.getReturnObject();
2330 if (vdr != null && deleteReq.getStatusCode() == 200) {
2331 ValetStatus status = vdr.getStatus();
2332 if (status != null) {
2333 String statusCode = status.getStatus(); // "ok" or "failed"
2334 if ("ok".equalsIgnoreCase(statusCode)) {
2335 logger.debug("delete request to valet returned success");
2336 valetDeleteRequestSucceeded = true;
2338 logger.debug("delete request to valet returned failure");
2339 valetDeleteRequestSucceeded = false;
2340 valetErrorMessage = status.getMessage();
2344 logger.debug("Got a bad response back from valet - delete request failed");
2345 valetDeleteRequestSucceeded = false;
2346 valetErrorMessage = "Got a bad response back from valet - delete request failed";
2348 } catch (Exception e) {
2349 logger.error("An exception occurred trying to call valet - valetDeleteRequest failed", e);
2350 valetDeleteRequestSucceeded = false;
2351 valetErrorMessage = e.getMessage();
2353 if (valetDeleteRequestSucceeded == false && failRequestOnValetFailure == true) {
2354 logger.error("ValetDeleteRequestFailed - del req still will be sent to openstack", new VnfException
2355 ("ValetDeleteRequestFailedError"));
2357 return valetDeleteRequestSucceeded;