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.concurrent.TimeUnit;
35 import javax.jws.WebService;
36 import javax.xml.ws.Holder;
38 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
39 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
40 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
41 import org.openecomp.mso.cloud.CloudConfig;
42 import org.openecomp.mso.cloud.CloudConfigFactory;
43 import org.openecomp.mso.cloud.CloudSite;
44 import org.openecomp.mso.db.catalog.CatalogDatabase;
45 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
46 import org.openecomp.mso.db.catalog.beans.HeatFiles;
47 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
48 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
49 import org.openecomp.mso.db.catalog.beans.VfModule;
50 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
51 import org.openecomp.mso.db.catalog.beans.VnfResource;
52 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
53 import org.openecomp.mso.entity.MsoRequest;
54 import org.openecomp.mso.logger.MessageEnum;
55 import org.openecomp.mso.logger.MsoAlarmLogger;
56 import org.openecomp.mso.logger.MsoLogger;
57 import org.openecomp.mso.openstack.beans.HeatStatus;
58 import org.openecomp.mso.openstack.beans.StackInfo;
59 import org.openecomp.mso.openstack.beans.VnfRollback;
60 import org.openecomp.mso.openstack.beans.VnfStatus;
61 import org.openecomp.mso.openstack.exceptions.MsoException;
62 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
63 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
64 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
65 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
66 import org.openecomp.mso.properties.MsoPropertiesFactory;
68 import com.fasterxml.jackson.core.JsonParseException;
69 import com.fasterxml.jackson.databind.JsonNode;
70 import com.fasterxml.jackson.databind.ObjectMapper;
72 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
73 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
75 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
76 protected CloudConfig cloudConfig = null;
78 MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory();
80 protected MsoHeatUtils heat;
82 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
83 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
84 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
85 private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA);
86 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger();
87 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
88 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
89 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
92 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
94 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
96 public MsoVnfAdapterImpl() {
97 // empty implementation
101 * This constructor MUST be used if this class is called with the new operator.
103 * @param msoPropFactory
105 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
106 this.msoPropertiesFactory = msoPropFactory;
107 this.cloudConfigFactory = cloudConfigFact;
108 heat = new MsoHeatUtils(MSO_PROP_VNF_ADAPTER, this.msoPropertiesFactory, this.cloudConfigFactory);
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 StackInfo heatStack = null;
282 long subStartTime = System.currentTimeMillis();
284 heatStack = heat.queryStack(cloudSiteId, tenantId, vnfName);
285 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
286 } catch (MsoException me) {
287 me.addContext("QueryVNF");
288 // Failed to query the Stack due to an openstack exception.
289 // Convert to a generic VnfException
290 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
291 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
292 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
293 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
294 throw new VnfException(me);
297 // Populate the outputs based on the returned Stack information
299 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
301 vnfExists.value = Boolean.FALSE;
302 status.value = VnfStatus.NOTFOUND;
304 outputs.value = new HashMap<>(); // Return as an empty map
306 LOGGER.debug("VNF " + vnfName + " not found");
308 vnfExists.value = Boolean.TRUE;
309 status.value = stackStatusToVnfStatus(heatStack.getStatus());
310 vnfId.value = heatStack.getCanonicalName();
311 outputs.value = copyStringOutputs(heatStack.getOutputs());
313 LOGGER.debug("VNF " + vnfName + " found, ID = " + vnfId.value);
315 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
319 * This is the "Delete VNF" web service implementation.
320 * It will delete a VNF by name or ID in the specified cloud and tenant.
322 * The method has no outputs.
324 * @param cloudSiteId CLLI code of the cloud site in which to delete
325 * @param tenantId Openstack tenant identifier
326 * @param vnfName VNF Name or Openstack ID
327 * @param msoRequest Request tracking information for logs
330 public void deleteVnf(String cloudSiteId,
333 MsoRequest msoRequest) throws VnfException {
334 MsoLogger.setLogContext(msoRequest);
335 MsoLogger.setServiceName("DeleteVnf");
336 LOGGER.debug("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
337 // Will capture execution time for metrics
338 long startTime = System.currentTimeMillis();
340 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
341 // The possible outcomes of deleteStack are a StackInfo object with status
342 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
344 long subStartTime = System.currentTimeMillis();
346 heat.deleteStack(tenantId, cloudSiteId, vnfName, true);
347 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
348 } catch (MsoException me) {
349 me.addContext("DeleteVNF");
350 // Failed to query the Stack due to an openstack exception.
351 // Convert to a generic VnfException
352 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
353 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
354 LOGGER.error(MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
355 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
356 throw new VnfException(me);
359 // On success, nothing is returned.
360 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
364 * This web service endpoint will rollback a previous Create VNF operation.
365 * A rollback object is returned to the client in a successful creation
366 * response. The client can pass that object as-is back to the rollbackVnf
367 * operation to undo the creation.
370 public void rollbackVnf(VnfRollback rollback) throws VnfException {
371 long startTime = System.currentTimeMillis();
372 MsoLogger.setServiceName("RollbackVnf");
373 // rollback may be null (e.g. if stack already existed when Create was called)
374 if (rollback == null) {
375 LOGGER.info(MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
376 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
380 // Get the elements of the VnfRollback object for easier access
381 String cloudSiteId = rollback.getCloudSiteId();
382 String tenantId = rollback.getTenantId();
383 String vnfId = rollback.getVnfId();
385 MsoLogger.setLogContext(rollback.getMsoRequest());
387 LOGGER.debug("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
389 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
390 // The possible outcomes of deleteStack are a StackInfo object with status
391 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
393 long subStartTime = System.currentTimeMillis();
395 heat.deleteStack(tenantId, cloudSiteId, vnfId, true);
396 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
397 } catch (MsoException me) {
398 // Failed to rollback the Stack due to an openstack exception.
399 // Convert to a generic VnfException
400 me.addContext("RollbackVNF");
401 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
402 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
403 LOGGER.error(MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
404 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
405 throw new VnfException(me);
407 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
410 private VnfStatus stackStatusToVnfStatus(HeatStatus stackStatus) {
411 switch (stackStatus) {
413 return VnfStatus.ACTIVE;
415 return VnfStatus.ACTIVE;
417 return VnfStatus.FAILED;
419 return VnfStatus.UNKNOWN;
423 private Map<String, String> copyStringOutputs(Map<String, Object> stackOutputs) {
424 Map<String, String> stringOutputs = new HashMap<>();
425 for (Map.Entry<String, Object> entry : stackOutputs.entrySet()) {
426 String key = entry.getKey();
427 Object value = entry.getValue();
428 if (value instanceof String) {
429 stringOutputs.put(key, (String) value);
430 } else if (value instanceof Integer) {
432 String str = "" + value;
433 stringOutputs.put(key, str);
434 } catch (Exception e) {
435 LOGGER.debug("Unable to add " + key + " to outputs", e);
437 } else if (value instanceof JsonNode) {
439 //String str = this.convertNode((JsonNode) value);
440 String str = value.toString();
441 stringOutputs.put(key, str);
442 } catch (Exception e) {
443 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode", e);
445 } else if (value instanceof java.util.LinkedHashMap) {
447 //String str = JSON_MAPPER.writeValueAsString(value);
448 String str = value.toString();
449 stringOutputs.put(key, str);
450 } catch (Exception e) {
451 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap", e);
455 String str = value.toString();
456 stringOutputs.put(key, str);
457 } catch (Exception e) {
458 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(), e);
462 return stringOutputs;
465 private Map<String, Object> copyStringInputs(Map<String, String> stringInputs) {
466 return new HashMap<>(stringInputs);
469 private boolean callHeatbridge(String heatStackId) {
470 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
471 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
472 long waitTimeMs = 10000L;
474 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
475 String[] envp = null;
476 File dir = new File(executionDir);
477 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
478 Runtime r = Runtime.getRuntime();
479 Process p = r.exec(cmdarray, envp, dir);
480 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
482 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
483 return wait && p.exitValue() == 0;
484 } catch (IOException e) {
485 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
487 } catch (InterruptedException e) {
488 LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e);
490 } catch (RuntimeException e) {
491 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e);
496 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
498 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
499 if (inputs == null) {
501 } else if (inputs.size() < 1) {
502 sb.append("\tEMPTY");
504 for (Map.Entry<String, Object> entry : inputs.entrySet()) {
506 String str = entry.getKey();
507 Object value = entry.getValue();
509 outputString = value.toString();
510 } catch (Exception e) {
511 LOGGER.debug("Exception :", e);
512 outputString = "Unable to call toString() on the value for " + str;
514 sb.append("\t\nitem ").append(i++).append(": '").append(str).append("'='").append(outputString)
518 LOGGER.debug(sb.toString());
521 private void sendMapToDebug(Map<String, String> inputs) {
523 StringBuilder sb = new StringBuilder("inputs:");
524 if (inputs == null) {
526 } else if (inputs.size() < 1) {
527 sb.append("\tEMPTY");
529 for (String str : inputs.keySet()) {
530 sb.append("\titem ").append(i++).append(": ").append(str).append("=").append(inputs.get(str));
533 LOGGER.debug(sb.toString());
536 private String convertNode(final JsonNode node) {
538 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
539 final String json = JSON_MAPPER.writeValueAsString(obj);
541 } catch (Exception e) {
542 LOGGER.debug("Error converting json to string " + e.getMessage(), e);
544 return "[Error converting json to string]";
547 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
548 if (objectMap == null) {
551 Map<String, String> stringMap = new HashMap<>();
552 for (String key : objectMap.keySet()) {
553 if (!stringMap.containsKey(key)) {
554 Object obj = objectMap.get(key);
555 if (obj instanceof String) {
556 stringMap.put(key, (String) objectMap.get(key));
557 } else if (obj instanceof JsonNode) {
558 // This is a bit of mess - but I think it's the least impacting
559 // let's convert it BACK to a string - then it will get converted back later
561 String str = this.convertNode((JsonNode) obj);
562 stringMap.put(key, str);
563 } catch (Exception e) {
564 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode " + key, e);
565 //okay in this instance - only string values (fqdn) are expected to be needed
567 } else if (obj instanceof java.util.LinkedHashMap) {
568 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
570 String str = JSON_MAPPER.writeValueAsString(obj);
571 stringMap.put(key, str);
572 } catch (Exception e) {
573 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap " + key, e);
575 } else if (obj instanceof Integer) {
577 String str = "" + obj;
578 stringMap.put(key, str);
579 } catch (Exception e) {
580 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer " + key, e);
584 String str = obj.toString();
585 stringMap.put(key, str);
586 } catch (Exception e) {
587 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value " + key + " (" + e.getMessage() + ")", e);
597 public void createVfModule(String cloudSiteId,
603 String volumeGroupHeatStackId,
604 String baseVfHeatStackId,
605 String modelCustomizationUuid,
606 Map<String, String> inputs,
607 Boolean failIfExists,
609 MsoRequest msoRequest,
610 Holder<String> vnfId,
611 Holder<Map<String, String>> outputs,
612 Holder<VnfRollback> rollback) throws VnfException {
613 String vfModuleName = vnfName;
614 String vfModuleType = vnfType;
615 String vfVersion = vnfVersion;
616 String mcu = modelCustomizationUuid;
617 boolean useMCUuid = false;
618 if (mcu != null && !mcu.isEmpty()) {
619 if ("null".equalsIgnoreCase(mcu)) {
620 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
624 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
628 MsoLogger.setLogContext(msoRequest);
629 MsoLogger.setServiceName("CreateVfModule");
630 String requestTypeString = "";
631 if (requestType != null && !"".equals(requestType)) {
632 requestTypeString = requestType;
634 String nestedStackId = null;
635 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
636 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
637 nestedStackId = volumeGroupHeatStackId;
640 String nestedBaseStackId = null;
641 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
642 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
643 nestedBaseStackId = baseVfHeatStackId;
647 if (inputs == null) {
648 // Create an empty set of inputs
649 inputs = new HashMap<>();
650 LOGGER.debug("inputs == null - setting to empty");
652 this.sendMapToDebug(inputs);
654 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
655 boolean oldWay = false;
656 if (requestTypeString.startsWith("X")) {
658 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
659 requestTypeString = requestTypeString.substring(1);
662 // 1607 - let's parse out the request type we're being sent
663 boolean isBaseRequest = false;
664 boolean isVolumeRequest = false;
665 if (requestTypeString.startsWith("VOLUME")) {
666 isVolumeRequest = true;
669 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
671 // Will capture execution time for metrics
672 long startTime = System.currentTimeMillis();
674 // Build a default rollback object (no actions performed)
675 VnfRollback vfRollback = new VnfRollback();
676 vfRollback.setCloudSiteId(cloudSiteId);
677 vfRollback.setTenantId(tenantId);
678 vfRollback.setMsoRequest(msoRequest);
679 vfRollback.setRequestType(requestTypeString);
680 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
681 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
682 vfRollback.setIsBase(isBaseRequest);
683 vfRollback.setModelCustomizationUuid(mcu);
685 // Put data into A&AI through Heatstack
686 callHeatbridge(baseVfHeatStackId);
688 // First, look up to see if the VF already exists.
689 StackInfo heatStack = null;
690 long subStartTime1 = System.currentTimeMillis();
692 heatStack = heat.queryStack(cloudSiteId, tenantId, vfModuleName);
693 LOGGER.recordMetricEvent(subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
694 } catch (MsoException me) {
695 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
696 LOGGER.recordMetricEvent(subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
697 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
698 // Failed to query the Stack due to an openstack exception.
699 // Convert to a generic VnfException
700 me.addContext("CreateVFModule");
701 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
702 throw new VnfException(me);
704 // New with 1607 - more precise handling/messaging if the stack already exists
705 if (heatStack != null && !(heatStack.getStatus() == HeatStatus.NOTFOUND)) {
706 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
707 HeatStatus status = heatStack.getStatus();
708 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
709 // fail - it's in progress - return meaningful error
710 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.";
711 LOGGER.error(MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
712 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
713 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
715 if (status == HeatStatus.FAILED) {
716 // fail - it exists and is in a FAILED state
717 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
718 LOGGER.error(MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
719 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
720 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
722 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
723 // fail - it exists and is in a FAILED state
724 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
725 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");
726 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
727 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
729 if (status == HeatStatus.CREATED) {
731 if (failIfExists != null && failIfExists) {
732 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
733 LOGGER.error(MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
734 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
735 throw new VnfAlreadyExists(vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName());
737 LOGGER.debug("Found Existing stack, status=" + heatStack.getStatus());
738 // Populate the outputs from the existing stack.
739 vnfId.value = heatStack.getCanonicalName();
740 outputs.value = copyStringOutputs(heatStack.getOutputs());
741 rollback.value = vfRollback; // Default rollback - no updates performed
744 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
749 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
750 StackInfo nestedHeatStack = null;
751 long subStartTime2 = System.currentTimeMillis();
752 Map<String, Object> nestedVolumeOutputs = null;
753 if (nestedStackId != null) {
755 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
756 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
757 LOGGER.recordMetricEvent(subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
758 } catch (MsoException me) {
759 // Failed to query the Stack due to an openstack exception.
760 // Convert to a generic VnfException
761 me.addContext("CreateVFModule");
762 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
763 LOGGER.recordMetricEvent(subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
764 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
765 LOGGER.debug("ERROR trying to query nested stack= " + error);
766 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
767 throw new VnfException(me);
769 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
770 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
771 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
772 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
774 throw new VnfException(error, MsoExceptionCategory.USERDATA);
776 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
777 //this.sendMapToDebug(inputs);
778 nestedVolumeOutputs = nestedHeatStack.getOutputs();
779 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
781 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
782 //this.sendMapToDebug(inputs);
786 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
787 StackInfo nestedBaseHeatStack = null;
788 long subStartTime3 = System.currentTimeMillis();
789 Map<String, Object> baseStackOutputs = null;
790 if (nestedBaseStackId != null) {
792 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
793 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
794 LOGGER.recordMetricEvent(subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
795 } catch (MsoException me) {
796 // Failed to query the Stack due to an openstack exception.
797 // Convert to a generic VnfException
798 me.addContext("CreateVFModule");
799 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
800 LOGGER.recordMetricEvent(subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
801 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
802 LOGGER.debug("ERROR trying to query nested base stack= " + error);
803 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
804 throw new VnfException(me);
806 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
807 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
808 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");
809 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
811 throw new VnfException(error, MsoExceptionCategory.USERDATA);
813 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
814 //this.sendMapToDebug(inputs);
815 baseStackOutputs = nestedBaseHeatStack.getOutputs();
816 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
818 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
819 //this.sendMapToDebug(inputs);
823 // Ready to deploy the new VNF
825 try (CatalogDatabase db = getCatalogDatabase()) {
828 VnfResource vnfResource = null;
829 VfModuleCustomization vfmc = null;
830 LOGGER.debug("version: " + vfVersion);
832 // 1707 - db refactoring
833 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
834 vf = vfmc != null ? vfmc.getVfModule() : null;
835 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
836 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
838 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
840 "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
841 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
842 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "",
843 MsoLogger.ErrorCode.DataError,
844 "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
845 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
847 throw new VnfException(error, MsoExceptionCategory.USERDATA);
849 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
852 isBaseRequest = true;
853 LOGGER.debug("This is a BASE VF request!");
855 LOGGER.debug("This is *not* a BASE VF request!");
856 if (!isVolumeRequest && nestedBaseStackId == null) {
858 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
861 } else { // This is to support gamma only - get info from vnf_resource table
862 if (vfVersion != null && !vfVersion.isEmpty()) {
863 vnfResource = db.getVnfResource(vnfType, vnfVersion);
865 vnfResource = db.getVnfResource(vnfType);
867 if (vnfResource == null) {
868 String error = "Create VNF: Unknown VNF Type: " + vnfType;
869 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
870 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
871 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
872 throw new VnfException(error, MsoExceptionCategory.USERDATA);
874 LOGGER.debug("Got VNF module definition from Catalog: "
875 + vnfResource.toString());
877 // By here - we have either a vf or vnfResource
879 //1607 - Add version check
880 // First - see if it's in the VnfResource record
881 // if we have a vf Module - then we have to query to get the VnfResource record.
883 if (vf.getVnfResourceModelUUId() != null) {
884 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
885 //vnfResource = db.getVnfResourceById(vnfResourceId);
886 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
887 if (vnfResource == null) {
889 "Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
893 String minVersionVnf = null;
894 String maxVersionVnf = null;
895 if (vnfResource != null) {
897 minVersionVnf = vnfResource.getAicVersionMin();
898 maxVersionVnf = vnfResource.getAicVersionMax();
899 } catch (Exception e) {
900 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
901 minVersionVnf = null;
902 maxVersionVnf = null;
904 if (minVersionVnf != null && "".equals(minVersionVnf)) {
905 minVersionVnf = null;
907 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
908 maxVersionVnf = null;
911 if (minVersionVnf != null && maxVersionVnf != null) {
912 MavenLikeVersioning aicV = new MavenLikeVersioning();
913 if (this.cloudConfig == null) {
914 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
917 if (this.cloudConfig != null) {
918 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
919 if (cloudSiteOpt.isPresent()) {
920 aicV.setVersion(cloudSiteOpt.get().getAic_version());
921 // Add code to handle unexpected values in here
922 boolean moreThanMin = true;
923 boolean equalToMin = true;
924 boolean moreThanMax = true;
925 boolean equalToMax = true;
926 boolean doNotTest = false;
928 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
929 equalToMin = aicV.isTheSameVersion(minVersionVnf);
930 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
931 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
932 } catch (Exception e) {
933 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage()
934 + " - will default to not check", e);
938 if ((moreThanMin || equalToMin) // aic >= min
939 && (equalToMax || !(moreThanMax))) { //aic <= max
940 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
941 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf
942 + " supported on Cloud: " + cloudSiteOpt.get().getId() + " with AIC_Version:"
943 + cloudSiteOpt.get().getAic_version());
947 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
948 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:"
949 + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get().getId()
950 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
951 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
952 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
954 throw new VnfException(error, MsoExceptionCategory.USERDATA);
957 LOGGER.debug("bypassing testing AIC version...");
959 } // let this error out downstream to avoid introducing uncertainty at this stage
961 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
965 "AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
967 // End Version check 1607
969 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
970 // with VNF_RESOURCE - we use the old methods.
971 //Integer heatTemplateId = null;
972 //Integer heatEnvtId = null;
974 String heatTemplateArtifactUuid = null;
975 String heatEnvironmentArtifactUuid = null;
978 if (isVolumeRequest) {
979 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
980 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
982 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
983 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
986 if (isVolumeRequest) {
987 LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
989 heatTemplateArtifactUuid = vnfResource.getTemplateId();
990 heatEnvironmentArtifactUuid = null;
993 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
994 HeatTemplate heatTemplate = null;
995 if (heatTemplateArtifactUuid == null || "".equals(heatTemplateArtifactUuid)) {
996 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
997 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
998 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
999 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1000 MsoAlarmLogger.CRITICAL, error);
1001 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1003 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1005 if (heatTemplate == null) {
1006 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1007 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1009 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1010 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1011 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1012 MsoAlarmLogger.CRITICAL, error);
1013 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1015 LOGGER.debug("Got HEAT Template from DB");
1017 HeatEnvironment heatEnvironment = null;
1018 String heatEnvironmentString = null;
1020 if (heatEnvironmentArtifactUuid != null && !"".equals(heatEnvironmentArtifactUuid)) {
1021 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1022 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1023 if (heatEnvironment == null) {
1024 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1025 + ", Environment ID="
1026 + heatEnvironmentArtifactUuid;
1027 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1028 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment",
1029 MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1030 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1032 // Alarm on this error, configuration must be fixed
1033 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1035 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1037 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1038 heatEnvironmentString = heatEnvironment
1039 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1040 LOGGER.debug("after parsing: " + heatEnvironmentString);
1043 LOGGER.debug("no environment parameter found for this Type " + vfModuleType);
1046 // Replace flavors in environment with those returned by OOF
1047 Map<String, Object> returnMap = updateFlavorsFromOof(heatEnvironmentString, inputs);
1048 heatEnvironmentString = returnMap.get("heatEnvironmentString").toString();
1049 LOGGER.debug("After OOF Update Heat Env String is: " + heatEnvironmentString);
1050 if (returnMap.get("inputs") instanceof Map) {
1051 inputs = (Map<String, String>) returnMap.get("inputs");
1052 LOGGER.debug("After OOF Update inputs are: " + inputs.toString());
1054 LOGGER.debug("inputs is not an instance of a Map: " + returnMap.get("inputs"));
1055 throw new VnfException("Updating inputs using OOF info failed.", MsoExceptionCategory.INTERNAL);
1058 // 1510 - Add the files: for nested templates *if* there are any
1059 LOGGER.debug("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1060 + heatTemplate.getArtifactUuid());
1061 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1062 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1063 if (nestedTemplates != null) {
1064 // for debugging print them out
1065 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1066 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1067 String providerResourceFile = entry.getKey();
1068 Object value = entry.getValue();
1069 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1070 String childTemplateBody = (String) value;
1071 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1072 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1075 LOGGER.debug("No nested templates found - nothing to do here");
1076 nestedTemplatesChecked = null; // just to make sure
1079 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1080 // *if* there are any
1081 Map<String, HeatFiles> heatFiles = null;
1082 Map<String, Object> heatFilesObjects = new HashMap<>();
1084 // Add ability to turn on adding get_files with volume requests (by property).
1085 boolean addGetFilesOnVolumeReq = false;
1087 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1088 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1089 addGetFilesOnVolumeReq = true;
1090 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1092 } catch (Exception e) {
1093 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1096 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1098 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1099 //heatFiles = db.getHeatFiles(vnfResource.getId());
1101 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1102 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1103 + vf.getModelUUID());
1105 .getHeatFilesForVfModule(vf.getModelUUID());
1107 if (heatFiles != null) {
1108 // add these to stack - to be done in createStack
1109 // here, we will map them to Map<String, Object> from
1110 // Map<String, HeatFiles>
1111 // this will match the nested templates format
1112 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1114 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1115 String heatFileName = entry.getKey();
1116 HeatFiles value = entry.getValue();
1117 if (heatFileName.startsWith("_ERROR|")) {
1118 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1119 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|") + 1);
1120 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1121 LOGGER.debug(error);
1122 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1123 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1124 // Alarm on this error, configuration must be fixed
1125 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1126 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1128 String heatFileBody = value.getFileBody();
1129 String heatFileNameChecked = heatFileName;
1130 LOGGER.debug(heatFileNameChecked + " -> "
1132 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1135 LOGGER.debug("No heat files found -nothing to do here");
1136 heatFilesObjects = null;
1139 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1142 // Check that required parameters have been supplied
1143 StringBuilder missingParams = null;
1144 List<String> paramList = new ArrayList<>();
1146 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1147 // supplied an alias. Only check if we don't find it initially.
1148 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1149 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1151 boolean checkRequiredParameters = true;
1153 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1154 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1155 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1156 checkRequiredParameters = false;
1157 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1158 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1160 } catch (Exception e) {
1161 // No problem - default is true
1162 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1164 // 1604 - Add enhanced environment & parameter checking
1165 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1166 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1167 // Note this also removes any comments
1168 MsoHeatEnvironmentEntry mhee = null;
1169 if (heatEnvironmentString != null && heatEnvironmentString.contains("parameters:")) {
1170 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1171 LOGGER.debug("Enhanced environment checking enabled - 1604");
1172 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1173 //LOGGER.debug("About to create MHEE with " + sb);
1174 mhee = new MsoHeatEnvironmentEntry(sb);
1176 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1177 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1178 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1180 if (!mhee.isValid()) {
1181 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1183 sb2.append("\nEnvironment:");
1186 LOGGER.debug(sb2.toString());
1188 LOGGER.debug("NO ENVIRONMENT for this entry");
1190 // New with 1707 - all variables converted to their native object types
1191 HashMap<String, Object> goldenInputs = null;
1193 LOGGER.debug("Now handle the inputs....first convert");
1194 ArrayList<String> parameterNames = new ArrayList<>();
1195 HashMap<String, String> aliasToParam = new HashMap<>();
1196 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1199 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1200 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1201 parameterNames.add(htp.getParamName());
1202 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1203 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1204 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1208 LOGGER.debug(sb.toString());
1209 } catch (Exception e) {
1210 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(), e);
1212 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1213 // Map<String, Object> - where the object matches the param type identified in the template
1214 // This will also not copy over params that aren't identified in the template
1215 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1216 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1217 LOGGER.debug("Now add in the base stack outputs if applicable");
1218 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1219 // Step 3 - add the volume inputs if any
1220 LOGGER.debug("Now add in the volume stack outputs if applicable");
1221 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1222 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1224 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1225 LOGGER.debug("Parameter:'" + parm.getParamName()
1229 + parm.getParamAlias());
1231 if (parm.isRequired() && (goldenInputs == null || !goldenInputs.containsKey(parm.getParamName()))) {
1232 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1233 LOGGER.debug("**Parameter " + parm.getParamName()
1234 + " is required and not in the inputs...check environment");
1235 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1236 LOGGER.debug("Required parameter " + parm.getParamName()
1237 + " appears to be in environment - do not count as missing");
1239 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
1240 if (missingParams == null) {
1241 missingParams = new StringBuilder(parm.getParamName());
1243 missingParams.append("," + parm.getParamName());
1247 paramList.add(parm.getParamName());
1249 if (missingParams != null) {
1250 if (checkRequiredParameters) {
1251 // Problem - missing one or more required parameters
1252 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1253 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
1254 MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1255 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1257 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1259 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1262 LOGGER.debug("No missing parameters found - ok to proceed");
1264 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1265 // and it causes problems with json that has arrays
1266 String newEnvironmentString = null;
1268 newEnvironmentString = mhee.getRawEntry().toString();
1271 // "Fix" the template if it has CR/LF (getting this from Oracle)
1272 String template = heatTemplate.getHeatTemplate();
1273 template = template.replaceAll("\r\n", "\n");
1275 // Have the tenant. Now deploy the stack itself
1276 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1277 // because we already checked for those.
1278 long createStackStarttime = System.currentTimeMillis();
1280 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1281 // heatTemplate.getTimeoutMinutes());
1282 if (backout == null) {
1286 LOGGER.debug("heat is not null!!");
1288 heatStack = heat.createStack(cloudSiteId,
1294 heatTemplate.getTimeoutMinutes(),
1295 newEnvironmentString,
1296 nestedTemplatesChecked,
1298 backout.booleanValue());
1300 .recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
1301 "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1302 } catch (MsoException me) {
1303 me.addContext("CreateVFModule");
1304 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1305 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1306 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1307 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1308 MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1310 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1312 throw new VnfException(me);
1313 } catch (NullPointerException npe) {
1314 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1315 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1316 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1317 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1318 MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1320 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1322 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1323 //npe.addContext ("CreateVNF");
1324 throw new VnfException("NullPointerException during heat.createStack");
1325 } catch (Exception e) {
1326 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1327 MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack",
1328 "OpenStack", "CreateStack", vfModuleName);
1329 LOGGER.debug("unhandled exception at heat.createStack", e);
1331 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1332 "Exception while creating stack with OpenStack");
1333 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1335 } catch (Exception e) {
1336 LOGGER.debug("unhandled exception in create VF", e);
1337 throw new VnfException("Exception during create VF " + e.getMessage());
1340 // Make sure DB session is closed
1342 // Reach this point if createStack is successful.
1343 // Populate remaining rollback info and response parameters.
1344 vfRollback.setVnfId(heatStack.getCanonicalName());
1345 vfRollback.setVnfCreated(true);
1347 vnfId.value = heatStack.getCanonicalName();
1348 outputs.value = copyStringOutputs(heatStack.getOutputs());
1349 rollback.value = vfRollback;
1351 LOGGER.debug("VF Module " + vfModuleName + " successfully created");
1352 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1356 public void deleteVfModule(String cloudSiteId,
1359 MsoRequest msoRequest,
1360 Holder<Map<String, String>> outputs) throws VnfException {
1361 MsoLogger.setLogContext(msoRequest);
1362 MsoLogger.setServiceName("DeleteVf");
1363 LOGGER.debug("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1364 // Will capture execution time for metrics
1365 long startTime = System.currentTimeMillis();
1367 // 1702 capture the output parameters on a delete
1368 // so we'll need to query first
1369 Map<String, Object> stackOutputs = null;
1371 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1372 } catch (MsoException me) {
1373 // Failed to query the Stack due to an openstack exception.
1374 // Convert to a generic VnfException
1375 me.addContext("DeleteVFModule");
1376 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1377 LOGGER.recordMetricEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1378 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1379 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1380 throw new VnfException(me);
1382 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1383 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1385 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1386 // The possible outcomes of deleteStack are a StackInfo object with status
1387 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1389 long subStartTime = System.currentTimeMillis();
1391 heat.deleteStack(tenantId, cloudSiteId, vnfName, true);
1392 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1393 } catch (MsoException me) {
1394 me.addContext("DeleteVNF");
1395 // Failed to query the Stack due to an openstack exception.
1396 // Convert to a generic VnfException
1397 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1398 LOGGER.recordMetricEvent(subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1399 LOGGER.error(MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1400 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1401 throw new VnfException(me);
1404 // On success, nothing is returned.
1405 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1409 public void updateVfModule(String cloudSiteId,
1415 String volumeGroupHeatStackId,
1416 String baseVfHeatStackId,
1417 String vfModuleStackId,
1418 String modelCustomizationUuid,
1419 Map<String, String> inputs,
1420 MsoRequest msoRequest,
1421 Holder<Map<String, String>> outputs,
1422 Holder<VnfRollback> rollback) throws VnfException {
1423 String vfModuleName = vnfName;
1424 String vfModuleType = vnfType;
1425 String methodName = "updateVfModule";
1426 MsoLogger.setLogContext(msoRequest.getRequestId(), msoRequest.getServiceInstanceId());
1427 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1428 MsoLogger.setServiceName(serviceName);
1430 String strInit = "updateVfModule: cloudSiteId=" + cloudSiteId +
1431 ",tenantId=" + tenantId +
1432 ",vnfType=" + vnfType +
1433 ",vnfVersion=" + vnfVersion +
1434 ",vnfName=" + vnfName +
1435 ",requestType=" + requestType +
1436 ",volumeGroupHeatStackId=" + volumeGroupHeatStackId +
1437 ",baseVfHeatStackId=" + baseVfHeatStackId +
1438 ",vfModuleStackId=" + vfModuleStackId +
1439 ",modelCustomizationUuid=" + modelCustomizationUuid;
1440 LOGGER.debug(strInit);
1442 String mcu = modelCustomizationUuid;
1443 boolean useMCUuid = false;
1444 if (mcu != null && !mcu.isEmpty()) {
1445 if (mcu.equalsIgnoreCase("null")) {
1446 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1450 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1455 String requestTypeString = "";
1456 if (requestType != null && !"".equals(requestType)) {
1457 requestTypeString = requestType;
1459 String nestedStackId = null;
1460 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
1461 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1462 nestedStackId = volumeGroupHeatStackId;
1465 String nestedBaseStackId = null;
1466 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
1467 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
1468 nestedBaseStackId = baseVfHeatStackId;
1472 if (inputs == null) {
1473 // Create an empty set of inputs
1474 inputs = new HashMap<>();
1475 LOGGER.debug("inputs == null - setting to empty");
1477 this.sendMapToDebug(inputs);
1479 boolean isBaseRequest = false;
1480 boolean isVolumeRequest = false;
1481 if (requestTypeString.startsWith("VOLUME")) {
1482 isVolumeRequest = true;
1484 if (vfModuleName == null || "".equals(vfModuleName.trim())) {
1485 if (vfModuleStackId != null) {
1486 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1490 LOGGER.debug("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1491 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1493 // Will capture execution time for metrics
1494 long startTime = System.currentTimeMillis();
1496 // Build a default rollback object (no actions performed)
1497 VnfRollback vfRollback = new VnfRollback();
1498 vfRollback.setCloudSiteId(cloudSiteId);
1499 vfRollback.setTenantId(tenantId);
1500 vfRollback.setMsoRequest(msoRequest);
1501 vfRollback.setRequestType(requestTypeString);
1502 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1503 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1504 vfRollback.setIsBase(isBaseRequest);
1505 vfRollback.setVfModuleStackId(vfModuleStackId);
1506 vfRollback.setModelCustomizationUuid(mcu);
1508 // First, look up to see if the VNF already exists.
1509 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate(MSO_PROP_VNF_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
1511 StackInfo heatStack = null;
1512 long queryStackStarttime = System.currentTimeMillis();
1513 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1515 heatStack = heat.queryStack(cloudSiteId, tenantId, vfModuleName);
1516 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1517 } catch (MsoException me) {
1518 // Failed to query the Stack due to an openstack exception.
1519 // Convert to a generic VnfException
1520 me.addContext("UpdateVFModule");
1521 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1522 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1523 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1524 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1525 throw new VnfException(me);
1528 //TODO - do we need to check for the other status possibilities?
1529 if (heatStack == null || heatStack.getStatus() == HeatStatus.NOTFOUND) {
1531 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1532 LOGGER.error(MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1533 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1534 throw new VnfNotFound(cloudSiteId, tenantId, vfModuleName);
1536 LOGGER.debug("Found Existing stack, status=" + heatStack.getStatus());
1537 // Populate the outputs from the existing stack.
1538 outputs.value = copyStringOutputs(heatStack.getOutputs());
1539 rollback.value = vfRollback; // Default rollback - no updates performed
1542 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1543 StackInfo nestedHeatStack = null;
1544 long queryStackStarttime2 = System.currentTimeMillis();
1545 Map<String, Object> nestedVolumeOutputs = null;
1546 if (nestedStackId != null) {
1548 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1549 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1550 LOGGER.recordMetricEvent(queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1551 } catch (MsoException me) {
1552 // Failed to query the Stack due to an openstack exception.
1553 // Convert to a generic VnfException
1554 me.addContext("UpdateVFModule");
1555 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1556 LOGGER.recordMetricEvent(queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1557 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1558 LOGGER.debug("ERROR trying to query nested stack= " + error);
1559 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1560 throw new VnfException(me);
1562 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1563 MsoLogger.setServiceName(serviceName);
1564 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
1565 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1566 LOGGER.debug(error);
1567 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1568 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1570 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1571 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1572 //this.sendMapToDebug(inputs);
1573 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1575 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1576 //this.sendMapToDebug(inputs);
1579 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1580 StackInfo nestedBaseHeatStack = null;
1581 Map<String, Object> baseStackOutputs = null;
1582 if (nestedBaseStackId != null) {
1583 long queryStackStarttime3 = System.currentTimeMillis();
1585 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1586 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1587 LOGGER.recordMetricEvent(queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1588 } catch (MsoException me) {
1589 // Failed to query the Stack due to an openstack exception.
1590 // Convert to a generic VnfException
1591 me.addContext("UpdateVfModule");
1592 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1593 LOGGER.recordMetricEvent(queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1594 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1595 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1596 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1597 throw new VnfException(me);
1599 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1600 MsoLogger.setServiceName(serviceName);
1601 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR";
1602 LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1603 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1604 LOGGER.debug(error);
1605 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1607 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1608 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1609 //this.sendMapToDebug(inputs);
1610 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1612 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1613 //this.sendMapToDebug(inputs);
1617 // Ready to deploy the new VNF
1619 // Get a handle to the Catalog Database
1621 // Make sure DB session is closed
1622 try (CatalogDatabase db = this.getCatalogDatabase()) {
1623 // Retrieve the VF definition
1624 VnfResource vnfResource = null;
1626 VfModuleCustomization vfmc = null;
1628 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1629 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1630 vf = vfmc != null ? vfmc.getVfModule() : null;
1632 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1635 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1638 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1639 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "",
1640 MsoLogger.ErrorCode.DataError, error);
1641 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1642 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1644 LOGGER.debug("Got VF module definition from Catalog: " + vf.toString());
1646 isBaseRequest = true;
1647 LOGGER.debug("This a BASE update request");
1649 LOGGER.debug("This is *not* a BASE VF update request");
1650 if (!isVolumeRequest && nestedBaseStackId == null) {
1651 LOGGER.debug("This is unexpected - no nestedBaseStackId with this non-base request");
1655 //1607 - Add version check
1656 // First - see if it's in the VnfResource record
1657 // if we have a vf Module - then we have to query to get the VnfResource record.
1658 if (vf.getVnfResourceModelUUId() != null) {
1659 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1660 //vnfResource = db.getVnfResourceById(vnfResourceId);
1661 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1662 if (vnfResource == null) {
1664 .debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1667 String minVersionVnf = null;
1668 String maxVersionVnf = null;
1669 if (vnfResource != null) {
1671 minVersionVnf = vnfResource.getAicVersionMin();
1672 maxVersionVnf = vnfResource.getAicVersionMax();
1673 } catch (Exception e) {
1674 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
1675 minVersionVnf = null;
1676 maxVersionVnf = null;
1678 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1679 minVersionVnf = null;
1681 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1682 maxVersionVnf = null;
1685 if (minVersionVnf != null && maxVersionVnf != null) {
1686 MavenLikeVersioning aicV = new MavenLikeVersioning();
1687 //String aicVersion = "";
1688 if (this.cloudConfig == null) {
1689 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1692 if (this.cloudConfig != null) {
1693 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1694 if (cloudSiteOpt.isPresent()) {
1695 aicV.setVersion(cloudSiteOpt.get().getAic_version());
1696 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1697 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV
1698 .isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1699 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1700 + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteOpt.get().getId()
1701 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version());
1705 "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1706 + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get()
1707 .getId() + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
1708 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1709 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1710 LOGGER.debug(error);
1711 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1713 } // let this error out downstream to avoid introducing uncertainty at this stage
1715 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1719 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1721 // End Version check 1607
1723 String heatTemplateArtifactUuid = null;
1724 String heatEnvironmentArtifactUuid = null;
1726 HeatTemplate heatTemplate = null;
1727 if (isVolumeRequest) {
1728 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1729 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1731 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1732 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1734 if (heatTemplateArtifactUuid == null) {
1736 "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType="
1737 + requestTypeString;
1738 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "",
1739 MsoLogger.ErrorCode.DataError, error);
1740 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1742 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1743 MsoAlarmLogger.CRITICAL, error);
1744 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1746 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1749 if (heatTemplate == null) {
1750 String error = "Update VNF: undefined Heat Template. VF="
1751 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1752 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1754 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1755 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1757 // Alarm on this error, configuration must be fixed
1758 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1759 MsoAlarmLogger.CRITICAL, error);
1761 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1764 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1766 // Add check for any Environment variable
1767 HeatEnvironment heatEnvironment = null;
1768 String heatEnvironmentString = null;
1770 if (heatEnvironmentArtifactUuid != null) {
1771 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1772 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1773 if (heatEnvironment == null) {
1775 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1776 + ", Environment ID="
1777 + heatEnvironmentArtifactUuid;
1778 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1779 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError,
1781 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1783 // Alarm on this error, configuration must be fixed
1784 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1786 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1788 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1789 heatEnvironmentString = heatEnvironment
1790 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1791 LOGGER.debug("After parsing: " + heatEnvironmentString);
1794 LOGGER.debug("no environment parameter for this VFModuleType " + vfModuleType);
1797 LOGGER.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1798 + heatTemplate.getArtifactUuid());
1799 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1800 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1801 if (nestedTemplates != null) {
1802 // for debugging print them out
1803 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1804 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1805 String providerResourceFile = entry.getKey();
1806 Object value = entry.getValue();
1807 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1808 String childTemplateBody = (String) value;
1809 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1810 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1813 LOGGER.debug("No nested templates found - nothing to do here");
1814 nestedTemplatesChecked = null;
1817 // Also add the files: for any get_files associated with this VfModule
1818 // *if* there are any
1819 LOGGER.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1820 + vf.getModelUUID());
1822 Map<String, HeatFiles> heatFiles = null;
1823 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1824 Map<String, Object> heatFilesObjects = new HashMap<>();
1826 // Add ability to turn on adding get_files with volume requests (by property).
1827 boolean addGetFilesOnVolumeReq = false;
1829 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1830 .getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1831 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1832 addGetFilesOnVolumeReq = true;
1833 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1835 } catch (Exception e) {
1836 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1837 + " - default to false", e);
1839 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1841 "In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1842 + vf.getModelUUID());
1844 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1845 if (heatFiles != null) {
1846 // add these to stack - to be done in createStack
1847 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1848 // this will match the nested templates format
1849 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1851 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1852 String heatFileName = entry.getKey();
1853 HeatFiles value = entry.getValue();
1854 if (heatFileName.startsWith("_ERROR|")) {
1855 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1856 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|") + 1);
1857 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType
1858 + " at HEAT_FILES index=" + heatFileId;
1859 LOGGER.debug(error);
1861 .error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId,
1862 vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1863 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1864 MsoLogger.ResponseCode.DataNotFound, error);
1865 // Alarm on this error, configuration must be fixed
1866 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1867 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1869 String heatFileBody = value.getFileBody();
1870 LOGGER.debug(heatFileName + " -> " + heatFileBody);
1871 heatFilesObjects.put(heatFileName, heatFileBody);
1874 LOGGER.debug("No heat files found -nothing to do here");
1875 heatFilesObjects = null;
1879 // Check that required parameters have been supplied
1880 StringBuilder missingParams = null;
1881 List<String> paramList = new ArrayList<>();
1883 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1884 // supplied an alias. Only check if we don't find it initially.
1885 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1886 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1888 // boolean haveEnvironmentParameters = false;
1889 boolean checkRequiredParameters = true;
1891 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1892 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1893 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1894 checkRequiredParameters = false;
1895 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1896 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1898 } catch (Exception e) {
1899 // No problem - default is true
1900 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1902 // 1604 - Add enhanced environment & parameter checking
1903 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1904 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1905 // Note this also removes any comments
1906 MsoHeatEnvironmentEntry mhee = null;
1907 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase().contains("parameters:")) {
1908 LOGGER.debug("Enhanced environment checking enabled - 1604");
1909 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1910 //LOGGER.debug("About to create MHEE with " + sb);
1911 mhee = new MsoHeatEnvironmentEntry(sb);
1912 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1913 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1914 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1916 if (!mhee.isValid()) {
1917 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1919 sb2.append("\nEnvironment:");
1922 LOGGER.debug(sb2.toString());
1924 LOGGER.debug("NO ENVIRONMENT for this entry");
1927 // New for 1607 - support params of json type
1928 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1929 boolean hasJson = false;
1931 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1932 LOGGER.debug("Parameter:'" + parm.getParamName()
1936 + parm.getParamAlias());
1938 String parameterType = parm.getParamType();
1939 if (parameterType == null || "".equals(parameterType.trim())) {
1940 parameterType = "String";
1942 JsonNode jsonNode = null;
1943 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1944 if (inputs.containsKey(parm.getParamName())) {
1946 String jsonString = null;
1948 jsonString = inputs.get(parm.getParamName());
1949 jsonNode = new ObjectMapper().readTree(jsonString);
1950 } catch (JsonParseException jpe) {
1951 //TODO - what to do here?
1952 //for now - send the error to debug, but just leave it as a String
1953 String errorMessage = jpe.getMessage();
1954 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1957 } catch (Exception e) {
1959 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1963 if (jsonNode != null) {
1964 jsonParams.put(parm.getParamName(), jsonNode);
1966 } else if (inputs.containsKey(parm.getParamAlias())) {
1968 String jsonString = null;
1970 jsonString = inputs.get(parm.getParamAlias());
1971 jsonNode = new ObjectMapper().readTree(jsonString);
1972 } catch (JsonParseException jpe) {
1973 //TODO - what to do here?
1974 //for now - send the error to debug, but just leave it as a String
1975 String errorMessage = jpe.getMessage();
1976 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1979 } catch (Exception e) {
1981 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1985 if (jsonNode != null) {
1986 // Notice here - we add it to the jsonParams hashMap with the actual name -
1987 // then manipulate the inputs so when we check for aliases below - it will not
1989 jsonParams.put(parm.getParamName(), jsonNode);
1990 inputs.remove(parm.getParamAlias());
1991 inputs.put(parm.getParamName(), jsonString);
1993 } //TODO add a check for the parameter in the env file
1996 if (parm.isRequired() && (inputs == null || !inputs.containsKey(parm.getParamName()))) {
1997 if (inputs.containsKey(parm.getParamAlias())) {
1998 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1999 String realParamName = parm.getParamName();
2000 String alias = parm.getParamAlias();
2001 String value = inputs.get(alias);
2002 LOGGER.debug("*Found an Alias: paramName=" + realParamName
2007 inputs.remove(alias);
2008 inputs.put(realParamName, value);
2009 LOGGER.debug(alias + " entry removed from inputs, added back using " + realParamName);
2011 // enhanced - check if it's in the Environment (note: that method
2012 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2014 LOGGER.debug("Required parameter " + parm.getParamName()
2015 + " appears to be in environment - do not count as missing");
2017 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
2018 if (missingParams == null) {
2019 missingParams = new StringBuilder(parm.getParamName());
2021 missingParams.append("," + parm.getParamName());
2025 paramList.add(parm.getParamName());
2027 if (missingParams != null) {
2028 // Problem - missing one or more required parameters
2029 if (checkRequiredParameters) {
2030 String error = "Update VNF: Missing Required inputs: " + missingParams;
2031 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
2032 MsoLogger.ErrorCode.DataError, error);
2033 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
2035 throw new VnfException(error, MsoExceptionCategory.USERDATA);
2037 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
2040 LOGGER.debug("No missing parameters found - ok to proceed");
2043 // Just submit the envt entry as received from the database
2044 String newEnvironmentString = null;
2046 newEnvironmentString = mhee.getRawEntry().toString();
2049 // Remove any extraneous parameters (don't throw an error)
2050 if (inputs != null) {
2051 List<String> extraParams = new ArrayList<>();
2052 extraParams.addAll(inputs.keySet());
2053 // This is not a valid parameter for this template
2054 extraParams.removeAll(paramList);
2055 if (!extraParams.isEmpty()) {
2056 LOGGER.warn(MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "",
2057 MsoLogger.ErrorCode.DataError, "Extra params");
2058 inputs.keySet().removeAll(extraParams);
2061 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2062 Map<String, Object> inputsTwo = null;
2063 if (hasJson && jsonParams.size() > 0) {
2064 inputsTwo = new HashMap<>();
2065 for (Map.Entry<String, String> entry : inputs.entrySet()) {
2066 String keyParamName = entry.getKey();
2067 String value = entry.getValue();
2068 if (jsonParams.containsKey(keyParamName)) {
2069 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2071 inputsTwo.put(keyParamName, value);
2076 // "Fix" the template if it has CR/LF (getting this from Oracle)
2077 String template = heatTemplate.getHeatTemplate();
2078 template = template.replaceAll("\r\n", "\n");
2080 // Have the tenant. Now deploy the stack itself
2081 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2082 // because we already checked for those.
2083 long updateStackStarttime = System.currentTimeMillis();
2086 heatStack = heatU.updateStack(cloudSiteId,
2090 copyStringInputs(inputs),
2092 heatTemplate.getTimeoutMinutes(),
2093 newEnvironmentString,
2094 //heatEnvironmentString,
2095 nestedTemplatesChecked,
2097 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2098 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2099 "UpdateStack", null);
2101 heatStack = heatU.updateStack(cloudSiteId,
2107 heatTemplate.getTimeoutMinutes(),
2108 newEnvironmentString,
2109 //heatEnvironmentString,
2110 nestedTemplatesChecked,
2112 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2113 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2114 "UpdateStack", null);
2116 } catch (MsoException me) {
2117 me.addContext("UpdateVFModule");
2118 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2119 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.ERROR,
2120 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2121 LOGGER.error(MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
2122 MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2124 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
2126 throw new VnfException(me);
2129 // Make sure DB session is closed
2131 // Reach this point if updateStack is successful.
2132 // Populate remaining rollback info and response parameters.
2133 vfRollback.setVnfId(heatStack.getCanonicalName());
2134 vfRollback.setVnfCreated(true);
2136 outputs.value = copyStringOutputs(heatStack.getOutputs());
2137 rollback.value = vfRollback;
2138 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2141 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2142 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2143 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2144 if (vfModuleStackId == null)
2146 int index = vfModuleStackId.lastIndexOf('/');
2149 String vfModuleName = null;
2151 vfModuleName = vfModuleStackId.substring(0, index);
2152 } catch (Exception e) {
2153 LOGGER.debug("Exception", e);
2154 vfModuleName = null;
2156 return vfModuleName;
2159 private CatalogDatabase getCatalogDatabase(){
2160 return CatalogDatabase.getInstance();
2163 private Map<String, Object> updateFlavorsFromOof(String heatEnvironmentString, Map<String, String> inputs) {
2164 Map<String, Object> returnMap = new HashMap<>();
2165 for (Map.Entry<String, String> input : inputs.entrySet()){
2166 if (heatEnvironmentString.contains("label_" + input.getKey())){
2167 heatEnvironmentString = heatEnvironmentString.replace("label_" + input.getKey(),
2169 inputs.remove("label_" + input.getKey());
2172 returnMap.put("heatEnvironmentString", heatEnvironmentString);
2173 returnMap.put("inputs", inputs);