2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.mso.adapters.vnf;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.List;
32 import java.util.Optional;
33 import java.util.Scanner;
34 import java.util.concurrent.TimeUnit;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
38 import javax.jws.WebService;
39 import javax.xml.ws.Holder;
41 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
42 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
43 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
44 import org.openecomp.mso.cloud.CloudConfig;
45 import org.openecomp.mso.cloud.CloudConfigFactory;
46 import org.openecomp.mso.cloud.CloudSite;
47 import org.openecomp.mso.db.catalog.CatalogDatabase;
48 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
49 import org.openecomp.mso.db.catalog.beans.HeatFiles;
50 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
51 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
52 import org.openecomp.mso.db.catalog.beans.VfModule;
53 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
54 import org.openecomp.mso.db.catalog.beans.VnfResource;
55 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
56 import org.openecomp.mso.entity.MsoRequest;
57 import org.openecomp.mso.logger.MessageEnum;
58 import org.openecomp.mso.logger.MsoAlarmLogger;
59 import org.openecomp.mso.logger.MsoLogger;
60 import org.openecomp.mso.openstack.beans.HeatStatus;
61 import org.openecomp.mso.openstack.beans.StackInfo;
62 import org.openecomp.mso.openstack.beans.VnfRollback;
63 import org.openecomp.mso.openstack.beans.VnfStatus;
64 import org.openecomp.mso.openstack.exceptions.MsoException;
65 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
66 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
67 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
68 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
69 import org.openecomp.mso.properties.MsoPropertiesFactory;
71 import com.fasterxml.jackson.core.JsonParseException;
72 import com.fasterxml.jackson.databind.JsonNode;
73 import com.fasterxml.jackson.databind.ObjectMapper;
75 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
76 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
78 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
79 protected CloudConfig cloudConfig = null;
81 MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory();
83 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
84 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
85 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
86 private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA);
87 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger();
88 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
89 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
90 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
93 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
95 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
97 public MsoVnfAdapterImpl() {
98 // empty implementation
102 * This constructor MUST be used if this class is called with the new operator.
104 * @param msoPropFactory
106 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
107 this.msoPropertiesFactory = msoPropFactory;
108 this.cloudConfigFactory = cloudConfigFact;
112 * Health Check web method. Does nothing but return to show the adapter is deployed.
115 public void healthCheck() {
116 LOGGER.debug("Health check call in VNF Adapter");
120 * This is the "Create VNF" web service implementation.
121 * It will create a new VNF of the requested type in the specified cloud
122 * and tenant. The tenant must exist before this service is called.
124 * If a VNF with the same name already exists, this can be considered a
125 * success or failure, depending on the value of the 'failIfExists' parameter.
127 * All VNF types will be defined in the MSO catalog. The caller must request
128 * one of these pre-defined types or an error will be returned. Within the
129 * catalog, each VNF type references (among other things) a Heat template
130 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
133 * Depending on the Heat template, a variable set of input parameters will
134 * be defined, some of which are required. The caller is responsible to
135 * pass the necessary input data for the VNF or an error will be thrown.
137 * The method returns the vnfId (the canonical name), a Map of VNF output
138 * attributes, and a VnfRollback object. This last object can be passed
139 * as-is to the rollbackVnf operation to undo everything that was created
140 * for the VNF. This is useful if a VNF is successfully created but the
141 * orchestrator fails on a subsequent operation.
143 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
144 * @param tenantId Openstack tenant identifier
145 * @param vnfType VNF type key, should match a VNF definition in catalog DB
146 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
147 * @param vnfName Name to be assigned to the new VNF
148 * @param inputs Map of key=value inputs for VNF stack creation
149 * @param failIfExists Flag whether already existing VNF should be considered
150 * a success or failure
151 * @param msoRequest Request tracking information for logs
152 * @param vnfId Holder for output VNF Openstack ID
153 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
154 * @param rollback Holder for returning VnfRollback object
157 public void createVnf(String cloudSiteId,
163 String volumeGroupHeatStackId,
164 Map<String, String> inputs,
165 Boolean failIfExists,
167 MsoRequest msoRequest,
168 Holder<String> vnfId,
169 Holder<Map<String, String>> outputs,
170 Holder<VnfRollback> rollback) throws VnfException {
171 // Create a hook here to catch shortcut createVf requests:
172 if (requestType != null) {
173 if (requestType.startsWith("VFMOD")) {
174 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
175 String newRequestType = requestType.substring(5);
176 String vfVolGroupHeatStackId = "";
177 String vfBaseHeatStackId = "";
179 if (volumeGroupHeatStackId != null) {
180 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
181 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|") + 1);
183 } catch (Exception e) {
184 // might be ok - both are just blank
185 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId, e);
187 this.createVfModule(cloudSiteId,
193 vfVolGroupHeatStackId,
206 // createVf will know if the requestType starts with "X" that it's the "old" way
207 StringBuilder newRequestTypeSb = new StringBuilder("X");
208 String vfVolGroupHeatStackId = "";
209 String vfBaseHeatStackId = "";
210 if (requestType != null) {
211 newRequestTypeSb.append(requestType);
213 this.createVfModule(cloudSiteId,
218 newRequestTypeSb.toString(),
219 vfVolGroupHeatStackId,
229 // End createVf shortcut
233 public void updateVnf(String cloudSiteId,
239 String volumeGroupHeatStackId,
240 Map<String, String> inputs,
241 MsoRequest msoRequest,
242 Holder<Map<String, String>> outputs,
243 Holder<VnfRollback> rollback) throws VnfException {
244 // As of 1707 - this method should no longer be called
245 MsoLogger.setLogContext(msoRequest.getRequestId(), msoRequest.getServiceInstanceId());
246 MsoLogger.setServiceName("UpdateVnf");
247 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
251 * This is the "Query VNF" web service implementation.
252 * It will look up a VNF by name or ID in the specified cloud and tenant.
254 * The method returns an indicator that the VNF exists, its Openstack internal
255 * ID, its status, and the set of outputs (from when the stack was created).
257 * @param cloudSiteId CLLI code of the cloud site in which to query
258 * @param tenantId Openstack tenant identifier
259 * @param vnfName VNF Name or Openstack ID
260 * @param msoRequest Request tracking information for logs
261 * @param vnfExists Flag reporting the result of the query
262 * @param vnfId Holder for output VNF Openstack ID
263 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
266 public void queryVnf(String cloudSiteId,
269 MsoRequest msoRequest,
270 Holder<Boolean> vnfExists,
271 Holder<String> vnfId,
272 Holder<VnfStatus> status,
273 Holder<Map<String, String>> outputs) throws VnfException {
274 MsoLogger.setLogContext(msoRequest);
275 MsoLogger.setServiceName("QueryVnf");
276 LOGGER.debug("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
278 // Will capture execution time for metrics
279 long startTime = System.currentTimeMillis();
281 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
283 StackInfo heatStack = null;
284 long subStartTime = System.currentTimeMillis();
286 heatStack = heat.queryStack(cloudSiteId, tenantId, vnfName);
287 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
288 } catch (MsoException me) {
289 me.addContext("QueryVNF");
290 // Failed to query the Stack due to an openstack exception.
291 // Convert to a generic VnfException
292 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
293 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
294 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
295 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
296 throw new VnfException(me);
299 // Populate the outputs based on the returned Stack information
301 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
303 vnfExists.value = Boolean.FALSE;
304 status.value = VnfStatus.NOTFOUND;
306 outputs.value = new HashMap<>(); // Return as an empty map
308 LOGGER.debug("VNF " + vnfName + " not found");
310 vnfExists.value = Boolean.TRUE;
311 status.value = stackStatusToVnfStatus(heatStack.getStatus());
312 vnfId.value = heatStack.getCanonicalName();
313 outputs.value = copyStringOutputs(heatStack.getOutputs());
315 LOGGER.debug("VNF " + vnfName + " found, ID = " + vnfId.value);
317 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
321 * This is the "Delete VNF" web service implementation.
322 * It will delete a VNF by name or ID in the specified cloud and tenant.
324 * The method has no outputs.
326 * @param cloudSiteId CLLI code of the cloud site in which to delete
327 * @param tenantId Openstack tenant identifier
328 * @param vnfName VNF Name or Openstack ID
329 * @param msoRequest Request tracking information for logs
332 public void deleteVnf(String cloudSiteId,
335 MsoRequest msoRequest) throws VnfException {
336 MsoLogger.setLogContext(msoRequest);
337 MsoLogger.setServiceName("DeleteVnf");
338 LOGGER.debug("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
339 // Will capture execution time for metrics
340 long startTime = System.currentTimeMillis();
342 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
344 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
345 // The possible outcomes of deleteStack are a StackInfo object with status
346 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
348 long subStartTime = System.currentTimeMillis();
350 heat.deleteStack(tenantId, cloudSiteId, vnfName, true);
351 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
352 } catch (MsoException me) {
353 me.addContext("DeleteVNF");
354 // Failed to query the Stack due to an openstack exception.
355 // Convert to a generic VnfException
356 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
357 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
358 LOGGER.error(MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
359 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
360 throw new VnfException(me);
363 // On success, nothing is returned.
364 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
368 * This web service endpoint will rollback a previous Create VNF operation.
369 * A rollback object is returned to the client in a successful creation
370 * response. The client can pass that object as-is back to the rollbackVnf
371 * operation to undo the creation.
374 public void rollbackVnf(VnfRollback rollback) throws VnfException {
375 long startTime = System.currentTimeMillis();
376 MsoLogger.setServiceName("RollbackVnf");
377 // rollback may be null (e.g. if stack already existed when Create was called)
378 if (rollback == null) {
379 LOGGER.info(MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
380 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
384 // Get the elements of the VnfRollback object for easier access
385 String cloudSiteId = rollback.getCloudSiteId();
386 String tenantId = rollback.getTenantId();
387 String vnfId = rollback.getVnfId();
389 MsoLogger.setLogContext(rollback.getMsoRequest());
391 LOGGER.debug("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
393 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
395 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
396 // The possible outcomes of deleteStack are a StackInfo object with status
397 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
399 long subStartTime = System.currentTimeMillis();
401 heat.deleteStack(tenantId, cloudSiteId, vnfId, true);
402 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
403 } catch (MsoException me) {
404 // Failed to rollback the Stack due to an openstack exception.
405 // Convert to a generic VnfException
406 me.addContext("RollbackVNF");
407 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
408 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
409 LOGGER.error(MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
410 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
411 throw new VnfException(me);
413 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
416 private VnfStatus stackStatusToVnfStatus(HeatStatus stackStatus) {
417 switch (stackStatus) {
419 return VnfStatus.ACTIVE;
421 return VnfStatus.ACTIVE;
423 return VnfStatus.FAILED;
425 return VnfStatus.UNKNOWN;
429 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
430 Map<String, String> stringOutputs = new HashMap<>();
431 for (Map.Entry<String, Object> entry : stackOutputs.entrySet()) {
432 String key = entry.getKey();
433 Object value = entry.getValue();
434 if (value instanceof String) {
435 stringOutputs.put(key, (String) value);
436 } else if (value instanceof Integer) {
438 String str = "" + value;
439 stringOutputs.put(key, str);
440 } catch (Exception e) {
441 LOGGER.debug("Unable to add " + key + " to outputs", e);
443 } else if (value instanceof JsonNode) {
445 //String str = this.convertNode((JsonNode) value);
446 String str = value.toString();
447 stringOutputs.put(key, str);
448 } catch (Exception e) {
449 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode", e);
451 } else if (value instanceof java.util.LinkedHashMap) {
453 //String str = JSON_MAPPER.writeValueAsString(value);
454 String str = value.toString();
455 stringOutputs.put(key, str);
456 } catch (Exception e) {
457 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap", e);
461 String str = value.toString();
462 stringOutputs.put(key, str);
463 } catch (Exception e) {
464 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(), e);
468 return stringOutputs;
471 private Map<String, Object> copyStringInputs(Map<String, String> stringInputs) {
472 return new HashMap<>(stringInputs);
475 private boolean callHeatbridge(String heatStackId) {
476 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
477 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
478 long waitTimeMs = 10000L;
480 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
481 String[] envp = null;
482 File dir = new File(executionDir);
483 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
484 Runtime r = Runtime.getRuntime();
485 Process p = r.exec(cmdarray, envp, dir);
486 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
488 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
489 return wait && p.exitValue() == 0;
490 } catch (IOException e) {
491 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
493 } catch (InterruptedException e) {
494 LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e);
496 } catch (RuntimeException e) {
497 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e);
502 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
504 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
505 if (inputs == null) {
507 } else if (inputs.size() < 1) {
508 sb.append("\tEMPTY");
510 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
512 String str = entry.getKey();
513 Object value = entry.getValue();
515 outputString = value.toString();
516 } catch (Exception e) {
517 LOGGER.debug("Exception :", e);
518 outputString = "Unable to call toString() on the value for " + str;
520 sb.append("\t\nitem ").append(i++).append(": '").append(str).append("'='").append(outputString)
524 LOGGER.debug(sb.toString());
527 private void sendMapToDebug(Map<String, String> inputs) {
529 StringBuilder sb = new StringBuilder("inputs:");
530 if (inputs == null) {
532 } else if (inputs.size() < 1) {
533 sb.append("\tEMPTY");
535 for (String str : inputs.keySet()) {
536 sb.append("\titem ").append(i++).append(": ").append(str).append("=").append(inputs.get(str));
539 LOGGER.debug(sb.toString());
542 private String convertNode(final JsonNode node) {
544 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
545 final String json = JSON_MAPPER.writeValueAsString(obj);
547 } catch (Exception e) {
548 LOGGER.debug("Error converting json to string " + e.getMessage(), e);
550 return "[Error converting json to string]";
553 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
554 if (objectMap == null) {
557 Map<String, String> stringMap = new HashMap<>();
558 for (String key : objectMap.keySet()) {
559 if (!stringMap.containsKey(key)) {
560 Object obj = objectMap.get(key);
561 if (obj instanceof String) {
562 stringMap.put(key, (String) objectMap.get(key));
563 } else if (obj instanceof JsonNode) {
564 // This is a bit of mess - but I think it's the least impacting
565 // let's convert it BACK to a string - then it will get converted back later
567 String str = this.convertNode((JsonNode) obj);
568 stringMap.put(key, str);
569 } catch (Exception e) {
570 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
571 //okay in this instance - only string values (fqdn) are expected to be needed
573 } else if (obj instanceof java.util.LinkedHashMap) {
574 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
576 String str = JSON_MAPPER.writeValueAsString(obj);
577 stringMap.put(key, str);
578 } catch (Exception e) {
579 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
581 } else if (obj instanceof Integer) {
583 String str = "" + obj;
584 stringMap.put(key, str);
585 } catch (Exception e) {
586 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
590 String str = obj.toString();
591 stringMap.put(key, str);
592 } catch (Exception e) {
593 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")", e);
603 public void createVfModule(String cloudSiteId,
609 String volumeGroupHeatStackId,
610 String baseVfHeatStackId,
611 String modelCustomizationUuid,
612 Map<String, String> inputs,
613 Boolean failIfExists,
615 MsoRequest msoRequest,
616 Holder<String> vnfId,
617 Holder<Map<String, String>> outputs,
618 Holder<VnfRollback> rollback) throws VnfException {
619 String vfModuleName = vnfName;
620 String vfModuleType = vnfType;
621 String vfVersion = vnfVersion;
622 String mcu = modelCustomizationUuid;
623 boolean useMCUuid = false;
624 if (mcu != null && !mcu.isEmpty()) {
625 if ("null".equalsIgnoreCase(mcu)) {
626 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
630 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
634 MsoLogger.setLogContext(msoRequest);
635 MsoLogger.setServiceName("CreateVfModule");
636 String requestTypeString = "";
637 if (requestType != null && !"".equals(requestType)) {
638 requestTypeString = requestType;
640 String nestedStackId = null;
641 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
642 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
643 nestedStackId = volumeGroupHeatStackId;
646 String nestedBaseStackId = null;
647 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
648 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
649 nestedBaseStackId = baseVfHeatStackId;
653 if (inputs == null) {
654 // Create an empty set of inputs
655 inputs = new HashMap<>();
656 LOGGER.debug("inputs == null - setting to empty");
658 this.sendMapToDebug(inputs);
660 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
661 boolean oldWay = false;
662 if (requestTypeString.startsWith("X")) {
664 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
665 requestTypeString = requestTypeString.substring(1);
668 // 1607 - let's parse out the request type we're being sent
669 boolean isBaseRequest = false;
670 boolean isVolumeRequest = false;
671 if (requestTypeString.startsWith("VOLUME")) {
672 isVolumeRequest = true;
675 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
677 // TODO(sshank): Figure out the body format to be sent from Groovy.
678 String hpaEnviromnentString = "";
679 // Something similar to the following:
681 if requestTypeString.substring(?) != "" {
682 hpaEnviromnentString = requestTypeString.substring(?)
686 // Will capture execution time for metrics
687 long startTime = System.currentTimeMillis();
689 // Build a default rollback object (no actions performed)
690 VnfRollback vfRollback = new VnfRollback();
691 vfRollback.setCloudSiteId(cloudSiteId);
692 vfRollback.setTenantId(tenantId);
693 vfRollback.setMsoRequest(msoRequest);
694 vfRollback.setRequestType(requestTypeString);
695 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
696 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
697 vfRollback.setIsBase(isBaseRequest);
698 vfRollback.setModelCustomizationUuid(mcu);
700 // Put data into A&AI through Heatstack
701 callHeatbridge(baseVfHeatStackId);
703 // First, look up to see if the VF already exists.
704 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
706 StackInfo heatStack = null;
707 long subStartTime1 = System.currentTimeMillis();
709 heatStack = heat.queryStack(cloudSiteId, tenantId, vfModuleName);
710 LOGGER.recordMetricEvent(subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
711 } catch (MsoException me) {
712 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
713 LOGGER.recordMetricEvent(subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
714 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
715 // Failed to query the Stack due to an openstack exception.
716 // Convert to a generic VnfException
717 me.addContext("CreateVFModule");
718 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
719 throw new VnfException(me);
721 // New with 1607 - more precise handling/messaging if the stack already exists
722 if (heatStack != null && !(heatStack.getStatus() == HeatStatus.NOTFOUND)) {
723 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
724 HeatStatus status = heatStack.getStatus();
725 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
726 // fail - it's in progress - return meaningful error
727 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; please wait for it to complete, or fix manually.";
728 LOGGER.error(MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
729 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
730 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
732 if (status == HeatStatus.FAILED) {
733 // fail - it exists and is in a FAILED state
734 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
735 LOGGER.error(MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
736 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
737 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
739 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
740 // fail - it exists and is in a FAILED state
741 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
742 LOGGER.error(MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in UPDATED or UNKNOWN state");
743 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
744 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
746 if (status == HeatStatus.CREATED) {
748 if (failIfExists != null && failIfExists) {
749 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
750 LOGGER.error(MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
751 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
752 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
754 LOGGER.debug("Found Existing stack, status=" + heatStack.getStatus());
755 // Populate the outputs from the existing stack.
756 vnfId.value = heatStack.getCanonicalName();
757 outputs.value = copyStringOutputs(heatStack.getOutputs());
758 rollback.value = vfRollback; // Default rollback - no updates performed
761 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
766 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
767 StackInfo nestedHeatStack = null;
768 long subStartTime2 = System.currentTimeMillis();
769 Map<String, Object> nestedVolumeOutputs = null;
770 if (nestedStackId != null) {
772 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
773 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
774 LOGGER.recordMetricEvent(subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
775 } catch (MsoException me) {
776 // Failed to query the Stack due to an openstack exception.
777 // Convert to a generic VnfException
778 me.addContext("CreateVFModule");
779 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
780 LOGGER.recordMetricEvent(subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
781 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
782 LOGGER.debug("ERROR trying to query nested stack= " + error);
783 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
784 throw new VnfException(me);
786 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
787 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
788 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
789 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
791 throw new VnfException(error, MsoExceptionCategory.USERDATA);
793 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
794 //this.sendMapToDebug(inputs);
795 nestedVolumeOutputs = nestedHeatStack.getOutputs();
796 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
798 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
799 //this.sendMapToDebug(inputs);
803 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
804 StackInfo nestedBaseHeatStack = null;
805 long subStartTime3 = System.currentTimeMillis();
806 Map<String, Object> baseStackOutputs = null;
807 if (nestedBaseStackId != null) {
809 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
810 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
811 LOGGER.recordMetricEvent(subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
812 } catch (MsoException me) {
813 // Failed to query the Stack due to an openstack exception.
814 // Convert to a generic VnfException
815 me.addContext("CreateVFModule");
816 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
817 LOGGER.recordMetricEvent(subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
818 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
819 LOGGER.debug("ERROR trying to query nested base stack= " + error);
820 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
821 throw new VnfException(me);
823 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
824 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
825 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached base heatStack ID DOES NOT EXIST");
826 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
828 throw new VnfException(error, MsoExceptionCategory.USERDATA);
830 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
831 //this.sendMapToDebug(inputs);
832 baseStackOutputs = nestedBaseHeatStack.getOutputs();
833 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
835 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
836 //this.sendMapToDebug(inputs);
840 // Ready to deploy the new VNF
842 try (CatalogDatabase db = CatalogDatabase.getInstance()) {
845 VnfResource vnfResource = null;
846 VfModuleCustomization vfmc = null;
847 LOGGER.debug("version: " + vfVersion);
849 // 1707 - db refactoring
850 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
851 vf = vfmc != null ? vfmc.getVfModule() : null;
852 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
853 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
855 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
857 "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
858 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
859 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "",
860 MsoLogger.ErrorCode.DataError,
861 "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
862 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
864 throw new VnfException(error, MsoExceptionCategory.USERDATA);
866 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
869 isBaseRequest = true;
870 LOGGER.debug("This is a BASE VF request!");
872 LOGGER.debug("This is *not* a BASE VF request!");
873 if (!isVolumeRequest && nestedBaseStackId == null) {
875 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
878 } else { // This is to support gamma only - get info from vnf_resource table
879 if (vfVersion != null && !vfVersion.isEmpty()) {
880 vnfResource = db.getVnfResource(vnfType, vnfVersion);
882 vnfResource = db.getVnfResource(vnfType);
884 if (vnfResource == null) {
885 String error = "Create VNF: Unknown VNF Type: " + vnfType;
886 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
887 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
888 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
889 throw new VnfException(error, MsoExceptionCategory.USERDATA);
891 LOGGER.debug("Got VNF module definition from Catalog: "
892 + vnfResource.toString());
894 // By here - we have either a vf or vnfResource
896 //1607 - Add version check
897 // First - see if it's in the VnfResource record
898 // if we have a vf Module - then we have to query to get the VnfResource record.
900 if (vf.getVnfResourceModelUUId() != null) {
901 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
902 //vnfResource = db.getVnfResourceById(vnfResourceId);
903 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
904 if (vnfResource == null) {
906 "Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
910 String minVersionVnf = null;
911 String maxVersionVnf = null;
912 if (vnfResource != null) {
914 minVersionVnf = vnfResource.getAicVersionMin();
915 maxVersionVnf = vnfResource.getAicVersionMax();
916 } catch (Exception e) {
917 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
918 minVersionVnf = null;
919 maxVersionVnf = null;
921 if (minVersionVnf != null && "".equals(minVersionVnf)) {
922 minVersionVnf = null;
924 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
925 maxVersionVnf = null;
928 if (minVersionVnf != null && maxVersionVnf != null) {
929 MavenLikeVersioning aicV = new MavenLikeVersioning();
930 if (this.cloudConfig == null) {
931 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
934 if (this.cloudConfig != null) {
935 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
936 if (cloudSiteOpt.isPresent()) {
937 aicV.setVersion(cloudSiteOpt.get().getAic_version());
938 // Add code to handle unexpected values in here
939 boolean moreThanMin = true;
940 boolean equalToMin = true;
941 boolean moreThanMax = true;
942 boolean equalToMax = true;
943 boolean doNotTest = false;
945 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
946 equalToMin = aicV.isTheSameVersion(minVersionVnf);
947 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
948 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
949 } catch (Exception e) {
950 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage()
951 + " - will default to not check", e);
955 if ((moreThanMin || equalToMin) // aic >= min
956 && (equalToMax || !(moreThanMax))) { //aic <= max
957 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
958 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf
959 + " supported on Cloud: " + cloudSiteOpt.get().getId() + " with AIC_Version:"
960 + cloudSiteOpt.get().getAic_version());
964 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
965 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:"
966 + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get().getId()
967 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
968 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
969 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
971 throw new VnfException(error, MsoExceptionCategory.USERDATA);
974 LOGGER.debug("bypassing testing AIC version...");
976 } // let this error out downstream to avoid introducing uncertainty at this stage
978 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
982 "AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
984 // End Version check 1607
986 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
987 // with VNF_RESOURCE - we use the old methods.
988 //Integer heatTemplateId = null;
989 //Integer heatEnvtId = null;
991 String heatTemplateArtifactUuid = null;
992 String heatEnvironmentArtifactUuid = null;
995 if (isVolumeRequest) {
996 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
997 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
999 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1000 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1003 if (isVolumeRequest) {
1004 LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
1006 heatTemplateArtifactUuid = vnfResource.getTemplateId();
1007 heatEnvironmentArtifactUuid = null;
1010 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1011 HeatTemplate heatTemplate = null;
1012 if (heatTemplateArtifactUuid == null || "".equals(heatTemplateArtifactUuid)) {
1013 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1014 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1015 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1016 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1017 MsoAlarmLogger.CRITICAL, error);
1018 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1020 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1022 if (heatTemplate == null) {
1023 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1024 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1026 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1027 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1028 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1029 MsoAlarmLogger.CRITICAL, error);
1030 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1032 LOGGER.debug("Got HEAT Template from DB");
1034 HeatEnvironment heatEnvironment = null;
1035 String heatEnvironmentString = null;
1037 if (heatEnvironmentArtifactUuid != null && !"".equals(heatEnvironmentArtifactUuid)) {
1038 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1039 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1040 if (heatEnvironment == null) {
1041 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1042 + ", Environment ID="
1043 + heatEnvironmentArtifactUuid;
1044 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1045 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment",
1046 MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1047 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1049 // Alarm on this error, configuration must be fixed
1050 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1052 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1054 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1055 heatEnvironmentString = heatEnvironment
1056 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1057 LOGGER.debug("after parsing: " + heatEnvironmentString);
1060 LOGGER.debug("no environment parameter found for this Type " + vfModuleType);
1063 // 1510 - Add the files: for nested templates *if* there are any
1064 LOGGER.debug("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1065 + heatTemplate.getArtifactUuid());
1066 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1067 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1068 if (nestedTemplates != null) {
1069 // for debugging print them out
1070 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1071 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1072 String providerResourceFile = entry.getKey();
1073 Object value = entry.getValue();
1074 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1075 String childTemplateBody = (String) value;
1076 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1077 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1080 LOGGER.debug("No nested templates found - nothing to do here");
1081 nestedTemplatesChecked = null; // just to make sure
1084 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1085 // *if* there are any
1086 Map<String, HeatFiles> heatFiles = null;
1087 Map<String, Object> heatFilesObjects = new HashMap<>();
1089 // Add ability to turn on adding get_files with volume requests (by property).
1090 boolean addGetFilesOnVolumeReq = false;
1092 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1093 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1094 addGetFilesOnVolumeReq = true;
1095 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1097 } catch (Exception e) {
1098 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1101 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1103 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1104 //heatFiles = db.getHeatFiles(vnfResource.getId());
1106 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1107 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1108 + vf.getModelUUID());
1110 .getHeatFilesForVfModule(vf.getModelUUID());
1112 if (heatFiles != null) {
1113 // add these to stack - to be done in createStack
1114 // here, we will map them to Map<String, Object> from
1115 // Map<String, HeatFiles>
1116 // this will match the nested templates format
1117 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1119 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1120 String heatFileName = entry.getKey();
1121 HeatFiles value = entry.getValue();
1122 if (heatFileName.startsWith("_ERROR|")) {
1123 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1124 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|") + 1);
1125 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1126 LOGGER.debug(error);
1127 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1128 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1129 // Alarm on this error, configuration must be fixed
1130 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1131 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1133 String heatFileBody = value.getFileBody();
1134 String heatFileNameChecked = heatFileName;
1135 LOGGER.debug(heatFileNameChecked + " -> "
1137 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1140 LOGGER.debug("No heat files found -nothing to do here");
1141 heatFilesObjects = null;
1144 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1147 // Check that required parameters have been supplied
1148 StringBuilder missingParams = null;
1149 List<String> paramList = new ArrayList<>();
1151 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1152 // supplied an alias. Only check if we don't find it initially.
1153 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1154 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1156 boolean checkRequiredParameters = true;
1158 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1159 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1160 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1161 checkRequiredParameters = false;
1162 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1163 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1165 } catch (Exception e) {
1166 // No problem - default is true
1167 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1169 // 1604 - Add enhanced environment & parameter checking
1170 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1171 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1172 // Note this also removes any comments
1173 MsoHeatEnvironmentEntry mhee = null;
1174 if (heatEnvironmentString != null && heatEnvironmentString.contains("parameters:")) {
1175 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1176 LOGGER.debug("Enhanced environment checking enabled - 1604");
1177 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1178 //LOGGER.debug("About to create MHEE with " + sb);
1179 mhee = new MsoHeatEnvironmentEntry(sb);
1181 // sshank: hpaEnviromnentString is obtained from requestTypeString above.
1182 if (hpaEnviromnentString != null && hpaEnviromnentString.contains("parameters:")) {
1183 StringBuilder hpasb = new StringBuilder(hpaEnviromnentString);
1184 mhee.setHPAParameters(hpasb);
1187 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1188 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1189 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1191 if (!mhee.isValid()) {
1192 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1194 sb2.append("\nEnvironment:");
1197 LOGGER.debug(sb2.toString());
1199 LOGGER.debug("NO ENVIRONMENT for this entry");
1201 // New with 1707 - all variables converted to their native object types
1202 HashMap<String, Object> goldenInputs = null;
1204 LOGGER.debug("Now handle the inputs....first convert");
1205 ArrayList<String> parameterNames = new ArrayList<>();
1206 HashMap<String, String> aliasToParam = new HashMap<>();
1207 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1210 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1211 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1212 parameterNames.add(htp.getParamName());
1213 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1214 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1215 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1219 LOGGER.debug(sb.toString());
1220 } catch (Exception e) {
1221 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(), e);
1223 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1224 // Map<String, Object> - where the object matches the param type identified in the template
1225 // This will also not copy over params that aren't identified in the template
1226 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1227 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1228 LOGGER.debug("Now add in the base stack outputs if applicable");
1229 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1230 // Step 3 - add the volume inputs if any
1231 LOGGER.debug("Now add in the volume stack outputs if applicable");
1232 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1233 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1235 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1236 LOGGER.debug("Parameter:'" + parm.getParamName()
1240 + parm.getParamAlias());
1242 if (parm.isRequired() && (goldenInputs == null || !goldenInputs.containsKey(parm.getParamName()))) {
1243 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1244 LOGGER.debug("**Parameter " + parm.getParamName()
1245 + " is required and not in the inputs...check environment");
1246 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1247 LOGGER.debug("Required parameter " + parm.getParamName()
1248 + " appears to be in environment - do not count as missing");
1250 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
1251 if (missingParams == null) {
1252 missingParams = new StringBuilder(parm.getParamName());
1254 missingParams.append("," + parm.getParamName());
1258 paramList.add(parm.getParamName());
1260 if (missingParams != null) {
1261 if (checkRequiredParameters) {
1262 // Problem - missing one or more required parameters
1263 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1264 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
1265 MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1266 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1268 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1270 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1273 LOGGER.debug("No missing parameters found - ok to proceed");
1275 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1276 // and it causes problems with json that has arrays
1277 String newEnvironmentString = null;
1279 newEnvironmentString = mhee.getRawEntry().toString();
1282 // "Fix" the template if it has CR/LF (getting this from Oracle)
1283 String template = heatTemplate.getHeatTemplate();
1284 template = template.replaceAll("\r\n", "\n");
1286 // Have the tenant. Now deploy the stack itself
1287 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1288 // because we already checked for those.
1289 long createStackStarttime = System.currentTimeMillis();
1291 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1292 // heatTemplate.getTimeoutMinutes());
1293 if (backout == null) {
1297 LOGGER.debug("heat is not null!!");
1299 heatStack = heat.createStack(cloudSiteId,
1305 heatTemplate.getTimeoutMinutes(),
1306 newEnvironmentString,
1307 nestedTemplatesChecked,
1309 backout.booleanValue());
1311 .recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
1312 "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1313 } catch (MsoException me) {
1314 me.addContext("CreateVFModule");
1315 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1316 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1317 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1318 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1319 MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1321 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1323 throw new VnfException(me);
1324 } catch (NullPointerException npe) {
1325 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1326 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1327 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1328 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1329 MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1331 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1333 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1334 //npe.addContext ("CreateVNF");
1335 throw new VnfException("NullPointerException during heat.createStack");
1336 } catch (Exception e) {
1337 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1338 MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack",
1339 "OpenStack", "CreateStack", vfModuleName);
1340 LOGGER.debug("unhandled exception at heat.createStack", e);
1342 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1343 "Exception while creating stack with OpenStack");
1344 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1346 } catch (Exception e) {
1347 LOGGER.debug("unhandled exception in create VF", e);
1348 throw new VnfException("Exception during create VF " + e.getMessage());
1351 // Make sure DB session is closed
1353 // Reach this point if createStack is successful.
1354 // Populate remaining rollback info and response parameters.
1355 vfRollback.setVnfId(heatStack.getCanonicalName());
1356 vfRollback.setVnfCreated(true);
1358 vnfId.value = heatStack.getCanonicalName();
1359 outputs.value = copyStringOutputs(heatStack.getOutputs());
1360 rollback.value = vfRollback;
1362 LOGGER.debug("VF Module " + vfModuleName + " successfully created");
1363 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1367 public void deleteVfModule(String cloudSiteId,
1370 MsoRequest msoRequest,
1371 Holder<Map<String, String>> outputs) throws VnfException {
1372 MsoLogger.setLogContext(msoRequest);
1373 MsoLogger.setServiceName("DeleteVf");
1374 LOGGER.debug("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1375 // Will capture execution time for metrics
1376 long startTime = System.currentTimeMillis();
1378 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
1380 // 1702 capture the output parameters on a delete
1381 // so we'll need to query first
1382 Map<String, Object> stackOutputs = null;
1384 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1385 } catch (MsoException me) {
1386 // Failed to query the Stack due to an openstack exception.
1387 // Convert to a generic VnfException
1388 me.addContext("DeleteVFModule");
1389 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1390 LOGGER.recordMetricEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1391 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1392 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1393 throw new VnfException(me);
1395 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1396 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1398 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1399 // The possible outcomes of deleteStack are a StackInfo object with status
1400 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1402 long subStartTime = System.currentTimeMillis();
1404 heat.deleteStack(tenantId, cloudSiteId, vnfName, true);
1405 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1406 } catch (MsoException me) {
1407 me.addContext("DeleteVNF");
1408 // Failed to query the Stack due to an openstack exception.
1409 // Convert to a generic VnfException
1410 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1411 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1412 LOGGER.error(MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1413 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1414 throw new VnfException(me);
1417 // On success, nothing is returned.
1418 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1422 public void updateVfModule(String cloudSiteId,
1428 String volumeGroupHeatStackId,
1429 String baseVfHeatStackId,
1430 String vfModuleStackId,
1431 String modelCustomizationUuid,
1432 Map<String, String> inputs,
1433 MsoRequest msoRequest,
1434 Holder<Map<String, String>> outputs,
1435 Holder<VnfRollback> rollback) throws VnfException {
1436 String vfModuleName = vnfName;
1437 String vfModuleType = vnfType;
1438 String methodName = "updateVfModule";
1439 MsoLogger.setLogContext(msoRequest.getRequestId(), msoRequest.getServiceInstanceId());
1440 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1441 MsoLogger.setServiceName(serviceName);
1443 String strInit = "updateVfModule: cloudSiteId=" + cloudSiteId +
1444 ",tenantId=" + tenantId +
1445 ",vnfType=" + vnfType +
1446 ",vnfVersion=" + vnfVersion +
1447 ",vnfName=" + vnfName +
1448 ",requestType=" + requestType +
1449 ",volumeGroupHeatStackId=" + volumeGroupHeatStackId +
1450 ",baseVfHeatStackId=" + baseVfHeatStackId +
1451 ",vfModuleStackId=" + vfModuleStackId +
1452 ",modelCustomizationUuid=" + modelCustomizationUuid;
1453 LOGGER.debug(strInit);
1455 String mcu = modelCustomizationUuid;
1456 boolean useMCUuid = false;
1457 if (mcu != null && !mcu.isEmpty()) {
1458 if (mcu.equalsIgnoreCase("null")) {
1459 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1463 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1468 String requestTypeString = "";
1469 if (requestType != null && !"".equals(requestType)) {
1470 requestTypeString = requestType;
1472 String nestedStackId = null;
1473 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
1474 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1475 nestedStackId = volumeGroupHeatStackId;
1478 String nestedBaseStackId = null;
1479 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
1480 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
1481 nestedBaseStackId = baseVfHeatStackId;
1485 if (inputs == null) {
1486 // Create an empty set of inputs
1487 inputs = new HashMap<>();
1488 LOGGER.debug("inputs == null - setting to empty");
1490 this.sendMapToDebug(inputs);
1492 boolean isBaseRequest = false;
1493 boolean isVolumeRequest = false;
1494 if (requestTypeString.startsWith("VOLUME")) {
1495 isVolumeRequest = true;
1497 if (vfModuleName == null || "".equals(vfModuleName.trim())) {
1498 if (vfModuleStackId != null) {
1499 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1503 LOGGER.debug("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1504 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1506 // Will capture execution time for metrics
1507 long startTime = System.currentTimeMillis();
1509 // Build a default rollback object (no actions performed)
1510 VnfRollback vfRollback = new VnfRollback();
1511 vfRollback.setCloudSiteId(cloudSiteId);
1512 vfRollback.setTenantId(tenantId);
1513 vfRollback.setMsoRequest(msoRequest);
1514 vfRollback.setRequestType(requestTypeString);
1515 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1516 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1517 vfRollback.setIsBase(isBaseRequest);
1518 vfRollback.setVfModuleStackId(vfModuleStackId);
1519 vfRollback.setModelCustomizationUuid(mcu);
1521 // First, look up to see if the VNF already exists.
1522 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
1523 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
1525 StackInfo heatStack = null;
1526 long queryStackStarttime = System.currentTimeMillis();
1527 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1529 heatStack = heat.queryStack(cloudSiteId, tenantId, vfModuleName);
1530 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1531 } catch (MsoException me) {
1532 // Failed to query the Stack due to an openstack exception.
1533 // Convert to a generic VnfException
1534 me.addContext("UpdateVFModule");
1535 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1536 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1537 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1538 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1539 throw new VnfException(me);
1542 //TODO - do we need to check for the other status possibilities?
1543 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
1545 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1546 LOGGER.error(MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1547 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1548 throw new VnfNotFound(cloudSiteId, tenantId, vfModuleName);
1550 LOGGER.debug("Found Existing stack, status=" + heatStack.getStatus());
1551 // Populate the outputs from the existing stack.
1552 outputs.value = copyStringOutputs(heatStack.getOutputs());
1553 rollback.value = vfRollback; // Default rollback - no updates performed
1556 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1557 StackInfo nestedHeatStack = null;
1558 long queryStackStarttime2 = System.currentTimeMillis();
1559 Map<String, Object> nestedVolumeOutputs = null;
1560 if (nestedStackId != null) {
1562 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1563 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1564 LOGGER.recordMetricEvent(queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1565 } catch (MsoException me) {
1566 // Failed to query the Stack due to an openstack exception.
1567 // Convert to a generic VnfException
1568 me.addContext("UpdateVFModule");
1569 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1570 LOGGER.recordMetricEvent(queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1571 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1572 LOGGER.debug("ERROR trying to query nested stack= " + error);
1573 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1574 throw new VnfException(me);
1576 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1577 MsoLogger.setServiceName(serviceName);
1578 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
1579 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1580 LOGGER.debug(error);
1581 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1582 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1584 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1585 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1586 //this.sendMapToDebug(inputs);
1587 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1589 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1590 //this.sendMapToDebug(inputs);
1593 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1594 StackInfo nestedBaseHeatStack = null;
1595 Map<String, Object> baseStackOutputs = null;
1596 if (nestedBaseStackId != null) {
1597 long queryStackStarttime3 = System.currentTimeMillis();
1599 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1600 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1601 LOGGER.recordMetricEvent(queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1602 } catch (MsoException me) {
1603 // Failed to query the Stack due to an openstack exception.
1604 // Convert to a generic VnfException
1605 me.addContext("UpdateVfModule");
1606 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1607 LOGGER.recordMetricEvent(queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1608 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1609 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1610 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1611 throw new VnfException(me);
1613 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1614 MsoLogger.setServiceName(serviceName);
1615 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
1616 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1617 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1618 LOGGER.debug(error);
1619 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1621 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1622 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1623 //this.sendMapToDebug(inputs);
1624 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1626 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1627 //this.sendMapToDebug(inputs);
1631 // Ready to deploy the new VNF
1633 // Get a handle to the Catalog Database
1635 // Make sure DB session is closed
1636 try (CatalogDatabase db = CatalogDatabase.getInstance()) {
1637 // Retrieve the VF definition
1638 VnfResource vnfResource = null;
1640 VfModuleCustomization vfmc = null;
1642 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1643 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1644 vf = vfmc != null ? vfmc.getVfModule() : null;
1646 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1649 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1652 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1653 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "",
1654 MsoLogger.ErrorCode.DataError, error);
1655 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1656 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1658 LOGGER.debug("Got VF module definition from Catalog: " + vf.toString());
1660 isBaseRequest = true;
1661 LOGGER.debug("This a BASE update request");
1663 LOGGER.debug("This is *not* a BASE VF update request");
1664 if (!isVolumeRequest && nestedBaseStackId == null) {
1665 LOGGER.debug("This is unexpected - no nestedBaseStackId with this non-base request");
1669 //1607 - Add version check
1670 // First - see if it's in the VnfResource record
1671 // if we have a vf Module - then we have to query to get the VnfResource record.
1672 if (vf.getVnfResourceModelUUId() != null) {
1673 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1674 //vnfResource = db.getVnfResourceById(vnfResourceId);
1675 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1676 if (vnfResource == null) {
1678 .debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1681 String minVersionVnf = null;
1682 String maxVersionVnf = null;
1683 if (vnfResource != null) {
1685 minVersionVnf = vnfResource.getAicVersionMin();
1686 maxVersionVnf = vnfResource.getAicVersionMax();
1687 } catch (Exception e) {
1688 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
1689 minVersionVnf = null;
1690 maxVersionVnf = null;
1692 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1693 minVersionVnf = null;
1695 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1696 maxVersionVnf = null;
1699 if (minVersionVnf != null && maxVersionVnf != null) {
1700 MavenLikeVersioning aicV = new MavenLikeVersioning();
1701 //String aicVersion = "";
1702 if (this.cloudConfig == null) {
1703 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1706 if (this.cloudConfig != null) {
1707 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1708 if (cloudSiteOpt.isPresent()) {
1709 aicV.setVersion(cloudSiteOpt.get().getAic_version());
1710 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1711 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV
1712 .isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1713 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1714 + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteOpt.get().getId()
1715 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version());
1719 "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1720 + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get()
1721 .getId() + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
1722 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1723 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1724 LOGGER.debug(error);
1725 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1727 } // let this error out downstream to avoid introducing uncertainty at this stage
1729 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1733 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1735 // End Version check 1607
1737 String heatTemplateArtifactUuid = null;
1738 String heatEnvironmentArtifactUuid = null;
1740 HeatTemplate heatTemplate = null;
1741 if (isVolumeRequest) {
1742 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1743 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1745 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1746 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1748 if (heatTemplateArtifactUuid == null) {
1750 "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType="
1751 + requestTypeString;
1752 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "",
1753 MsoLogger.ErrorCode.DataError, error);
1754 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1756 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1757 MsoAlarmLogger.CRITICAL, error);
1758 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1760 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1763 if (heatTemplate == null) {
1764 String error = "Update VNF: undefined Heat Template. VF="
1765 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1766 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1768 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1769 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1771 // Alarm on this error, configuration must be fixed
1772 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1773 MsoAlarmLogger.CRITICAL, error);
1775 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1778 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1780 // Add check for any Environment variable
1781 HeatEnvironment heatEnvironment = null;
1782 String heatEnvironmentString = null;
1784 if (heatEnvironmentArtifactUuid != null) {
1785 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1786 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1787 if (heatEnvironment == null) {
1789 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1790 + ", Environment ID="
1791 + heatEnvironmentArtifactUuid;
1792 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1793 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError,
1795 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1797 // Alarm on this error, configuration must be fixed
1798 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1800 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1802 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1803 heatEnvironmentString = heatEnvironment
1804 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1805 LOGGER.debug("After parsing: " + heatEnvironmentString);
1808 LOGGER.debug("no environment parameter for this VFModuleType " + vfModuleType);
1811 LOGGER.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1812 + heatTemplate.getArtifactUuid());
1813 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1814 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1815 if (nestedTemplates != null) {
1816 // for debugging print them out
1817 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1818 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1819 String providerResourceFile = entry.getKey();
1820 Object value = entry.getValue();
1821 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1822 String childTemplateBody = (String) value;
1823 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1824 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1827 LOGGER.debug("No nested templates found - nothing to do here");
1828 nestedTemplatesChecked = null;
1831 // Also add the files: for any get_files associated with this VfModule
1832 // *if* there are any
1833 LOGGER.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1834 + vf.getModelUUID());
1836 Map<String, HeatFiles> heatFiles = null;
1837 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1838 Map<String, Object> heatFilesObjects = new HashMap<>();
1840 // Add ability to turn on adding get_files with volume requests (by property).
1841 boolean addGetFilesOnVolumeReq = false;
1843 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1844 .getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1845 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1846 addGetFilesOnVolumeReq = true;
1847 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1849 } catch (Exception e) {
1850 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1851 + " - default to false", e);
1853 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1855 "In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1856 + vf.getModelUUID());
1858 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1859 if (heatFiles != null) {
1860 // add these to stack - to be done in createStack
1861 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1862 // this will match the nested templates format
1863 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1865 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1866 String heatFileName = entry.getKey();
1867 HeatFiles value = entry.getValue();
1868 if (heatFileName.startsWith("_ERROR|")) {
1869 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1870 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|") + 1);
1871 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType
1872 + " at HEAT_FILES index=" + heatFileId;
1873 LOGGER.debug(error);
1875 .error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId,
1876 vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1877 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1878 MsoLogger.ResponseCode.DataNotFound, error);
1879 // Alarm on this error, configuration must be fixed
1880 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1881 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1883 String heatFileBody = value.getFileBody();
1884 LOGGER.debug(heatFileName + " -> " + heatFileBody);
1885 heatFilesObjects.put(heatFileName, heatFileBody);
1888 LOGGER.debug("No heat files found -nothing to do here");
1889 heatFilesObjects = null;
1893 // Check that required parameters have been supplied
1894 StringBuilder missingParams = null;
1895 List<String> paramList = new ArrayList<>();
1897 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1898 // supplied an alias. Only check if we don't find it initially.
1899 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1900 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1902 boolean haveEnvironmentParameters = false;
1903 boolean checkRequiredParameters = true;
1905 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1906 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1907 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1908 checkRequiredParameters = false;
1909 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1910 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1912 } catch (Exception e) {
1913 // No problem - default is true
1914 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1916 // 1604 - Add enhanced environment & parameter checking
1917 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1918 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1919 // Note this also removes any comments
1920 MsoHeatEnvironmentEntry mhee = null;
1921 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase().contains("parameters:")) {
1922 LOGGER.debug("Enhanced environment checking enabled - 1604");
1923 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1924 //LOGGER.debug("About to create MHEE with " + sb);
1925 mhee = new MsoHeatEnvironmentEntry(sb);
1926 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1927 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1928 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1930 if (!mhee.isValid()) {
1931 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1933 sb2.append("\nEnvironment:");
1936 LOGGER.debug(sb2.toString());
1938 LOGGER.debug("NO ENVIRONMENT for this entry");
1941 // New for 1607 - support params of json type
1942 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1943 boolean hasJson = false;
1945 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1946 LOGGER.debug("Parameter:'" + parm.getParamName()
1950 + parm.getParamAlias());
1952 String parameterType = parm.getParamType();
1953 if (parameterType == null || "".equals(parameterType.trim())) {
1954 parameterType = "String";
1956 JsonNode jsonNode = null;
1957 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1958 if (inputs.containsKey(parm.getParamName())) {
1960 String jsonString = null;
1962 jsonString = inputs.get(parm.getParamName());
1963 jsonNode = new ObjectMapper().readTree(jsonString);
1964 } catch (JsonParseException jpe) {
1965 //TODO - what to do here?
1966 //for now - send the error to debug, but just leave it as a String
1967 String errorMessage = jpe.getMessage();
1968 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1971 } catch (Exception e) {
1973 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1977 if (jsonNode != null) {
1978 jsonParams.put(parm.getParamName(), jsonNode);
1980 } else if (inputs.containsKey(parm.getParamAlias())) {
1982 String jsonString = null;
1984 jsonString = inputs.get(parm.getParamAlias());
1985 jsonNode = new ObjectMapper().readTree(jsonString);
1986 } catch (JsonParseException jpe) {
1987 //TODO - what to do here?
1988 //for now - send the error to debug, but just leave it as a String
1989 String errorMessage = jpe.getMessage();
1990 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1993 } catch (Exception e) {
1995 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1999 if (jsonNode != null) {
2000 // Notice here - we add it to the jsonParams hashMap with the actual name -
2001 // then manipulate the inputs so when we check for aliases below - it will not
2003 jsonParams.put(parm.getParamName(), jsonNode);
2004 inputs.remove(parm.getParamAlias());
2005 inputs.put(parm.getParamName(), jsonString);
2007 } //TODO add a check for the parameter in the env file
2010 if (parm.isRequired() && (inputs == null || !inputs.containsKey(parm.getParamName()))) {
2011 if (inputs.containsKey(parm.getParamAlias())) {
2012 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2013 String realParamName = parm.getParamName();
2014 String alias = parm.getParamAlias();
2015 String value = inputs.get(alias);
2016 LOGGER.debug("*Found an Alias: paramName=" + realParamName
2021 inputs.remove(alias);
2022 inputs.put(realParamName, value);
2023 LOGGER.debug(alias + " entry removed from inputs, added back using " + realParamName);
2025 // enhanced - check if it's in the Environment (note: that method
2026 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2028 LOGGER.debug("Required parameter " + parm.getParamName()
2029 + " appears to be in environment - do not count as missing");
2031 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
2032 if (missingParams == null) {
2033 missingParams = new StringBuilder(parm.getParamName());
2035 missingParams.append("," + parm.getParamName());
2039 paramList.add(parm.getParamName());
2041 if (missingParams != null) {
2042 // Problem - missing one or more required parameters
2043 if (checkRequiredParameters) {
2044 String error = "Update VNF: Missing Required inputs: " + missingParams;
2045 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
2046 MsoLogger.ErrorCode.DataError, error);
2047 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
2049 throw new VnfException(error, MsoExceptionCategory.USERDATA);
2051 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
2054 LOGGER.debug("No missing parameters found - ok to proceed");
2057 // Just submit the envt entry as received from the database
2058 String newEnvironmentString = null;
2060 newEnvironmentString = mhee.getRawEntry().toString();
2063 // Remove any extraneous parameters (don't throw an error)
2064 if (inputs != null) {
2065 List<String> extraParams = new ArrayList<>();
2066 extraParams.addAll(inputs.keySet());
2067 // This is not a valid parameter for this template
2068 extraParams.removeAll(paramList);
2069 if (!extraParams.isEmpty()) {
2070 LOGGER.warn(MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "",
2071 MsoLogger.ErrorCode.DataError, "Extra params");
2072 inputs.keySet().removeAll(extraParams);
2075 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2076 Map<String, Object> inputsTwo = null;
2077 if (hasJson && jsonParams.size() > 0) {
2078 inputsTwo = new HashMap<>();
2079 for (Map.Entry<String, String> entry : inputs.entrySet()) {
2080 String keyParamName = entry.getKey();
2081 String value = entry.getValue();
2082 if (jsonParams.containsKey(keyParamName)) {
2083 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2085 inputsTwo.put(keyParamName, value);
2090 // "Fix" the template if it has CR/LF (getting this from Oracle)
2091 String template = heatTemplate.getHeatTemplate();
2092 template = template.replaceAll("\r\n", "\n");
2094 // Have the tenant. Now deploy the stack itself
2095 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2096 // because we already checked for those.
2097 long updateStackStarttime = System.currentTimeMillis();
2100 heatStack = heatU.updateStack(cloudSiteId,
2104 copyStringInputs(inputs),
2106 heatTemplate.getTimeoutMinutes(),
2107 newEnvironmentString,
2108 //heatEnvironmentString,
2109 nestedTemplatesChecked,
2111 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2112 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2113 "UpdateStack", null);
2115 heatStack = heatU.updateStack(cloudSiteId,
2121 heatTemplate.getTimeoutMinutes(),
2122 newEnvironmentString,
2123 //heatEnvironmentString,
2124 nestedTemplatesChecked,
2126 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2127 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2128 "UpdateStack", null);
2130 } catch (MsoException me) {
2131 me.addContext("UpdateVFModule");
2132 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2133 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.ERROR,
2134 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2135 LOGGER.error(MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
2136 MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2138 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
2140 throw new VnfException(me);
2143 // Make sure DB session is closed
2145 // Reach this point if updateStack is successful.
2146 // Populate remaining rollback info and response parameters.
2147 vfRollback.setVnfId(heatStack.getCanonicalName());
2148 vfRollback.setVnfCreated(true);
2150 outputs.value = copyStringOutputs(heatStack.getOutputs());
2151 rollback.value = vfRollback;
2152 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2155 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2156 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2157 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2158 if (vfModuleStackId == null)
2160 int index = vfModuleStackId.lastIndexOf('/');
2163 String vfModuleName = null;
2165 vfModuleName = vfModuleStackId.substring(0, index);
2166 } catch (Exception e) {
2167 LOGGER.debug("Exception", e);
2168 vfModuleName = null;
2170 return vfModuleName;