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;
24 import java.util.Optional;
25 import org.codehaus.jackson.JsonNode;
26 import org.codehaus.jackson.JsonParseException;
27 import org.codehaus.jackson.map.ObjectMapper;
28 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
29 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
30 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
31 import org.openecomp.mso.cloud.CloudConfig;
32 import org.openecomp.mso.cloud.CloudConfigFactory;
33 import org.openecomp.mso.cloud.CloudSite;
34 import org.openecomp.mso.db.catalog.CatalogDatabase;
35 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
36 import org.openecomp.mso.db.catalog.beans.HeatFiles;
37 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
38 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
39 import org.openecomp.mso.db.catalog.beans.VfModule;
40 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
41 import org.openecomp.mso.db.catalog.beans.VnfResource;
42 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
43 import org.openecomp.mso.entity.MsoRequest;
44 import org.openecomp.mso.logger.MessageEnum;
45 import org.openecomp.mso.logger.MsoAlarmLogger;
46 import org.openecomp.mso.logger.MsoLogger;
47 import org.openecomp.mso.openstack.beans.HeatStatus;
48 import org.openecomp.mso.openstack.beans.StackInfo;
49 import org.openecomp.mso.openstack.beans.VnfRollback;
50 import org.openecomp.mso.openstack.beans.VnfStatus;
51 import org.openecomp.mso.openstack.exceptions.MsoException;
52 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
53 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
54 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
55 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
56 import org.openecomp.mso.properties.MsoPropertiesFactory;
58 import javax.jws.WebService;
59 import javax.xml.ws.Holder;
61 import java.io.IOException;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.HashMap;
65 import java.util.List;
67 import java.util.concurrent.TimeUnit;
69 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
70 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
72 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
73 protected CloudConfig cloudConfig = null;
75 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
77 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
78 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
79 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
80 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
81 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
82 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
83 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
84 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
87 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
88 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
90 public MsoVnfAdapterImpl() {
91 // empty implementation
95 * This constructor MUST be used if this class is called with the new operator.
96 * @param msoPropFactory
98 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
99 this.msoPropertiesFactory = msoPropFactory;
100 this.cloudConfigFactory = cloudConfigFact;
104 * Health Check web method. Does nothing but return to show the adapter is deployed.
107 public void healthCheck () {
108 LOGGER.debug ("Health check call in VNF Adapter");
112 * This is the "Create VNF" web service implementation.
113 * It will create a new VNF of the requested type in the specified cloud
114 * and tenant. The tenant must exist before this service is called.
116 * If a VNF with the same name already exists, this can be considered a
117 * success or failure, depending on the value of the 'failIfExists' parameter.
119 * All VNF types will be defined in the MSO catalog. The caller must request
120 * one of these pre-defined types or an error will be returned. Within the
121 * catalog, each VNF type references (among other things) a Heat template
122 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
125 * Depending on the Heat template, a variable set of input parameters will
126 * be defined, some of which are required. The caller is responsible to
127 * pass the necessary input data for the VNF or an error will be thrown.
129 * The method returns the vnfId (the canonical name), a Map of VNF output
130 * attributes, and a VnfRollback object. This last object can be passed
131 * as-is to the rollbackVnf operation to undo everything that was created
132 * for the VNF. This is useful if a VNF is successfully created but the
133 * orchestrator fails on a subsequent operation.
135 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
136 * @param tenantId Openstack tenant identifier
137 * @param vnfType VNF type key, should match a VNF definition in catalog DB
138 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
139 * @param vnfName Name to be assigned to the new VNF
140 * @param inputs Map of key=value inputs for VNF stack creation
141 * @param failIfExists Flag whether already existing VNF should be considered
142 * a success or failure
143 * @param msoRequest Request tracking information for logs
144 * @param vnfId Holder for output VNF Openstack ID
145 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
146 * @param rollback Holder for returning VnfRollback object
149 public void createVnf (String cloudSiteId,
155 String volumeGroupHeatStackId,
156 Map <String, String> inputs,
157 Boolean failIfExists,
159 MsoRequest msoRequest,
160 Holder <String> vnfId,
161 Holder <Map <String, String>> outputs,
162 Holder <VnfRollback> rollback) throws VnfException {
163 // Create a hook here to catch shortcut createVf requests:
164 if (requestType != null) {
165 if (requestType.startsWith("VFMOD")) {
166 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
167 String newRequestType = requestType.substring(5);
168 String vfVolGroupHeatStackId = "";
169 String vfBaseHeatStackId = "";
171 if (volumeGroupHeatStackId != null) {
172 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
173 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
175 } catch (Exception e) {
176 // might be ok - both are just blank
177 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
179 this.createVfModule(cloudSiteId,
185 vfVolGroupHeatStackId,
198 // createVf will know if the requestType starts with "X" that it's the "old" way
199 StringBuilder newRequestTypeSb = new StringBuilder("X");
200 String vfVolGroupHeatStackId = "";
201 String vfBaseHeatStackId = "";
202 if (requestType != null) {
203 newRequestTypeSb.append(requestType);
205 this.createVfModule(cloudSiteId,
210 newRequestTypeSb.toString(),
211 vfVolGroupHeatStackId,
221 // End createVf shortcut
225 public void updateVnf (String cloudSiteId,
231 String volumeGroupHeatStackId,
232 Map <String, String> inputs,
233 MsoRequest msoRequest,
234 Holder <Map <String, String>> outputs,
235 Holder <VnfRollback> rollback) throws VnfException {
236 // As of 1707 - this method should no longer be called
237 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
238 MsoLogger.setServiceName ("UpdateVnf");
239 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
243 * This is the "Query VNF" web service implementation.
244 * It will look up a VNF by name or ID in the specified cloud and tenant.
246 * The method returns an indicator that the VNF exists, its Openstack internal
247 * ID, its status, and the set of outputs (from when the stack was created).
249 * @param cloudSiteId CLLI code of the cloud site in which to query
250 * @param tenantId Openstack tenant identifier
251 * @param vnfName VNF Name or Openstack ID
252 * @param msoRequest Request tracking information for logs
253 * @param vnfExists Flag reporting the result of the query
254 * @param vnfId Holder for output VNF Openstack ID
255 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
258 public void queryVnf (String cloudSiteId,
261 MsoRequest msoRequest,
262 Holder <Boolean> vnfExists,
263 Holder <String> vnfId,
264 Holder <VnfStatus> status,
265 Holder <Map <String, String>> outputs) throws VnfException {
266 MsoLogger.setLogContext (msoRequest);
267 MsoLogger.setServiceName ("QueryVnf");
268 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
270 // Will capture execution time for metrics
271 long startTime = System.currentTimeMillis ();
273 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
275 StackInfo heatStack = null;
276 long subStartTime = System.currentTimeMillis ();
278 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
279 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
280 } catch (MsoException me) {
281 me.addContext ("QueryVNF");
282 // Failed to query the Stack due to an openstack exception.
283 // Convert to a generic VnfException
284 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
285 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
286 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
287 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
288 throw new VnfException (me);
291 // Populate the outputs based on the returned Stack information
293 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
295 vnfExists.value = Boolean.FALSE;
296 status.value = VnfStatus.NOTFOUND;
298 outputs.value = new HashMap<>(); // Return as an empty map
300 LOGGER.debug ("VNF " + vnfName + " not found");
302 vnfExists.value = Boolean.TRUE;
303 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
304 vnfId.value = heatStack.getCanonicalName ();
305 outputs.value = copyStringOutputs (heatStack.getOutputs ());
307 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
309 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
313 * This is the "Delete VNF" web service implementation.
314 * It will delete a VNF by name or ID in the specified cloud and tenant.
316 * The method has no outputs.
318 * @param cloudSiteId CLLI code of the cloud site in which to delete
319 * @param tenantId Openstack tenant identifier
320 * @param vnfName VNF Name or Openstack ID
321 * @param msoRequest Request tracking information for logs
324 public void deleteVnf (String cloudSiteId,
327 MsoRequest msoRequest) throws VnfException {
328 MsoLogger.setLogContext (msoRequest);
329 MsoLogger.setServiceName ("DeleteVnf");
330 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
331 // Will capture execution time for metrics
332 long startTime = System.currentTimeMillis ();
334 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
336 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
337 // The possible outcomes of deleteStack are a StackInfo object with status
338 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
340 long subStartTime = System.currentTimeMillis ();
342 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
343 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
344 } catch (MsoException me) {
345 me.addContext ("DeleteVNF");
346 // Failed to query the Stack due to an openstack exception.
347 // Convert to a generic VnfException
348 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
349 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
350 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
351 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
352 throw new VnfException (me);
355 // On success, nothing is returned.
356 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
360 * This web service endpoint will rollback a previous Create VNF operation.
361 * A rollback object is returned to the client in a successful creation
362 * response. The client can pass that object as-is back to the rollbackVnf
363 * operation to undo the creation.
366 public void rollbackVnf (VnfRollback rollback) throws VnfException {
367 long startTime = System.currentTimeMillis ();
368 MsoLogger.setServiceName ("RollbackVnf");
369 // rollback may be null (e.g. if stack already existed when Create was called)
370 if (rollback == null) {
371 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
372 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
376 // Get the elements of the VnfRollback object for easier access
377 String cloudSiteId = rollback.getCloudSiteId ();
378 String tenantId = rollback.getTenantId ();
379 String vnfId = rollback.getVnfId ();
381 MsoLogger.setLogContext (rollback.getMsoRequest());
383 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
385 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
387 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
388 // The possible outcomes of deleteStack are a StackInfo object with status
389 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
391 long subStartTime = System.currentTimeMillis ();
393 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
394 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
395 } catch (MsoException me) {
396 // Failed to rollback the Stack due to an openstack exception.
397 // Convert to a generic VnfException
398 me.addContext ("RollbackVNF");
399 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
400 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
401 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
402 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
403 throw new VnfException (me);
405 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
408 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
409 switch (stackStatus) {
411 return VnfStatus.ACTIVE;
413 return VnfStatus.ACTIVE;
415 return VnfStatus.FAILED;
417 return VnfStatus.UNKNOWN;
421 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
422 Map <String, String> stringOutputs = new HashMap <> ();
423 for (Map.Entry<String,Object> entry : stackOutputs.entrySet ()) {
424 String key = entry.getKey();
425 Object value = entry.getValue();
426 if (value instanceof String) {
427 stringOutputs.put (key, (String) value);
428 } else if (value instanceof Integer) {
430 String str = "" + value;
431 stringOutputs.put(key, str);
432 } catch (Exception e) {
433 LOGGER.debug("Unable to add " + key + " to outputs",e);
435 } else if (value instanceof JsonNode) {
437 String str = this.convertNode((JsonNode) value);
438 stringOutputs.put(key, str);
439 } catch (Exception e) {
440 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode",e);
442 } else if (value instanceof java.util.LinkedHashMap) {
444 String str = JSON_MAPPER.writeValueAsString(value);
445 stringOutputs.put(key, str);
446 } catch (Exception e) {
447 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap",e);
451 String str = value.toString();
452 stringOutputs.put(key, str);
453 } catch (Exception e) {
454 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),e);
458 return stringOutputs;
461 private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
462 return new HashMap <> (stringInputs);
465 private boolean callHeatbridge(String heatStackId) {
466 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
467 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
468 long waitTimeMs = 10000L;
470 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
471 String[] envp = null;
472 File dir = new File(executionDir);
473 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
474 Runtime r = Runtime.getRuntime();
475 Process p = r.exec(cmdarray, envp, dir);
476 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
478 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
479 return wait && p.exitValue()==0;
480 } catch (IOException e) {
481 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
483 } catch (InterruptedException e) {
484 LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e);
486 } catch (RuntimeException e) {
487 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e);
492 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
494 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
495 if (inputs == null) {
498 else if (inputs.size() < 1) {
499 sb.append("\tEMPTY");
501 for (Map.Entry<String,Object> entry : inputs.entrySet()) {
503 String str = entry.getKey();
504 Object value = entry.getValue();
506 outputString = value.toString();
507 } catch (Exception e) {
508 LOGGER.debug("Exception :",e);
509 outputString = "Unable to call toString() on the value for " + str;
511 sb.append("\t\nitem ").append(i++).append(": '").append(str).append("'='").append(outputString)
515 LOGGER.debug(sb.toString());
518 private void sendMapToDebug(Map<String, String> inputs) {
520 StringBuilder sb = new StringBuilder("inputs:");
521 if (inputs == null) {
524 else if (inputs.size() < 1) {
525 sb.append("\tEMPTY");
527 for (String str : inputs.keySet()) {
528 sb.append("\titem ").append(i++).append(": ").append(str).append("=").append(inputs.get(str));
531 LOGGER.debug(sb.toString());
534 private String convertNode(final JsonNode node) {
536 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
537 final String json = JSON_MAPPER.writeValueAsString(obj);
539 } catch (Exception e) {
540 LOGGER.debug("Error converting json to string " + e.getMessage(),e);
542 return "[Error converting json to string]";
545 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
546 if (objectMap == null) {
549 Map<String, String> stringMap = new HashMap<>();
550 for (String key : objectMap.keySet()) {
551 if (!stringMap.containsKey(key)) {
552 Object obj = objectMap.get(key);
553 if (obj instanceof String) {
554 stringMap.put(key, (String) objectMap.get(key));
555 } else if (obj instanceof JsonNode ){
556 // This is a bit of mess - but I think it's the least impacting
557 // let's convert it BACK to a string - then it will get converted back later
559 String str = this.convertNode((JsonNode) obj);
560 stringMap.put(key, str);
561 } catch (Exception e) {
562 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
563 //okay in this instance - only string values (fqdn) are expected to be needed
565 } else if (obj instanceof java.util.LinkedHashMap) {
566 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
568 String str = JSON_MAPPER.writeValueAsString(obj);
569 stringMap.put(key, str);
570 } catch (Exception e) {
571 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
573 } else if (obj instanceof Integer) {
575 String str = "" + obj;
576 stringMap.put(key, str);
577 } catch (Exception e) {
578 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
582 String str = obj.toString();
583 stringMap.put(key, str);
584 } catch (Exception e) {
585 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
595 public void createVfModule(String cloudSiteId,
601 String volumeGroupHeatStackId,
602 String baseVfHeatStackId,
603 String modelCustomizationUuid,
604 Map <String, String> inputs,
605 Boolean failIfExists,
607 MsoRequest msoRequest,
608 Holder <String> vnfId,
609 Holder <Map <String, String>> outputs,
610 Holder <VnfRollback> rollback) throws VnfException {
611 String vfModuleName = vnfName;
612 String vfModuleType = vnfType;
613 String vfVersion = vnfVersion;
614 String mcu = modelCustomizationUuid;
615 boolean useMCUuid = false;
616 if (mcu != null && !mcu.isEmpty()) {
617 if ("null".equalsIgnoreCase(mcu)) {
618 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
622 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
626 MsoLogger.setLogContext (msoRequest);
627 MsoLogger.setServiceName ("CreateVfModule");
628 String requestTypeString = "";
629 if (requestType != null && !"".equals(requestType)) {
630 requestTypeString = requestType;
632 String nestedStackId = null;
633 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
634 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
635 nestedStackId = volumeGroupHeatStackId;
638 String nestedBaseStackId = null;
639 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
640 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
641 nestedBaseStackId = baseVfHeatStackId;
645 if (inputs == null) {
646 // Create an empty set of inputs
647 inputs = new HashMap<>();
648 LOGGER.debug("inputs == null - setting to empty");
650 this.sendMapToDebug(inputs);
652 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
653 boolean oldWay = false;
654 if (requestTypeString.startsWith("X")) {
656 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
657 requestTypeString = requestTypeString.substring(1);
660 // 1607 - let's parse out the request type we're being sent
661 boolean isBaseRequest = false;
662 boolean isVolumeRequest = false;
663 if (requestTypeString.startsWith("VOLUME")) {
664 isVolumeRequest = true;
667 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
668 // Will capture execution time for metrics
669 long startTime = System.currentTimeMillis ();
671 // Build a default rollback object (no actions performed)
672 VnfRollback vfRollback = new VnfRollback();
673 vfRollback.setCloudSiteId(cloudSiteId);
674 vfRollback.setTenantId(tenantId);
675 vfRollback.setMsoRequest(msoRequest);
676 vfRollback.setRequestType(requestTypeString);
677 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
678 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
679 vfRollback.setIsBase(isBaseRequest);
680 vfRollback.setModelCustomizationUuid(mcu);
682 // Put data into A&AI through Heatstack
683 callHeatbridge(baseVfHeatStackId);
685 // First, look up to see if the VF already exists.
686 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
688 StackInfo heatStack = null;
689 long subStartTime1 = System.currentTimeMillis ();
691 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
692 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
693 } catch (MsoException me) {
694 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
695 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
696 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
697 // Failed to query the Stack due to an openstack exception.
698 // Convert to a generic VnfException
699 me.addContext ("CreateVFModule");
700 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
701 throw new VnfException (me);
703 // New with 1607 - more precise handling/messaging if the stack already exists
704 if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
705 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
706 HeatStatus status = heatStack.getStatus();
707 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
708 // fail - it's in progress - return meaningful error
709 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.";
710 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
711 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
712 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
714 if (status == HeatStatus.FAILED) {
715 // fail - it exists and is in a FAILED state
716 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
717 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
718 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
719 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
721 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
722 // fail - it exists and is in a FAILED state
723 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
724 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");
725 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
726 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
728 if (status == HeatStatus.CREATED) {
730 if (failIfExists != null && failIfExists) {
731 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
732 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
733 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
734 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
736 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
737 // Populate the outputs from the existing stack.
738 vnfId.value = heatStack.getCanonicalName ();
739 outputs.value = copyStringOutputs (heatStack.getOutputs ());
740 rollback.value = vfRollback; // Default rollback - no updates performed
743 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
748 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
749 StackInfo nestedHeatStack = null;
750 long subStartTime2 = System.currentTimeMillis ();
751 Map<String, Object> nestedVolumeOutputs = null;
752 if (nestedStackId != null) {
754 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
755 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
756 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
757 } catch (MsoException me) {
758 // Failed to query the Stack due to an openstack exception.
759 // Convert to a generic VnfException
760 me.addContext ("CreateVFModule");
761 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
762 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
763 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
764 LOGGER.debug("ERROR trying to query nested stack= " + error);
765 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
766 throw new VnfException (me);
768 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
769 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
770 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
771 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
773 throw new VnfException (error, MsoExceptionCategory.USERDATA);
775 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
776 //this.sendMapToDebug(inputs);
777 nestedVolumeOutputs = nestedHeatStack.getOutputs();
778 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
780 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
781 //this.sendMapToDebug(inputs);
785 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
786 StackInfo nestedBaseHeatStack = null;
787 long subStartTime3 = System.currentTimeMillis ();
788 Map<String, Object> baseStackOutputs = null;
789 if (nestedBaseStackId != null) {
791 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
792 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
793 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
794 } catch (MsoException me) {
795 // Failed to query the Stack due to an openstack exception.
796 // Convert to a generic VnfException
797 me.addContext ("CreateVFModule");
798 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
799 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
800 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
801 LOGGER.debug("ERROR trying to query nested base stack= " + error);
802 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
803 throw new VnfException (me);
805 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
806 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
807 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");
808 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
810 throw new VnfException (error, MsoExceptionCategory.USERDATA);
812 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
813 //this.sendMapToDebug(inputs);
814 baseStackOutputs = nestedBaseHeatStack.getOutputs();
815 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
817 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
818 //this.sendMapToDebug(inputs);
822 // Ready to deploy the new VNF
824 try (CatalogDatabase db = CatalogDatabase.getInstance()) {
827 VnfResource vnfResource = null;
828 VfModuleCustomization vfmc = null;
829 LOGGER.debug("version: " + vfVersion);
831 // 1707 - db refactoring
832 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
833 vf = vfmc != null ? vfmc.getVfModule() : null;
834 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
835 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
837 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
839 "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
840 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
841 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "",
842 MsoLogger.ErrorCode.DataError,
843 "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
844 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
846 throw new VnfException(error, MsoExceptionCategory.USERDATA);
848 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
851 isBaseRequest = true;
852 LOGGER.debug("This is a BASE VF request!");
854 LOGGER.debug("This is *not* a BASE VF request!");
855 if (!isVolumeRequest && nestedBaseStackId == null) {
857 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
863 // Need to handle old and new schema methods - for a time. Try the new way first.
864 if (vfVersion != null && !vfVersion.isEmpty()) {
865 vf = db.getVfModuleType(vfModuleType, vfVersion);
867 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME");
868 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
870 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
874 vf = db.getVfModuleType(vfModuleType);
876 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
877 vf = db.getVfModuleModelName(vfModuleType);
879 LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
884 String error = "Create VF Module: Unable to determine specific VF Module Type: "
886 if (vfVersion != null && !vfVersion.isEmpty()) {
887 error += " with version = " + vfVersion;
889 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
890 "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type");
891 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
892 throw new VnfException(error, MsoExceptionCategory.USERDATA);
894 LOGGER.debug("Got VF module definition from Catalog: "
898 isBaseRequest = true;
899 LOGGER.debug("This is a BASE VF request!");
901 LOGGER.debug("This is *not* a BASE VF request!");
902 if (!isVolumeRequest && nestedBaseStackId == null) {
903 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
907 else { // This is to support gamma only - get info from vnf_resource table
908 if (vfVersion != null && !vfVersion.isEmpty()) {
909 vnfResource = db.getVnfResource(vnfType, vnfVersion);
911 vnfResource = db.getVnfResource(vnfType);
913 if (vnfResource == null) {
914 String error = "Create VNF: Unknown VNF Type: " + vnfType;
915 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
916 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
917 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
919 throw new VnfException(error, MsoExceptionCategory.USERDATA);
921 LOGGER.debug("Got VNF module definition from Catalog: "
922 + vnfResource.toString());
924 // By here - we have either a vf or vnfResource
926 //1607 - Add version check
927 // First - see if it's in the VnfResource record
928 // if we have a vf Module - then we have to query to get the VnfResource record.
930 if (vf.getVnfResourceModelUUId() != null) {
931 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
932 //vnfResource = db.getVnfResourceById(vnfResourceId);
933 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
934 if (vnfResource == null) {
936 "Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
940 String minVersionVnf = null;
941 String maxVersionVnf = null;
942 if (vnfResource != null) {
944 minVersionVnf = vnfResource.getAicVersionMin();
945 maxVersionVnf = vnfResource.getAicVersionMax();
946 } catch (Exception e) {
947 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
948 minVersionVnf = null;
949 maxVersionVnf = null;
951 if (minVersionVnf != null && "".equals(minVersionVnf)) {
952 minVersionVnf = null;
954 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
955 maxVersionVnf = null;
958 if (minVersionVnf != null && maxVersionVnf != null) {
959 MavenLikeVersioning aicV = new MavenLikeVersioning();
960 if (this.cloudConfig == null) {
961 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
964 if (this.cloudConfig != null) {
965 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
966 if (cloudSiteOpt.isPresent()) {
967 aicV.setVersion(cloudSiteOpt.get().getAic_version());
968 // Add code to handle unexpected values in here
969 boolean moreThanMin = true;
970 boolean equalToMin = true;
971 boolean moreThanMax = true;
972 boolean equalToMax = true;
973 boolean doNotTest = false;
975 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
976 equalToMin = aicV.isTheSameVersion(minVersionVnf);
977 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
978 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
979 } catch (Exception e) {
980 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage()
981 + " - will default to not check", e);
985 if ((moreThanMin || equalToMin) // aic >= min
986 && (equalToMax || !(moreThanMax))) { //aic <= max
987 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
988 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf
989 + " supported on Cloud: " + cloudSiteOpt.get().getId() + " with AIC_Version:"
990 + cloudSiteOpt.get().getAic_version());
994 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
995 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:"
996 + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get().getId()
997 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
998 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
999 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1000 LOGGER.debug(error);
1001 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1004 LOGGER.debug("bypassing testing AIC version...");
1006 } // let this error out downstream to avoid introducing uncertainty at this stage
1008 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1012 "AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1014 // End Version check 1607
1016 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
1017 // with VNF_RESOURCE - we use the old methods.
1018 //Integer heatTemplateId = null;
1019 //Integer heatEnvtId = null;
1021 String heatTemplateArtifactUuid = null;
1022 String heatEnvironmentArtifactUuid = null;
1025 if (isVolumeRequest) {
1026 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1027 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1029 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1030 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1033 if (isVolumeRequest) {
1035 "DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
1037 VnfComponent vnfComponent = null;
1038 vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME");
1039 if (vnfComponent == null) {
1040 String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME";
1041 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry");
1042 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1043 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1045 heatTemplateId = vnfComponent.getHeatTemplateId();
1046 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1050 heatTemplateArtifactUuid = vnfResource.getTemplateId();
1051 heatEnvironmentArtifactUuid = null;
1054 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1055 HeatTemplate heatTemplate = null;
1056 if (heatTemplateArtifactUuid == null || "".equals(heatTemplateArtifactUuid)) {
1057 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType="
1058 + requestTypeString;
1059 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "",
1060 MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1061 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1063 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1064 MsoAlarmLogger.CRITICAL, error);
1065 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1067 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1069 if (heatTemplate == null) {
1070 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1071 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1073 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "",
1074 MsoLogger.ErrorCode.BusinessProcesssError,
1075 "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1076 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1078 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1079 MsoAlarmLogger.CRITICAL, error);
1080 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1082 LOGGER.debug("Got HEAT Template from DB");
1084 HeatEnvironment heatEnvironment = null;
1085 String heatEnvironmentString = null;
1087 if (heatEnvironmentArtifactUuid != null && !"".equals(heatEnvironmentArtifactUuid)) {
1088 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1089 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1090 if (heatEnvironment == null) {
1091 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1092 + ", Environment ID="
1093 + heatEnvironmentArtifactUuid;
1094 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1095 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment",
1096 MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1097 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1099 // Alarm on this error, configuration must be fixed
1100 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1102 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1104 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1105 heatEnvironmentString = heatEnvironment
1106 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1107 LOGGER.debug("after parsing: " + heatEnvironmentString);
1110 LOGGER.debug("no environment parameter found for this Type " + vfModuleType);
1113 // 1510 - Add the files: for nested templates *if* there are any
1114 LOGGER.debug("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1115 + heatTemplate.getArtifactUuid());
1116 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1117 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1118 if (nestedTemplates != null) {
1119 // for debugging print them out
1120 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1121 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1122 String providerResourceFile = entry.getKey();
1123 Object value = entry.getValue();
1124 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1125 String childTemplateBody = (String) value;
1126 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1127 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1130 LOGGER.debug("No nested templates found - nothing to do here");
1131 nestedTemplatesChecked = null; // just to make sure
1134 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1135 // *if* there are any
1136 Map<String, HeatFiles> heatFiles = null;
1137 Map<String, Object> heatFilesObjects = new HashMap<>();
1139 // Add ability to turn on adding get_files with volume requests (by property).
1140 boolean addGetFilesOnVolumeReq = false;
1142 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1143 .getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1144 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1145 addGetFilesOnVolumeReq = true;
1146 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1148 } catch (Exception e) {
1149 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1150 + " - default to false", e);
1153 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1156 "In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1157 //heatFiles = db.getHeatFiles(vnfResource.getId());
1159 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1161 "In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1162 + vf.getModelUUID());
1164 .getHeatFilesForVfModule(vf.getModelUUID());
1166 if (heatFiles != null) {
1167 // add these to stack - to be done in createStack
1168 // here, we will map them to Map<String, Object> from
1169 // Map<String, HeatFiles>
1170 // this will match the nested templates format
1171 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1173 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1174 String heatFileName = entry.getKey();
1175 HeatFiles value = entry.getValue();
1176 if (heatFileName.startsWith("_ERROR|")) {
1177 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1178 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|") + 1);
1179 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType
1180 + " at HEAT_FILES index=" + heatFileId;
1181 LOGGER.debug(error);
1183 .error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId,
1184 vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError,
1185 "HEAT_FILES entry not found");
1186 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1187 MsoLogger.ResponseCode.DataNotFound, error);
1188 // Alarm on this error, configuration must be fixed
1189 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1190 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1192 String heatFileBody = value.getFileBody();
1193 String heatFileNameChecked = heatFileName;
1194 LOGGER.debug(heatFileNameChecked + " -> "
1196 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1199 LOGGER.debug("No heat files found -nothing to do here");
1200 heatFilesObjects = null;
1203 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1206 // Check that required parameters have been supplied
1207 StringBuilder missingParams = null;
1208 List<String> paramList = new ArrayList<>();
1210 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1211 // supplied an alias. Only check if we don't find it initially.
1212 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1213 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1215 boolean checkRequiredParameters = true;
1217 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1218 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1219 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1220 checkRequiredParameters = false;
1221 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1222 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1224 } catch (Exception e) {
1225 // No problem - default is true
1226 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1228 // 1604 - Add enhanced environment & parameter checking
1229 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1230 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1231 // Note this also removes any comments
1232 MsoHeatEnvironmentEntry mhee = null;
1233 if (heatEnvironmentString != null && heatEnvironmentString.contains("parameters:")) {
1234 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1235 LOGGER.debug("Enhanced environment checking enabled - 1604");
1236 mhee = MsoHeatEnvironmentEntry.create(heatEnvironmentString);
1237 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1238 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1239 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1241 if (!mhee.isValid()) {
1242 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1244 sb2.append("\nEnvironment:");
1247 LOGGER.debug(sb2.toString());
1249 LOGGER.debug("NO ENVIRONMENT for this entry");
1251 // New with 1707 - all variables converted to their native object types
1252 HashMap<String, Object> goldenInputs = null;
1254 LOGGER.debug("Now handle the inputs....first convert");
1255 ArrayList<String> parameterNames = new ArrayList<>();
1256 HashMap<String, String> aliasToParam = new HashMap<>();
1257 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1260 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1261 sb.append("param[").append(cntr++).append("]=").append(htp.getParamName());
1262 parameterNames.add(htp.getParamName());
1263 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1264 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1265 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1269 LOGGER.debug(sb.toString());
1270 } catch (Exception e) {
1271 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(), e);
1273 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1274 // Map<String, Object> - where the object matches the param type identified in the template
1275 // This will also not copy over params that aren't identified in the template
1276 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1277 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1278 LOGGER.debug("Now add in the base stack outputs if applicable");
1279 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1280 // Step 3 - add the volume inputs if any
1281 LOGGER.debug("Now add in the volume stack outputs if applicable");
1282 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1283 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1285 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1286 LOGGER.debug("Parameter:'" + parm.getParamName()
1290 + parm.getParamAlias());
1292 if (parm.isRequired() && (goldenInputs == null || !goldenInputs.containsKey(parm.getParamName()))) {
1293 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1294 LOGGER.debug("**Parameter " + parm.getParamName()
1295 + " is required and not in the inputs...check environment");
1296 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1297 LOGGER.debug("Required parameter " + parm.getParamName()
1298 + " appears to be in environment - do not count as missing");
1300 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
1301 if (missingParams == null) {
1302 missingParams = new StringBuilder(parm.getParamName());
1304 missingParams.append("," + parm.getParamName());
1308 paramList.add(parm.getParamName());
1310 if (missingParams != null) {
1311 if (checkRequiredParameters) {
1312 // Problem - missing one or more required parameters
1313 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1314 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
1315 MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1316 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1318 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1320 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1323 LOGGER.debug("No missing parameters found - ok to proceed");
1325 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1326 // and it causes problems with json that has arrays
1327 String newEnvironmentString = null;
1329 newEnvironmentString = mhee.getRawEntry();
1332 // "Fix" the template if it has CR/LF (getting this from Oracle)
1333 String template = heatTemplate.getHeatTemplate();
1334 template = template.replaceAll("\r\n", "\n");
1336 // Have the tenant. Now deploy the stack itself
1337 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1338 // because we already checked for those.
1339 long createStackStarttime = System.currentTimeMillis();
1341 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1342 // heatTemplate.getTimeoutMinutes());
1343 if (backout == null) {
1347 LOGGER.debug("heat is not null!!");
1349 heatStack = heat.createStack(cloudSiteId,
1355 heatTemplate.getTimeoutMinutes(),
1356 newEnvironmentString,
1357 nestedTemplatesChecked,
1359 backout.booleanValue());
1361 .recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
1362 "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1363 } catch (MsoException me) {
1364 me.addContext("CreateVFModule");
1365 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1366 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1367 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1368 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1369 MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1371 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1373 throw new VnfException(me);
1374 } catch (NullPointerException npe) {
1375 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1376 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1377 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1378 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1379 MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1381 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1383 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1384 //npe.addContext ("CreateVNF");
1385 throw new VnfException("NullPointerException during heat.createStack");
1386 } catch (Exception e) {
1387 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1388 MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack",
1389 "OpenStack", "CreateStack", vfModuleName);
1390 LOGGER.debug("unhandled exception at heat.createStack", e);
1392 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1393 "Exception while creating stack with OpenStack");
1394 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1396 } catch (Exception e) {
1397 LOGGER.debug("unhandled exception in create VF", e);
1398 throw new VnfException("Exception during create VF " + e.getMessage());
1401 // Make sure DB session is closed
1403 // Reach this point if createStack is successful.
1404 // Populate remaining rollback info and response parameters.
1405 vfRollback.setVnfId (heatStack.getCanonicalName ());
1406 vfRollback.setVnfCreated (true);
1408 vnfId.value = heatStack.getCanonicalName ();
1409 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1410 rollback.value = vfRollback;
1412 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1413 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1417 public void deleteVfModule (String cloudSiteId,
1420 MsoRequest msoRequest,
1421 Holder <Map <String, String>> outputs) throws VnfException {
1422 MsoLogger.setLogContext (msoRequest);
1423 MsoLogger.setServiceName ("DeleteVf");
1424 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1425 // Will capture execution time for metrics
1426 long startTime = System.currentTimeMillis ();
1428 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1430 // 1702 capture the output parameters on a delete
1431 // so we'll need to query first
1432 Map<String, Object> stackOutputs = null;
1434 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1435 } catch (MsoException me) {
1436 // Failed to query the Stack due to an openstack exception.
1437 // Convert to a generic VnfException
1438 me.addContext ("DeleteVFModule");
1439 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1440 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1441 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1442 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1443 throw new VnfException (me);
1445 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1446 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1448 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1449 // The possible outcomes of deleteStack are a StackInfo object with status
1450 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1452 long subStartTime = System.currentTimeMillis ();
1454 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1455 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1456 } catch (MsoException me) {
1457 me.addContext ("DeleteVNF");
1458 // Failed to query the Stack due to an openstack exception.
1459 // Convert to a generic VnfException
1460 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1461 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1462 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1463 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1464 throw new VnfException (me);
1467 // On success, nothing is returned.
1468 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1472 public void updateVfModule (String cloudSiteId,
1478 String volumeGroupHeatStackId,
1479 String baseVfHeatStackId,
1480 String vfModuleStackId,
1481 String modelCustomizationUuid,
1482 Map <String, String> inputs,
1483 MsoRequest msoRequest,
1484 Holder <Map <String, String>> outputs,
1485 Holder <VnfRollback> rollback) throws VnfException {
1486 String vfModuleName = vnfName;
1487 String vfModuleType = vnfType;
1488 String methodName = "updateVfModule";
1489 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1490 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1491 MsoLogger.setServiceName (serviceName);
1493 String strInit = "updateVfModule: cloudSiteId=" + cloudSiteId +
1494 ",tenantId=" + tenantId +
1495 ",vnfType=" + vnfType +
1496 ",vnfVersion=" + vnfVersion +
1497 ",vnfName=" + vnfName +
1498 ",requestType=" + requestType +
1499 ",volumeGroupHeatStackId=" + volumeGroupHeatStackId +
1500 ",baseVfHeatStackId=" + baseVfHeatStackId +
1501 ",vfModuleStackId=" + vfModuleStackId +
1502 ",modelCustomizationUuid=" + modelCustomizationUuid;
1503 LOGGER.debug(strInit);
1505 String mcu = modelCustomizationUuid;
1506 boolean useMCUuid = false;
1507 if (mcu != null && !mcu.isEmpty()) {
1508 if (mcu.equalsIgnoreCase("null")) {
1509 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1513 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1518 String requestTypeString = "";
1519 if (requestType != null && !"".equals(requestType)) {
1520 requestTypeString = requestType;
1522 String nestedStackId = null;
1523 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
1524 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1525 nestedStackId = volumeGroupHeatStackId;
1528 String nestedBaseStackId = null;
1529 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
1530 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
1531 nestedBaseStackId = baseVfHeatStackId;
1535 if (inputs == null) {
1536 // Create an empty set of inputs
1537 inputs = new HashMap<>();
1538 LOGGER.debug("inputs == null - setting to empty");
1540 this.sendMapToDebug(inputs);
1542 boolean isBaseRequest = false;
1543 boolean isVolumeRequest = false;
1544 if (requestTypeString.startsWith("VOLUME")) {
1545 isVolumeRequest = true;
1547 if (vfModuleName == null || "".equals(vfModuleName.trim())) {
1548 if (vfModuleStackId != null) {
1549 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1553 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1554 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1556 // Will capture execution time for metrics
1557 long startTime = System.currentTimeMillis ();
1559 // Build a default rollback object (no actions performed)
1560 VnfRollback vfRollback = new VnfRollback ();
1561 vfRollback.setCloudSiteId (cloudSiteId);
1562 vfRollback.setTenantId (tenantId);
1563 vfRollback.setMsoRequest (msoRequest);
1564 vfRollback.setRequestType(requestTypeString);
1565 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1566 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1567 vfRollback.setIsBase(isBaseRequest);
1568 vfRollback.setVfModuleStackId(vfModuleStackId);
1569 vfRollback.setModelCustomizationUuid(mcu);
1571 // First, look up to see if the VNF already exists.
1572 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1573 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1575 StackInfo heatStack = null;
1576 long queryStackStarttime = System.currentTimeMillis ();
1577 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1579 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1580 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1581 } catch (MsoException me) {
1582 // Failed to query the Stack due to an openstack exception.
1583 // Convert to a generic VnfException
1584 me.addContext ("UpdateVFModule");
1585 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1586 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1587 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1588 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1589 throw new VnfException (me);
1592 //TODO - do we need to check for the other status possibilities?
1593 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1595 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1596 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1597 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1598 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1600 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1601 // Populate the outputs from the existing stack.
1602 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1603 rollback.value = vfRollback; // Default rollback - no updates performed
1606 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1607 StackInfo nestedHeatStack = null;
1608 long queryStackStarttime2 = System.currentTimeMillis ();
1609 Map<String, Object> nestedVolumeOutputs = null;
1610 if (nestedStackId != null) {
1612 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1613 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1614 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1615 } catch (MsoException me) {
1616 // Failed to query the Stack due to an openstack exception.
1617 // Convert to a generic VnfException
1618 me.addContext ("UpdateVFModule");
1619 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1620 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1621 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1622 LOGGER.debug("ERROR trying to query nested stack= " + error);
1623 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1624 throw new VnfException (me);
1626 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1627 MsoLogger.setServiceName (serviceName);
1628 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1629 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1630 LOGGER.debug(error);
1631 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1632 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1634 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1635 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1636 //this.sendMapToDebug(inputs);
1637 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1639 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1640 //this.sendMapToDebug(inputs);
1643 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1644 StackInfo nestedBaseHeatStack = null;
1645 Map<String, Object> baseStackOutputs = null;
1646 if (nestedBaseStackId != null) {
1647 long queryStackStarttime3 = System.currentTimeMillis ();
1649 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1650 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1651 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1652 } catch (MsoException me) {
1653 // Failed to query the Stack due to an openstack exception.
1654 // Convert to a generic VnfException
1655 me.addContext ("UpdateVfModule");
1656 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1657 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1658 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1659 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1660 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1661 throw new VnfException (me);
1663 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1664 MsoLogger.setServiceName (serviceName);
1665 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1666 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1667 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1668 LOGGER.debug(error);
1669 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1671 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1672 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1673 //this.sendMapToDebug(inputs);
1674 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1676 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1677 //this.sendMapToDebug(inputs);
1681 // Ready to deploy the new VNF
1683 // Get a handle to the Catalog Database
1685 // Make sure DB session is closed
1686 try (CatalogDatabase db = CatalogDatabase.getInstance()) {
1687 // Retrieve the VF definition
1688 VnfResource vnfResource = null;
1690 VfModuleCustomization vfmc = null;
1692 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1693 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1694 vf = vfmc != null ? vfmc.getVfModule() : null;
1696 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1699 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1702 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1703 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "",
1704 MsoLogger.ErrorCode.DataError, error);
1705 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1706 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1708 LOGGER.debug("Got VF module definition from Catalog: " + vf.toString());
1710 isBaseRequest = true;
1711 LOGGER.debug("This a BASE update request");
1713 LOGGER.debug("This is *not* a BASE VF update request");
1714 if (!isVolumeRequest && nestedBaseStackId == null) {
1716 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1720 //1607 - Add version check
1721 // First - see if it's in the VnfResource record
1722 // if we have a vf Module - then we have to query to get the VnfResource record.
1723 if (vf.getVnfResourceModelUUId() != null) {
1724 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1725 //vnfResource = db.getVnfResourceById(vnfResourceId);
1726 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1727 if (vnfResource == null) {
1729 .debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1732 String minVersionVnf = null;
1733 String maxVersionVnf = null;
1734 if (vnfResource != null) {
1736 minVersionVnf = vnfResource.getAicVersionMin();
1737 maxVersionVnf = vnfResource.getAicVersionMax();
1738 } catch (Exception e) {
1739 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
1740 minVersionVnf = null;
1741 maxVersionVnf = null;
1743 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1744 minVersionVnf = null;
1746 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1747 maxVersionVnf = null;
1750 if (minVersionVnf != null && maxVersionVnf != null) {
1751 MavenLikeVersioning aicV = new MavenLikeVersioning();
1752 //String aicVersion = "";
1753 if (this.cloudConfig == null) {
1754 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1757 if (this.cloudConfig != null) {
1758 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1759 if (cloudSiteOpt.isPresent()) {
1760 aicV.setVersion(cloudSiteOpt.get().getAic_version());
1761 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1762 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV
1763 .isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1764 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1765 + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteOpt.get().getId()
1766 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version());
1770 "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1771 + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get()
1772 .getId() + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
1773 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1774 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1775 LOGGER.debug(error);
1776 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1778 } // let this error out downstream to avoid introducing uncertainty at this stage
1780 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1784 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1786 // End Version check 1607
1788 String heatTemplateArtifactUuid = null;
1789 String heatEnvironmentArtifactUuid = null;
1791 HeatTemplate heatTemplate = null;
1792 if (isVolumeRequest) {
1793 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1794 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1796 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1797 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1799 if (heatTemplateArtifactUuid == null) {
1801 "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType="
1802 + requestTypeString;
1803 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "",
1804 MsoLogger.ErrorCode.DataError, error);
1805 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1807 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1808 MsoAlarmLogger.CRITICAL, error);
1809 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1811 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1814 if (heatTemplate == null) {
1815 String error = "Update VNF: undefined Heat Template. VF="
1816 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1817 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1819 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1820 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1822 // Alarm on this error, configuration must be fixed
1823 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1824 MsoAlarmLogger.CRITICAL, error);
1826 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1829 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1831 // Add check for any Environment variable
1832 HeatEnvironment heatEnvironment = null;
1833 String heatEnvironmentString = null;
1835 if (heatEnvironmentArtifactUuid != null) {
1836 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1837 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1838 if (heatEnvironment == null) {
1840 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1841 + ", Environment ID="
1842 + heatEnvironmentArtifactUuid;
1843 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1844 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError,
1846 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1848 // Alarm on this error, configuration must be fixed
1849 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1851 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1853 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1854 heatEnvironmentString = heatEnvironment
1855 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1856 LOGGER.debug("After parsing: " + heatEnvironmentString);
1859 LOGGER.debug("no environment parameter for this VFModuleType " + vfModuleType);
1862 LOGGER.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1863 + heatTemplate.getArtifactUuid());
1864 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1865 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1866 if (nestedTemplates != null) {
1867 // for debugging print them out
1868 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1869 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1870 String providerResourceFile = entry.getKey();
1871 Object value = entry.getValue();
1872 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1873 String childTemplateBody = (String) value;
1874 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1875 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1878 LOGGER.debug("No nested templates found - nothing to do here");
1879 nestedTemplatesChecked = null;
1882 // Also add the files: for any get_files associated with this VfModule
1883 // *if* there are any
1884 LOGGER.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1885 + vf.getModelUUID());
1887 Map<String, HeatFiles> heatFiles = null;
1888 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1889 Map<String, Object> heatFilesObjects = new HashMap<>();
1891 // Add ability to turn on adding get_files with volume requests (by property).
1892 boolean addGetFilesOnVolumeReq = false;
1894 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1895 .getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1896 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1897 addGetFilesOnVolumeReq = true;
1898 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1900 } catch (Exception e) {
1901 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1902 + " - default to false", e);
1904 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1906 "In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1907 + vf.getModelUUID());
1909 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1910 if (heatFiles != null) {
1911 // add these to stack - to be done in createStack
1912 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1913 // this will match the nested templates format
1914 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1916 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1917 String heatFileName = entry.getKey();
1918 HeatFiles value = entry.getValue();
1919 if (heatFileName.startsWith("_ERROR|")) {
1920 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1921 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|") + 1);
1922 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType
1923 + " at HEAT_FILES index=" + heatFileId;
1924 LOGGER.debug(error);
1926 .error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId,
1927 vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1928 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1929 MsoLogger.ResponseCode.DataNotFound, error);
1930 // Alarm on this error, configuration must be fixed
1931 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1932 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1934 String heatFileBody = value.getFileBody();
1935 LOGGER.debug(heatFileName + " -> " + heatFileBody);
1936 heatFilesObjects.put(heatFileName, heatFileBody);
1939 LOGGER.debug("No heat files found -nothing to do here");
1940 heatFilesObjects = null;
1944 // Check that required parameters have been supplied
1945 StringBuilder missingParams = null;
1946 List<String> paramList = new ArrayList<>();
1948 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1949 // supplied an alias. Only check if we don't find it initially.
1950 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1951 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1953 boolean haveEnvironmentParameters = false;
1954 boolean checkRequiredParameters = true;
1956 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1957 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1958 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1959 checkRequiredParameters = false;
1960 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1961 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1963 } catch (Exception e) {
1964 // No problem - default is true
1965 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1967 // 1604 - Add enhanced environment & parameter checking
1968 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1969 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1970 // Note this also removes any comments
1971 MsoHeatEnvironmentEntry mhee = null;
1972 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase().contains("parameters:")) {
1973 LOGGER.debug("Enhanced environment checking enabled - 1604");
1974 mhee = MsoHeatEnvironmentEntry.create(heatEnvironmentString);
1975 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1976 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1977 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1979 if (!mhee.isValid()) {
1980 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1982 sb2.append("\nEnvironment:");
1985 LOGGER.debug(sb2.toString());
1987 LOGGER.debug("NO ENVIRONMENT for this entry");
1990 // New for 1607 - support params of json type
1991 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1992 boolean hasJson = false;
1994 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1995 LOGGER.debug("Parameter:'" + parm.getParamName()
1999 + parm.getParamAlias());
2001 String parameterType = parm.getParamType();
2002 if (parameterType == null || "".equals(parameterType.trim())) {
2003 parameterType = "String";
2005 JsonNode jsonNode = null;
2006 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
2007 if (inputs.containsKey(parm.getParamName())) {
2009 String jsonString = null;
2011 jsonString = inputs.get(parm.getParamName());
2012 jsonNode = new ObjectMapper().readTree(jsonString);
2013 } catch (JsonParseException jpe) {
2014 //TODO - what to do here?
2015 //for now - send the error to debug, but just leave it as a String
2016 String errorMessage = jpe.getMessage();
2017 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
2020 } catch (Exception e) {
2022 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
2026 if (jsonNode != null) {
2027 jsonParams.put(parm.getParamName(), jsonNode);
2029 } else if (inputs.containsKey(parm.getParamAlias())) {
2031 String jsonString = null;
2033 jsonString = inputs.get(parm.getParamAlias());
2034 jsonNode = new ObjectMapper().readTree(jsonString);
2035 } catch (JsonParseException jpe) {
2036 //TODO - what to do here?
2037 //for now - send the error to debug, but just leave it as a String
2038 String errorMessage = jpe.getMessage();
2039 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
2042 } catch (Exception e) {
2044 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
2048 if (jsonNode != null) {
2049 // Notice here - we add it to the jsonParams hashMap with the actual name -
2050 // then manipulate the inputs so when we check for aliases below - it will not
2052 jsonParams.put(parm.getParamName(), jsonNode);
2053 inputs.remove(parm.getParamAlias());
2054 inputs.put(parm.getParamName(), jsonString);
2056 } //TODO add a check for the parameter in the env file
2059 if (parm.isRequired() && (inputs == null || !inputs.containsKey(parm.getParamName()))) {
2060 if (inputs.containsKey(parm.getParamAlias())) {
2061 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2062 String realParamName = parm.getParamName();
2063 String alias = parm.getParamAlias();
2064 String value = inputs.get(alias);
2065 LOGGER.debug("*Found an Alias: paramName=" + realParamName
2070 inputs.remove(alias);
2071 inputs.put(realParamName, value);
2072 LOGGER.debug(alias + " entry removed from inputs, added back using " + realParamName);
2074 // enhanced - check if it's in the Environment (note: that method
2075 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2077 LOGGER.debug("Required parameter " + parm.getParamName()
2078 + " appears to be in environment - do not count as missing");
2080 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
2081 if (missingParams == null) {
2082 missingParams = new StringBuilder(parm.getParamName());
2084 missingParams.append("," + parm.getParamName());
2088 paramList.add(parm.getParamName());
2090 if (missingParams != null) {
2091 // Problem - missing one or more required parameters
2092 if (checkRequiredParameters) {
2093 String error = "Update VNF: Missing Required inputs: " + missingParams;
2094 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
2095 MsoLogger.ErrorCode.DataError, error);
2096 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
2098 throw new VnfException(error, MsoExceptionCategory.USERDATA);
2100 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
2103 LOGGER.debug("No missing parameters found - ok to proceed");
2106 // Just submit the envt entry as received from the database
2107 String newEnvironmentString = null;
2109 newEnvironmentString = mhee.getRawEntry();
2112 // Remove any extraneous parameters (don't throw an error)
2113 if (inputs != null) {
2114 List<String> extraParams = new ArrayList<>();
2115 extraParams.addAll(inputs.keySet());
2116 // This is not a valid parameter for this template
2117 extraParams.removeAll(paramList);
2118 if (!extraParams.isEmpty()) {
2119 LOGGER.warn(MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "",
2120 MsoLogger.ErrorCode.DataError, "Extra params");
2121 inputs.keySet().removeAll(extraParams);
2124 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2125 Map<String, Object> inputsTwo = null;
2126 if (hasJson && jsonParams.size() > 0) {
2127 inputsTwo = new HashMap<>();
2128 for (Map.Entry<String, String> entry : inputs.entrySet()) {
2129 String keyParamName = entry.getKey();
2130 String value = entry.getValue();
2131 if (jsonParams.containsKey(keyParamName)) {
2132 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2134 inputsTwo.put(keyParamName, value);
2139 // "Fix" the template if it has CR/LF (getting this from Oracle)
2140 String template = heatTemplate.getHeatTemplate();
2141 template = template.replaceAll("\r\n", "\n");
2143 // Have the tenant. Now deploy the stack itself
2144 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2145 // because we already checked for those.
2146 long updateStackStarttime = System.currentTimeMillis();
2149 heatStack = heatU.updateStack(cloudSiteId,
2153 copyStringInputs(inputs),
2155 heatTemplate.getTimeoutMinutes(),
2156 newEnvironmentString,
2157 //heatEnvironmentString,
2158 nestedTemplatesChecked,
2160 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2161 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2162 "UpdateStack", null);
2164 heatStack = heatU.updateStack(cloudSiteId,
2170 heatTemplate.getTimeoutMinutes(),
2171 newEnvironmentString,
2172 //heatEnvironmentString,
2173 nestedTemplatesChecked,
2175 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2176 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2177 "UpdateStack", null);
2180 } catch (MsoException me) {
2181 me.addContext("UpdateVFModule");
2182 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2183 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.ERROR,
2184 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2185 LOGGER.error(MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
2186 MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2188 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
2190 throw new VnfException(me);
2193 // Make sure DB session is closed
2195 // Reach this point if updateStack is successful.
2196 // Populate remaining rollback info and response parameters.
2197 vfRollback.setVnfId (heatStack.getCanonicalName ());
2198 vfRollback.setVnfCreated (true);
2200 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2201 rollback.value = vfRollback;
2202 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2205 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2206 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2207 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2208 if (vfModuleStackId == null)
2210 int index = vfModuleStackId.lastIndexOf('/');
2213 String vfModuleName = null;
2215 vfModuleName = vfModuleStackId.substring(0, index);
2216 } catch (Exception e) {
2217 LOGGER.debug("Exception", e);
2218 vfModuleName = null;
2220 return vfModuleName;