2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.mso.adapters.vnf;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.List;
32 import java.util.Optional;
33 import java.util.Scanner;
34 import java.util.concurrent.TimeUnit;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
38 import javax.jws.WebService;
39 import javax.xml.ws.Holder;
41 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
42 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
43 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
44 import org.openecomp.mso.cloud.CloudConfig;
45 import org.openecomp.mso.cloud.CloudConfigFactory;
46 import org.openecomp.mso.cloud.CloudSite;
47 import org.openecomp.mso.db.catalog.CatalogDatabase;
48 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
49 import org.openecomp.mso.db.catalog.beans.HeatFiles;
50 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
51 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
52 import org.openecomp.mso.db.catalog.beans.VfModule;
53 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
54 import org.openecomp.mso.db.catalog.beans.VnfResource;
55 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
56 import org.openecomp.mso.entity.MsoRequest;
57 import org.openecomp.mso.logger.MessageEnum;
58 import org.openecomp.mso.logger.MsoAlarmLogger;
59 import org.openecomp.mso.logger.MsoLogger;
60 import org.openecomp.mso.openstack.beans.HeatStatus;
61 import org.openecomp.mso.openstack.beans.StackInfo;
62 import org.openecomp.mso.openstack.beans.VnfRollback;
63 import org.openecomp.mso.openstack.beans.VnfStatus;
64 import org.openecomp.mso.openstack.exceptions.MsoException;
65 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
66 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
67 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
68 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
69 import org.openecomp.mso.properties.MsoPropertiesFactory;
71 import com.fasterxml.jackson.core.JsonParseException;
72 import com.fasterxml.jackson.databind.JsonNode;
73 import com.fasterxml.jackson.databind.ObjectMapper;
75 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
76 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
78 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
79 protected CloudConfig cloudConfig = null;
81 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
83 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
84 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
85 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
86 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
87 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
88 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
89 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
90 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
93 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
94 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
96 public MsoVnfAdapterImpl() {
97 // empty implementation
101 * This constructor MUST be used if this class is called with the new operator.
102 * @param msoPropFactory
104 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
105 this.msoPropertiesFactory = msoPropFactory;
106 this.cloudConfigFactory = cloudConfigFact;
110 * Health Check web method. Does nothing but return to show the adapter is deployed.
113 public void healthCheck () {
114 LOGGER.debug ("Health check call in VNF Adapter");
118 * This is the "Create VNF" web service implementation.
119 * It will create a new VNF of the requested type in the specified cloud
120 * and tenant. The tenant must exist before this service is called.
122 * If a VNF with the same name already exists, this can be considered a
123 * success or failure, depending on the value of the 'failIfExists' parameter.
125 * All VNF types will be defined in the MSO catalog. The caller must request
126 * one of these pre-defined types or an error will be returned. Within the
127 * catalog, each VNF type references (among other things) a Heat template
128 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
131 * Depending on the Heat template, a variable set of input parameters will
132 * be defined, some of which are required. The caller is responsible to
133 * pass the necessary input data for the VNF or an error will be thrown.
135 * The method returns the vnfId (the canonical name), a Map of VNF output
136 * attributes, and a VnfRollback object. This last object can be passed
137 * as-is to the rollbackVnf operation to undo everything that was created
138 * for the VNF. This is useful if a VNF is successfully created but the
139 * orchestrator fails on a subsequent operation.
141 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
142 * @param tenantId Openstack tenant identifier
143 * @param vnfType VNF type key, should match a VNF definition in catalog DB
144 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
145 * @param vnfName Name to be assigned to the new VNF
146 * @param inputs Map of key=value inputs for VNF stack creation
147 * @param failIfExists Flag whether already existing VNF should be considered
148 * a success or failure
149 * @param msoRequest Request tracking information for logs
150 * @param vnfId Holder for output VNF Openstack ID
151 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
152 * @param rollback Holder for returning VnfRollback object
155 public void createVnf (String cloudSiteId,
161 String volumeGroupHeatStackId,
162 Map <String, String> inputs,
163 Boolean failIfExists,
165 MsoRequest msoRequest,
166 Holder <String> vnfId,
167 Holder <Map <String, String>> outputs,
168 Holder <VnfRollback> rollback) throws VnfException {
169 // Create a hook here to catch shortcut createVf requests:
170 if (requestType != null) {
171 if (requestType.startsWith("VFMOD")) {
172 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
173 String newRequestType = requestType.substring(5);
174 String vfVolGroupHeatStackId = "";
175 String vfBaseHeatStackId = "";
177 if (volumeGroupHeatStackId != null) {
178 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
179 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
181 } catch (Exception e) {
182 // might be ok - both are just blank
183 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
185 this.createVfModule(cloudSiteId,
191 vfVolGroupHeatStackId,
204 // createVf will know if the requestType starts with "X" that it's the "old" way
205 StringBuilder newRequestTypeSb = new StringBuilder("X");
206 String vfVolGroupHeatStackId = "";
207 String vfBaseHeatStackId = "";
208 if (requestType != null) {
209 newRequestTypeSb.append(requestType);
211 this.createVfModule(cloudSiteId,
216 newRequestTypeSb.toString(),
217 vfVolGroupHeatStackId,
227 // End createVf shortcut
231 public void updateVnf (String cloudSiteId,
237 String volumeGroupHeatStackId,
238 Map <String, String> inputs,
239 MsoRequest msoRequest,
240 Holder <Map <String, String>> outputs,
241 Holder <VnfRollback> rollback) throws VnfException {
242 // As of 1707 - this method should no longer be called
243 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
244 MsoLogger.setServiceName ("UpdateVnf");
245 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
249 * This is the "Query VNF" web service implementation.
250 * It will look up a VNF by name or ID in the specified cloud and tenant.
252 * The method returns an indicator that the VNF exists, its Openstack internal
253 * ID, its status, and the set of outputs (from when the stack was created).
255 * @param cloudSiteId CLLI code of the cloud site in which to query
256 * @param tenantId Openstack tenant identifier
257 * @param vnfName VNF Name or Openstack ID
258 * @param msoRequest Request tracking information for logs
259 * @param vnfExists Flag reporting the result of the query
260 * @param vnfId Holder for output VNF Openstack ID
261 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
264 public void queryVnf (String cloudSiteId,
267 MsoRequest msoRequest,
268 Holder <Boolean> vnfExists,
269 Holder <String> vnfId,
270 Holder <VnfStatus> status,
271 Holder <Map <String, String>> outputs) throws VnfException {
272 MsoLogger.setLogContext (msoRequest);
273 MsoLogger.setServiceName ("QueryVnf");
274 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
276 // Will capture execution time for metrics
277 long startTime = System.currentTimeMillis ();
279 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
281 StackInfo heatStack = null;
282 long subStartTime = System.currentTimeMillis ();
284 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
285 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
286 } catch (MsoException me) {
287 me.addContext ("QueryVNF");
288 // Failed to query the Stack due to an openstack exception.
289 // Convert to a generic VnfException
290 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
291 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
292 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
293 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
294 throw new VnfException (me);
297 // Populate the outputs based on the returned Stack information
299 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
301 vnfExists.value = Boolean.FALSE;
302 status.value = VnfStatus.NOTFOUND;
304 outputs.value = new HashMap<>(); // Return as an empty map
306 LOGGER.debug ("VNF " + vnfName + " not found");
308 vnfExists.value = Boolean.TRUE;
309 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
310 vnfId.value = heatStack.getCanonicalName ();
311 outputs.value = copyStringOutputs (heatStack.getOutputs ());
313 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
315 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
319 * This is the "Delete VNF" web service implementation.
320 * It will delete a VNF by name or ID in the specified cloud and tenant.
322 * The method has no outputs.
324 * @param cloudSiteId CLLI code of the cloud site in which to delete
325 * @param tenantId Openstack tenant identifier
326 * @param vnfName VNF Name or Openstack ID
327 * @param msoRequest Request tracking information for logs
330 public void deleteVnf (String cloudSiteId,
333 MsoRequest msoRequest) throws VnfException {
334 MsoLogger.setLogContext (msoRequest);
335 MsoLogger.setServiceName ("DeleteVnf");
336 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
337 // Will capture execution time for metrics
338 long startTime = System.currentTimeMillis ();
340 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
342 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
343 // The possible outcomes of deleteStack are a StackInfo object with status
344 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
346 long subStartTime = System.currentTimeMillis ();
348 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
349 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
350 } catch (MsoException me) {
351 me.addContext ("DeleteVNF");
352 // Failed to query the Stack due to an openstack exception.
353 // Convert to a generic VnfException
354 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
355 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
356 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
357 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
358 throw new VnfException (me);
361 // On success, nothing is returned.
362 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
366 * This web service endpoint will rollback a previous Create VNF operation.
367 * A rollback object is returned to the client in a successful creation
368 * response. The client can pass that object as-is back to the rollbackVnf
369 * operation to undo the creation.
372 public void rollbackVnf (VnfRollback rollback) throws VnfException {
373 long startTime = System.currentTimeMillis ();
374 MsoLogger.setServiceName ("RollbackVnf");
375 // rollback may be null (e.g. if stack already existed when Create was called)
376 if (rollback == null) {
377 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
378 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
382 // Get the elements of the VnfRollback object for easier access
383 String cloudSiteId = rollback.getCloudSiteId ();
384 String tenantId = rollback.getTenantId ();
385 String vnfId = rollback.getVnfId ();
387 MsoLogger.setLogContext (rollback.getMsoRequest());
389 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
391 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
393 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
394 // The possible outcomes of deleteStack are a StackInfo object with status
395 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
397 long subStartTime = System.currentTimeMillis ();
399 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
400 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
401 } catch (MsoException me) {
402 // Failed to rollback the Stack due to an openstack exception.
403 // Convert to a generic VnfException
404 me.addContext ("RollbackVNF");
405 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
406 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
407 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
408 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
409 throw new VnfException (me);
411 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
414 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
415 switch (stackStatus) {
417 return VnfStatus.ACTIVE;
419 return VnfStatus.ACTIVE;
421 return VnfStatus.FAILED;
423 return VnfStatus.UNKNOWN;
427 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
428 Map <String, String> stringOutputs = new HashMap <> ();
429 for (Map.Entry<String,Object> entry : stackOutputs.entrySet ()) {
430 String key = entry.getKey();
431 Object value = entry.getValue();
432 if (value instanceof String) {
433 stringOutputs.put (key, (String) value);
434 } else if (value instanceof Integer) {
436 String str = "" + value;
437 stringOutputs.put(key, str);
438 } catch (Exception e) {
439 LOGGER.debug("Unable to add " + key + " to outputs",e);
441 } else if (value instanceof JsonNode) {
443 //String str = this.convertNode((JsonNode) value);
444 String str = value.toString();
445 stringOutputs.put(key, str);
446 } catch (Exception e) {
447 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode",e);
449 } else if (value instanceof java.util.LinkedHashMap) {
451 //String str = JSON_MAPPER.writeValueAsString(value);
452 String str = value.toString();
453 stringOutputs.put(key, str);
454 } catch (Exception e) {
455 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap",e);
459 String str = value.toString();
460 stringOutputs.put(key, str);
461 } catch (Exception e) {
462 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),e);
466 return stringOutputs;
469 private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
470 return new HashMap <> (stringInputs);
473 private boolean callHeatbridge(String heatStackId) {
474 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
475 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
476 long waitTimeMs = 10000L;
478 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
479 String[] envp = null;
480 File dir = new File(executionDir);
481 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
482 Runtime r = Runtime.getRuntime();
483 Process p = r.exec(cmdarray, envp, dir);
484 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
486 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
487 return wait && p.exitValue()==0;
488 } catch (IOException e) {
489 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
491 } catch (InterruptedException e) {
492 LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e);
494 } catch (RuntimeException e) {
495 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e);
500 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
502 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
503 if (inputs == null) {
506 else if (inputs.size() < 1) {
507 sb.append("\tEMPTY");
509 for (Map.Entry<String,Object> entry : inputs.entrySet()) {
511 String str = entry.getKey();
512 Object value = entry.getValue();
514 outputString = value.toString();
515 } catch (Exception e) {
516 LOGGER.debug("Exception :",e);
517 outputString = "Unable to call toString() on the value for " + str;
519 sb.append("\t\nitem ").append(i++).append(": '").append(str).append("'='").append(outputString)
523 LOGGER.debug(sb.toString());
526 private void sendMapToDebug(Map<String, String> inputs) {
528 StringBuilder sb = new StringBuilder("inputs:");
529 if (inputs == null) {
532 else if (inputs.size() < 1) {
533 sb.append("\tEMPTY");
535 for (String str : inputs.keySet()) {
536 sb.append("\titem ").append(i++).append(": ").append(str).append("=").append(inputs.get(str));
539 LOGGER.debug(sb.toString());
542 private String convertNode(final JsonNode node) {
544 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
545 final String json = JSON_MAPPER.writeValueAsString(obj);
547 } catch (Exception e) {
548 LOGGER.debug("Error converting json to string " + e.getMessage(),e);
550 return "[Error converting json to string]";
553 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
554 if (objectMap == null) {
557 Map<String, String> stringMap = new HashMap<>();
558 for (String key : objectMap.keySet()) {
559 if (!stringMap.containsKey(key)) {
560 Object obj = objectMap.get(key);
561 if (obj instanceof String) {
562 stringMap.put(key, (String) objectMap.get(key));
563 } else if (obj instanceof JsonNode ){
564 // This is a bit of mess - but I think it's the least impacting
565 // let's convert it BACK to a string - then it will get converted back later
567 String str = this.convertNode((JsonNode) obj);
568 stringMap.put(key, str);
569 } catch (Exception e) {
570 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
571 //okay in this instance - only string values (fqdn) are expected to be needed
573 } else if (obj instanceof java.util.LinkedHashMap) {
574 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
576 String str = JSON_MAPPER.writeValueAsString(obj);
577 stringMap.put(key, str);
578 } catch (Exception e) {
579 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
581 } else if (obj instanceof Integer) {
583 String str = "" + obj;
584 stringMap.put(key, str);
585 } catch (Exception e) {
586 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
590 String str = obj.toString();
591 stringMap.put(key, str);
592 } catch (Exception e) {
593 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
603 public void createVfModule(String cloudSiteId,
609 String volumeGroupHeatStackId,
610 String baseVfHeatStackId,
611 String modelCustomizationUuid,
612 Map <String, String> inputs,
613 Boolean failIfExists,
615 MsoRequest msoRequest,
616 Holder <String> vnfId,
617 Holder <Map <String, String>> outputs,
618 Holder <VnfRollback> rollback) throws VnfException {
619 String vfModuleName = vnfName;
620 String vfModuleType = vnfType;
621 String vfVersion = vnfVersion;
622 String mcu = modelCustomizationUuid;
623 boolean useMCUuid = false;
624 if (mcu != null && !mcu.isEmpty()) {
625 if ("null".equalsIgnoreCase(mcu)) {
626 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
630 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
634 MsoLogger.setLogContext (msoRequest);
635 MsoLogger.setServiceName ("CreateVfModule");
636 String requestTypeString = "";
637 if (requestType != null && !"".equals(requestType)) {
638 requestTypeString = requestType;
640 String nestedStackId = null;
641 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
642 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
643 nestedStackId = volumeGroupHeatStackId;
646 String nestedBaseStackId = null;
647 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
648 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
649 nestedBaseStackId = baseVfHeatStackId;
653 if (inputs == null) {
654 // Create an empty set of inputs
655 inputs = new HashMap<>();
656 LOGGER.debug("inputs == null - setting to empty");
658 this.sendMapToDebug(inputs);
660 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
661 boolean oldWay = false;
662 if (requestTypeString.startsWith("X")) {
664 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
665 requestTypeString = requestTypeString.substring(1);
668 // 1607 - let's parse out the request type we're being sent
669 boolean isBaseRequest = false;
670 boolean isVolumeRequest = false;
671 if (requestTypeString.startsWith("VOLUME")) {
672 isVolumeRequest = true;
675 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
676 // Will capture execution time for metrics
677 long startTime = System.currentTimeMillis ();
679 // Build a default rollback object (no actions performed)
680 VnfRollback vfRollback = new VnfRollback();
681 vfRollback.setCloudSiteId(cloudSiteId);
682 vfRollback.setTenantId(tenantId);
683 vfRollback.setMsoRequest(msoRequest);
684 vfRollback.setRequestType(requestTypeString);
685 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
686 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
687 vfRollback.setIsBase(isBaseRequest);
688 vfRollback.setModelCustomizationUuid(mcu);
690 // Put data into A&AI through Heatstack
691 callHeatbridge(baseVfHeatStackId);
693 // First, look up to see if the VF already exists.
694 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
696 StackInfo heatStack = null;
697 long subStartTime1 = System.currentTimeMillis ();
699 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
700 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
701 } catch (MsoException me) {
702 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
703 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
704 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
705 // Failed to query the Stack due to an openstack exception.
706 // Convert to a generic VnfException
707 me.addContext ("CreateVFModule");
708 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
709 throw new VnfException (me);
711 // New with 1607 - more precise handling/messaging if the stack already exists
712 if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
713 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
714 HeatStatus status = heatStack.getStatus();
715 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
716 // fail - it's in progress - return meaningful error
717 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.";
718 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
719 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
720 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
722 if (status == HeatStatus.FAILED) {
723 // fail - it exists and is in a FAILED state
724 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
725 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
726 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
727 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
729 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
730 // fail - it exists and is in a FAILED state
731 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
732 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");
733 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
734 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
736 if (status == HeatStatus.CREATED) {
738 if (failIfExists != null && failIfExists) {
739 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
740 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
741 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
742 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
744 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
745 // Populate the outputs from the existing stack.
746 vnfId.value = heatStack.getCanonicalName ();
747 outputs.value = copyStringOutputs (heatStack.getOutputs ());
748 rollback.value = vfRollback; // Default rollback - no updates performed
751 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
756 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
757 StackInfo nestedHeatStack = null;
758 long subStartTime2 = System.currentTimeMillis ();
759 Map<String, Object> nestedVolumeOutputs = null;
760 if (nestedStackId != null) {
762 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
763 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
764 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
765 } catch (MsoException me) {
766 // Failed to query the Stack due to an openstack exception.
767 // Convert to a generic VnfException
768 me.addContext ("CreateVFModule");
769 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
770 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
771 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
772 LOGGER.debug("ERROR trying to query nested stack= " + error);
773 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
774 throw new VnfException (me);
776 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
777 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
778 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
779 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
781 throw new VnfException (error, MsoExceptionCategory.USERDATA);
783 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
784 //this.sendMapToDebug(inputs);
785 nestedVolumeOutputs = nestedHeatStack.getOutputs();
786 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
788 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
789 //this.sendMapToDebug(inputs);
793 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
794 StackInfo nestedBaseHeatStack = null;
795 long subStartTime3 = System.currentTimeMillis ();
796 Map<String, Object> baseStackOutputs = null;
797 if (nestedBaseStackId != null) {
799 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
800 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
801 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
802 } catch (MsoException me) {
803 // Failed to query the Stack due to an openstack exception.
804 // Convert to a generic VnfException
805 me.addContext ("CreateVFModule");
806 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
807 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
808 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
809 LOGGER.debug("ERROR trying to query nested base stack= " + error);
810 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
811 throw new VnfException (me);
813 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
814 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
815 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");
816 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
818 throw new VnfException (error, MsoExceptionCategory.USERDATA);
820 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
821 //this.sendMapToDebug(inputs);
822 baseStackOutputs = nestedBaseHeatStack.getOutputs();
823 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
825 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
826 //this.sendMapToDebug(inputs);
830 // Ready to deploy the new VNF
832 try (CatalogDatabase db = CatalogDatabase.getInstance()) {
835 VnfResource vnfResource = null;
836 VfModuleCustomization vfmc = null;
837 LOGGER.debug("version: " + vfVersion);
839 // 1707 - db refactoring
840 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
841 vf = vfmc != null ? vfmc.getVfModule() : null;
842 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
843 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
845 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
847 "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
848 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
849 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "",
850 MsoLogger.ErrorCode.DataError,
851 "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
852 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
854 throw new VnfException(error, MsoExceptionCategory.USERDATA);
856 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
859 isBaseRequest = true;
860 LOGGER.debug("This is a BASE VF request!");
862 LOGGER.debug("This is *not* a BASE VF request!");
863 if (!isVolumeRequest && nestedBaseStackId == null) {
865 "DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
869 else { // This is to support gamma only - get info from vnf_resource table
870 if (vfVersion != null && !vfVersion.isEmpty()) {
871 vnfResource = db.getVnfResource(vnfType, vnfVersion);
873 vnfResource = db.getVnfResource(vnfType);
875 if (vnfResource == null) {
876 String error = "Create VNF: Unknown VNF Type: " + vnfType;
877 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
878 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
879 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
880 throw new VnfException(error, MsoExceptionCategory.USERDATA);
882 LOGGER.debug("Got VNF module definition from Catalog: "
883 + vnfResource.toString());
885 // By here - we have either a vf or vnfResource
887 //1607 - Add version check
888 // First - see if it's in the VnfResource record
889 // if we have a vf Module - then we have to query to get the VnfResource record.
891 if (vf.getVnfResourceModelUUId() != null) {
892 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
893 //vnfResource = db.getVnfResourceById(vnfResourceId);
894 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
895 if (vnfResource == null) {
897 "Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
901 String minVersionVnf = null;
902 String maxVersionVnf = null;
903 if (vnfResource != null) {
905 minVersionVnf = vnfResource.getAicVersionMin();
906 maxVersionVnf = vnfResource.getAicVersionMax();
907 } catch (Exception e) {
908 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
909 minVersionVnf = null;
910 maxVersionVnf = null;
912 if (minVersionVnf != null && "".equals(minVersionVnf)) {
913 minVersionVnf = null;
915 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
916 maxVersionVnf = null;
919 if (minVersionVnf != null && maxVersionVnf != null) {
920 MavenLikeVersioning aicV = new MavenLikeVersioning();
921 if (this.cloudConfig == null) {
922 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
925 if (this.cloudConfig != null) {
926 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
927 if (cloudSiteOpt.isPresent()) {
928 aicV.setVersion(cloudSiteOpt.get().getAic_version());
929 // Add code to handle unexpected values in here
930 boolean moreThanMin = true;
931 boolean equalToMin = true;
932 boolean moreThanMax = true;
933 boolean equalToMax = true;
934 boolean doNotTest = false;
936 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
937 equalToMin = aicV.isTheSameVersion(minVersionVnf);
938 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
939 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
940 } catch (Exception e) {
941 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage()
942 + " - will default to not check", e);
946 if ((moreThanMin || equalToMin) // aic >= min
947 && (equalToMax || !(moreThanMax))) { //aic <= max
948 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
949 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf
950 + " supported on Cloud: " + cloudSiteOpt.get().getId() + " with AIC_Version:"
951 + cloudSiteOpt.get().getAic_version());
955 "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource
956 .getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:"
957 + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get().getId()
958 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
959 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
960 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
962 throw new VnfException(error, MsoExceptionCategory.USERDATA);
965 LOGGER.debug("bypassing testing AIC version...");
967 } // let this error out downstream to avoid introducing uncertainty at this stage
969 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
973 "AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
975 // End Version check 1607
977 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
978 // with VNF_RESOURCE - we use the old methods.
979 //Integer heatTemplateId = null;
980 //Integer heatEnvtId = null;
982 String heatTemplateArtifactUuid = null;
983 String heatEnvironmentArtifactUuid = null;
986 if (isVolumeRequest) {
987 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
988 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
990 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
991 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
994 if (isVolumeRequest) {
995 LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
997 heatTemplateArtifactUuid = vnfResource.getTemplateId();
998 heatEnvironmentArtifactUuid = null;
1001 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1002 HeatTemplate heatTemplate = null;
1003 if (heatTemplateArtifactUuid == null || "".equals(heatTemplateArtifactUuid)) {
1004 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1005 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1006 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1007 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1008 MsoAlarmLogger.CRITICAL, error);
1009 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1011 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1013 if (heatTemplate == null) {
1014 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1015 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1017 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1018 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1019 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1020 MsoAlarmLogger.CRITICAL, error);
1021 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1023 LOGGER.debug("Got HEAT Template from DB");
1025 HeatEnvironment heatEnvironment = null;
1026 String heatEnvironmentString = null;
1028 if (heatEnvironmentArtifactUuid != null && !"".equals(heatEnvironmentArtifactUuid)) {
1029 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1030 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1031 if (heatEnvironment == null) {
1032 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1033 + ", Environment ID="
1034 + heatEnvironmentArtifactUuid;
1035 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1036 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment",
1037 MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1038 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1040 // Alarm on this error, configuration must be fixed
1041 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1043 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1045 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1046 heatEnvironmentString = heatEnvironment
1047 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1048 LOGGER.debug("after parsing: " + heatEnvironmentString);
1051 LOGGER.debug("no environment parameter found for this Type " + vfModuleType);
1054 // 1510 - Add the files: for nested templates *if* there are any
1055 LOGGER.debug("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1056 + heatTemplate.getArtifactUuid());
1057 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1058 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1059 if (nestedTemplates != null) {
1060 // for debugging print them out
1061 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1062 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1063 String providerResourceFile = entry.getKey();
1064 Object value = entry.getValue();
1065 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1066 String childTemplateBody = (String) value;
1067 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1068 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1071 LOGGER.debug("No nested templates found - nothing to do here");
1072 nestedTemplatesChecked = null; // just to make sure
1075 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1076 // *if* there are any
1077 Map<String, HeatFiles> heatFiles = null;
1078 Map<String, Object> heatFilesObjects = new HashMap<>();
1080 // Add ability to turn on adding get_files with volume requests (by property).
1081 boolean addGetFilesOnVolumeReq = false;
1083 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1084 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1085 addGetFilesOnVolumeReq = true;
1086 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1088 } catch (Exception e) {
1089 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1092 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1094 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1095 //heatFiles = db.getHeatFiles(vnfResource.getId());
1097 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1098 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1099 + vf.getModelUUID());
1101 .getHeatFilesForVfModule(vf.getModelUUID());
1103 if (heatFiles != null) {
1104 // add these to stack - to be done in createStack
1105 // here, we will map them to Map<String, Object> from
1106 // Map<String, HeatFiles>
1107 // this will match the nested templates format
1108 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1110 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1111 String heatFileName = entry.getKey();
1112 HeatFiles value = entry.getValue();
1113 if (heatFileName.startsWith("_ERROR|")) {
1114 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1115 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1116 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1117 LOGGER.debug(error);
1118 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1119 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1120 // Alarm on this error, configuration must be fixed
1121 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1122 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1124 String heatFileBody = value.getFileBody();
1125 String heatFileNameChecked = heatFileName;
1126 LOGGER.debug(heatFileNameChecked + " -> "
1128 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1131 LOGGER.debug("No heat files found -nothing to do here");
1132 heatFilesObjects = null;
1135 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1138 // Check that required parameters have been supplied
1139 StringBuilder missingParams = null;
1140 List <String> paramList = new ArrayList <> ();
1142 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1143 // supplied an alias. Only check if we don't find it initially.
1144 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1145 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1147 boolean checkRequiredParameters = true;
1149 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1150 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1151 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1152 checkRequiredParameters = false;
1153 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1154 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1156 } catch (Exception e) {
1157 // No problem - default is true
1158 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1160 // 1604 - Add enhanced environment & parameter checking
1161 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1162 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1163 // Note this also removes any comments
1164 MsoHeatEnvironmentEntry mhee = null;
1165 if (heatEnvironmentString != null && heatEnvironmentString.contains("parameters:")) {
1166 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1167 LOGGER.debug("Enhanced environment checking enabled - 1604");
1168 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1169 //LOGGER.debug("About to create MHEE with " + sb);
1170 mhee = new MsoHeatEnvironmentEntry(sb);
1171 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1172 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1173 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1175 if (!mhee.isValid()) {
1176 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1178 sb2.append("\nEnvironment:");
1181 LOGGER.debug(sb2.toString());
1183 LOGGER.debug("NO ENVIRONMENT for this entry");
1185 // New with 1707 - all variables converted to their native object types
1186 HashMap<String, Object> goldenInputs = null;
1188 LOGGER.debug("Now handle the inputs....first convert");
1189 ArrayList<String> parameterNames = new ArrayList<>();
1190 HashMap<String, String> aliasToParam = new HashMap<>();
1191 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1194 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1195 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1196 parameterNames.add(htp.getParamName());
1197 if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) {
1198 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1199 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1203 LOGGER.debug(sb.toString());
1204 } catch (Exception e) {
1205 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e);
1207 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1208 // Map<String, Object> - where the object matches the param type identified in the template
1209 // This will also not copy over params that aren't identified in the template
1210 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1211 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1212 LOGGER.debug("Now add in the base stack outputs if applicable");
1213 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1214 // Step 3 - add the volume inputs if any
1215 LOGGER.debug("Now add in the volume stack outputs if applicable");
1216 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1217 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1219 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1220 LOGGER.debug("Parameter:'" + parm.getParamName()
1224 + parm.getParamAlias());
1226 if (parm.isRequired() && (goldenInputs == null || !goldenInputs.containsKey(parm.getParamName()))) {
1227 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1228 LOGGER.debug("**Parameter " + parm.getParamName()
1229 + " is required and not in the inputs...check environment");
1230 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1231 LOGGER.debug("Required parameter " + parm.getParamName()
1232 + " appears to be in environment - do not count as missing");
1234 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
1235 if (missingParams == null) {
1236 missingParams = new StringBuilder(parm.getParamName());
1238 missingParams.append("," + parm.getParamName());
1242 paramList.add(parm.getParamName());
1244 if (missingParams != null) {
1245 if (checkRequiredParameters) {
1246 // Problem - missing one or more required parameters
1247 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1248 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
1249 MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1250 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1252 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1254 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
1257 LOGGER.debug("No missing parameters found - ok to proceed");
1259 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1260 // and it causes problems with json that has arrays
1261 String newEnvironmentString = null;
1263 newEnvironmentString = mhee.getRawEntry().toString();
1266 // "Fix" the template if it has CR/LF (getting this from Oracle)
1267 String template = heatTemplate.getHeatTemplate();
1268 template = template.replaceAll("\r\n", "\n");
1270 // Have the tenant. Now deploy the stack itself
1271 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1272 // because we already checked for those.
1273 long createStackStarttime = System.currentTimeMillis();
1275 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1276 // heatTemplate.getTimeoutMinutes());
1277 if (backout == null) {
1281 LOGGER.debug("heat is not null!!");
1283 heatStack = heat.createStack(cloudSiteId,
1289 heatTemplate.getTimeoutMinutes(),
1290 newEnvironmentString,
1291 nestedTemplatesChecked,
1293 backout.booleanValue());
1295 .recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
1296 "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1297 } catch (MsoException me) {
1298 me.addContext("CreateVFModule");
1299 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1300 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1301 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1302 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1303 MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1305 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1307 throw new VnfException(me);
1308 } catch (NullPointerException npe) {
1309 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1310 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1311 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1312 LOGGER.error(MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
1313 MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1315 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1317 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1318 //npe.addContext ("CreateVNF");
1319 throw new VnfException("NullPointerException during heat.createStack");
1320 } catch (Exception e) {
1321 LOGGER.recordMetricEvent(createStackStarttime, MsoLogger.StatusCode.ERROR,
1322 MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack",
1323 "OpenStack", "CreateStack", vfModuleName);
1324 LOGGER.debug("unhandled exception at heat.createStack", e);
1326 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
1327 "Exception while creating stack with OpenStack");
1328 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1330 } catch (Exception e) {
1331 LOGGER.debug("unhandled exception in create VF", e);
1332 throw new VnfException("Exception during create VF " + e.getMessage());
1335 // Make sure DB session is closed
1337 // Reach this point if createStack is successful.
1338 // Populate remaining rollback info and response parameters.
1339 vfRollback.setVnfId (heatStack.getCanonicalName ());
1340 vfRollback.setVnfCreated (true);
1342 vnfId.value = heatStack.getCanonicalName ();
1343 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1344 rollback.value = vfRollback;
1346 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1347 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1351 public void deleteVfModule (String cloudSiteId,
1354 MsoRequest msoRequest,
1355 Holder <Map <String, String>> outputs) throws VnfException {
1356 MsoLogger.setLogContext (msoRequest);
1357 MsoLogger.setServiceName ("DeleteVf");
1358 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1359 // Will capture execution time for metrics
1360 long startTime = System.currentTimeMillis ();
1362 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1364 // 1702 capture the output parameters on a delete
1365 // so we'll need to query first
1366 Map<String, Object> stackOutputs = null;
1368 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1369 } catch (MsoException me) {
1370 // Failed to query the Stack due to an openstack exception.
1371 // Convert to a generic VnfException
1372 me.addContext ("DeleteVFModule");
1373 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1374 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1375 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1376 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1377 throw new VnfException (me);
1379 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1380 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1382 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1383 // The possible outcomes of deleteStack are a StackInfo object with status
1384 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1386 long subStartTime = System.currentTimeMillis ();
1388 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1389 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1390 } catch (MsoException me) {
1391 me.addContext ("DeleteVNF");
1392 // Failed to query the Stack due to an openstack exception.
1393 // Convert to a generic VnfException
1394 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1395 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1396 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1397 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1398 throw new VnfException (me);
1401 // On success, nothing is returned.
1402 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1406 public void updateVfModule (String cloudSiteId,
1412 String volumeGroupHeatStackId,
1413 String baseVfHeatStackId,
1414 String vfModuleStackId,
1415 String modelCustomizationUuid,
1416 Map <String, String> inputs,
1417 MsoRequest msoRequest,
1418 Holder <Map <String, String>> outputs,
1419 Holder <VnfRollback> rollback) throws VnfException {
1420 String vfModuleName = vnfName;
1421 String vfModuleType = vnfType;
1422 String methodName = "updateVfModule";
1423 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1424 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1425 MsoLogger.setServiceName (serviceName);
1427 String strInit = "updateVfModule: cloudSiteId=" + cloudSiteId +
1428 ",tenantId=" + tenantId +
1429 ",vnfType=" + vnfType +
1430 ",vnfVersion=" + vnfVersion +
1431 ",vnfName=" + vnfName +
1432 ",requestType=" + requestType +
1433 ",volumeGroupHeatStackId=" + volumeGroupHeatStackId +
1434 ",baseVfHeatStackId=" + baseVfHeatStackId +
1435 ",vfModuleStackId=" + vfModuleStackId +
1436 ",modelCustomizationUuid=" + modelCustomizationUuid;
1437 LOGGER.debug(strInit);
1439 String mcu = modelCustomizationUuid;
1440 boolean useMCUuid = false;
1441 if (mcu != null && !mcu.isEmpty()) {
1442 if (mcu.equalsIgnoreCase("null")) {
1443 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1447 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1452 String requestTypeString = "";
1453 if (requestType != null && !"".equals(requestType)) {
1454 requestTypeString = requestType;
1456 String nestedStackId = null;
1457 if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId)) {
1458 if (!"null".equalsIgnoreCase(volumeGroupHeatStackId)) {
1459 nestedStackId = volumeGroupHeatStackId;
1462 String nestedBaseStackId = null;
1463 if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId)) {
1464 if (!"null".equalsIgnoreCase(baseVfHeatStackId)) {
1465 nestedBaseStackId = baseVfHeatStackId;
1469 if (inputs == null) {
1470 // Create an empty set of inputs
1471 inputs = new HashMap<>();
1472 LOGGER.debug("inputs == null - setting to empty");
1474 this.sendMapToDebug(inputs);
1476 boolean isBaseRequest = false;
1477 boolean isVolumeRequest = false;
1478 if (requestTypeString.startsWith("VOLUME")) {
1479 isVolumeRequest = true;
1481 if (vfModuleName == null || "".equals(vfModuleName.trim())) {
1482 if (vfModuleStackId != null) {
1483 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1487 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1488 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1490 // Will capture execution time for metrics
1491 long startTime = System.currentTimeMillis ();
1493 // Build a default rollback object (no actions performed)
1494 VnfRollback vfRollback = new VnfRollback ();
1495 vfRollback.setCloudSiteId (cloudSiteId);
1496 vfRollback.setTenantId (tenantId);
1497 vfRollback.setMsoRequest (msoRequest);
1498 vfRollback.setRequestType(requestTypeString);
1499 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1500 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1501 vfRollback.setIsBase(isBaseRequest);
1502 vfRollback.setVfModuleStackId(vfModuleStackId);
1503 vfRollback.setModelCustomizationUuid(mcu);
1505 // First, look up to see if the VNF already exists.
1506 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1507 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1509 StackInfo heatStack = null;
1510 long queryStackStarttime = System.currentTimeMillis ();
1511 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1513 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1514 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1515 } catch (MsoException me) {
1516 // Failed to query the Stack due to an openstack exception.
1517 // Convert to a generic VnfException
1518 me.addContext ("UpdateVFModule");
1519 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1520 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1521 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1522 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1523 throw new VnfException (me);
1526 //TODO - do we need to check for the other status possibilities?
1527 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1529 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1530 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1531 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1532 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1534 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1535 // Populate the outputs from the existing stack.
1536 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1537 rollback.value = vfRollback; // Default rollback - no updates performed
1540 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1541 StackInfo nestedHeatStack = null;
1542 long queryStackStarttime2 = System.currentTimeMillis ();
1543 Map<String, Object> nestedVolumeOutputs = null;
1544 if (nestedStackId != null) {
1546 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1547 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1548 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1549 } catch (MsoException me) {
1550 // Failed to query the Stack due to an openstack exception.
1551 // Convert to a generic VnfException
1552 me.addContext ("UpdateVFModule");
1553 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1554 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1555 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1556 LOGGER.debug("ERROR trying to query nested stack= " + error);
1557 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1558 throw new VnfException (me);
1560 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1561 MsoLogger.setServiceName (serviceName);
1562 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1563 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1564 LOGGER.debug(error);
1565 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1566 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1568 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1569 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1570 //this.sendMapToDebug(inputs);
1571 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1573 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1574 //this.sendMapToDebug(inputs);
1577 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1578 StackInfo nestedBaseHeatStack = null;
1579 Map<String, Object> baseStackOutputs = null;
1580 if (nestedBaseStackId != null) {
1581 long queryStackStarttime3 = System.currentTimeMillis ();
1583 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1584 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1585 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1586 } catch (MsoException me) {
1587 // Failed to query the Stack due to an openstack exception.
1588 // Convert to a generic VnfException
1589 me.addContext ("UpdateVfModule");
1590 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1591 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1592 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1593 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1594 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1595 throw new VnfException (me);
1597 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1598 MsoLogger.setServiceName (serviceName);
1599 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1600 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1601 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1602 LOGGER.debug(error);
1603 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1605 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1606 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1607 //this.sendMapToDebug(inputs);
1608 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1610 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1611 //this.sendMapToDebug(inputs);
1615 // Ready to deploy the new VNF
1617 // Get a handle to the Catalog Database
1619 // Make sure DB session is closed
1620 try (CatalogDatabase db = CatalogDatabase.getInstance()) {
1621 // Retrieve the VF definition
1622 VnfResource vnfResource = null;
1624 VfModuleCustomization vfmc = null;
1626 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1627 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1628 vf = vfmc != null ? vfmc.getVfModule() : null;
1630 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1633 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1636 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1637 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "",
1638 MsoLogger.ErrorCode.DataError, error);
1639 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1640 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1642 LOGGER.debug("Got VF module definition from Catalog: " + vf.toString());
1644 isBaseRequest = true;
1645 LOGGER.debug("This a BASE update request");
1647 LOGGER.debug("This is *not* a BASE VF update request");
1648 if (!isVolumeRequest && nestedBaseStackId == null) {
1649 LOGGER.debug("This is unexpected - no nestedBaseStackId with this non-base request");
1653 //1607 - Add version check
1654 // First - see if it's in the VnfResource record
1655 // if we have a vf Module - then we have to query to get the VnfResource record.
1656 if (vf.getVnfResourceModelUUId() != null) {
1657 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1658 //vnfResource = db.getVnfResourceById(vnfResourceId);
1659 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1660 if (vnfResource == null) {
1662 .debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1665 String minVersionVnf = null;
1666 String maxVersionVnf = null;
1667 if (vnfResource != null) {
1669 minVersionVnf = vnfResource.getAicVersionMin();
1670 maxVersionVnf = vnfResource.getAicVersionMax();
1671 } catch (Exception e) {
1672 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry", e);
1673 minVersionVnf = null;
1674 maxVersionVnf = null;
1676 if (minVersionVnf != null && "".equals(minVersionVnf)) {
1677 minVersionVnf = null;
1679 if (maxVersionVnf != null && "".equals(maxVersionVnf)) {
1680 maxVersionVnf = null;
1683 if (minVersionVnf != null && maxVersionVnf != null) {
1684 MavenLikeVersioning aicV = new MavenLikeVersioning();
1685 //String aicVersion = "";
1686 if (this.cloudConfig == null) {
1687 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1690 if (this.cloudConfig != null) {
1691 Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId);
1692 if (cloudSiteOpt.isPresent()) {
1693 aicV.setVersion(cloudSiteOpt.get().getAic_version());
1694 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1695 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV
1696 .isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1697 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1698 + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteOpt.get().getId()
1699 + " with AIC_Version:" + cloudSiteOpt.get().getAic_version());
1703 "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf
1704 + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteOpt.get()
1705 .getId() + " with AIC_Version:" + cloudSiteOpt.get().getAic_version();
1706 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1707 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1708 LOGGER.debug(error);
1709 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1711 } // let this error out downstream to avoid introducing uncertainty at this stage
1713 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1717 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1719 // End Version check 1607
1721 String heatTemplateArtifactUuid = null;
1722 String heatEnvironmentArtifactUuid = null;
1724 HeatTemplate heatTemplate = null;
1725 if (isVolumeRequest) {
1726 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1727 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1729 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1730 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1732 if (heatTemplateArtifactUuid == null) {
1734 "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType="
1735 + requestTypeString;
1736 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "",
1737 MsoLogger.ErrorCode.DataError, error);
1738 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1740 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1741 MsoAlarmLogger.CRITICAL, error);
1742 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1744 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1747 if (heatTemplate == null) {
1748 String error = "Update VNF: undefined Heat Template. VF="
1749 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1750 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1752 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1753 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1755 // Alarm on this error, configuration must be fixed
1756 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1757 MsoAlarmLogger.CRITICAL, error);
1759 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1762 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1764 // Add check for any Environment variable
1765 HeatEnvironment heatEnvironment = null;
1766 String heatEnvironmentString = null;
1768 if (heatEnvironmentArtifactUuid != null) {
1769 LOGGER.debug("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1770 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1771 if (heatEnvironment == null) {
1773 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1774 + ", Environment ID="
1775 + heatEnvironmentArtifactUuid;
1776 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID",
1777 String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError,
1779 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
1781 // Alarm on this error, configuration must be fixed
1782 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1784 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1786 LOGGER.debug("Got Heat Environment from DB: " + heatEnvironment.toString());
1787 heatEnvironmentString = heatEnvironment
1788 .getEnvironment(); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1789 LOGGER.debug("After parsing: " + heatEnvironmentString);
1792 LOGGER.debug("no environment parameter for this VFModuleType " + vfModuleType);
1795 LOGGER.debug("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1796 + heatTemplate.getArtifactUuid());
1797 Map<String, Object> nestedTemplates = db.getNestedTemplates(heatTemplate.getArtifactUuid());
1798 Map<String, Object> nestedTemplatesChecked = new HashMap<>();
1799 if (nestedTemplates != null) {
1800 // for debugging print them out
1801 LOGGER.debug("Contents of nestedTemplates - to be added to files: on stack:");
1802 for (Map.Entry<String, Object> entry : nestedTemplates.entrySet()) {
1803 String providerResourceFile = entry.getKey();
1804 Object value = entry.getValue();
1805 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1806 String childTemplateBody = (String) value;
1807 nestedTemplatesChecked.put(providerResourceFileChecked, childTemplateBody);
1808 LOGGER.debug(providerResourceFileChecked + " -> " + childTemplateBody);
1811 LOGGER.debug("No nested templates found - nothing to do here");
1812 nestedTemplatesChecked = null;
1815 // Also add the files: for any get_files associated with this VfModule
1816 // *if* there are any
1817 LOGGER.debug("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1818 + vf.getModelUUID());
1820 Map<String, HeatFiles> heatFiles = null;
1821 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1822 Map<String, Object> heatFilesObjects = new HashMap<>();
1824 // Add ability to turn on adding get_files with volume requests (by property).
1825 boolean addGetFilesOnVolumeReq = false;
1827 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1828 .getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1829 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1830 addGetFilesOnVolumeReq = true;
1831 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1833 } catch (Exception e) {
1834 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ
1835 + " - default to false", e);
1837 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1839 "In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1840 + vf.getModelUUID());
1842 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1843 if (heatFiles != null) {
1844 // add these to stack - to be done in createStack
1845 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1846 // this will match the nested templates format
1847 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1849 for (Map.Entry<String, HeatFiles> entry : heatFiles.entrySet()) {
1850 String heatFileName = entry.getKey();
1851 HeatFiles value = entry.getValue();
1852 if (heatFileName.startsWith("_ERROR|")) {
1853 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1854 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|") + 1);
1855 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType
1856 + " at HEAT_FILES index=" + heatFileId;
1857 LOGGER.debug(error);
1859 .error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId,
1860 vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1861 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1862 MsoLogger.ResponseCode.DataNotFound, error);
1863 // Alarm on this error, configuration must be fixed
1864 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1865 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1867 String heatFileBody = value.getFileBody();
1868 LOGGER.debug(heatFileName + " -> " + heatFileBody);
1869 heatFilesObjects.put(heatFileName, heatFileBody);
1872 LOGGER.debug("No heat files found -nothing to do here");
1873 heatFilesObjects = null;
1877 // Check that required parameters have been supplied
1878 StringBuilder missingParams = null;
1879 List<String> paramList = new ArrayList<>();
1881 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1882 // supplied an alias. Only check if we don't find it initially.
1883 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1884 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1886 boolean haveEnvironmentParameters = false;
1887 boolean checkRequiredParameters = true;
1889 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER)
1890 .getProperty(MsoVnfAdapterImpl.CHECK_REQD_PARAMS, null);
1891 if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) {
1892 checkRequiredParameters = false;
1893 LOGGER.debug("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1894 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1896 } catch (Exception e) {
1897 // No problem - default is true
1898 LOGGER.debug("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1900 // 1604 - Add enhanced environment & parameter checking
1901 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1902 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1903 // Note this also removes any comments
1904 MsoHeatEnvironmentEntry mhee = null;
1905 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase().contains("parameters:")) {
1906 LOGGER.debug("Enhanced environment checking enabled - 1604");
1907 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1908 //LOGGER.debug("About to create MHEE with " + sb);
1909 mhee = new MsoHeatEnvironmentEntry(sb);
1910 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1911 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1912 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1914 if (!mhee.isValid()) {
1915 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1917 sb2.append("\nEnvironment:");
1920 LOGGER.debug(sb2.toString());
1922 LOGGER.debug("NO ENVIRONMENT for this entry");
1925 // New for 1607 - support params of json type
1926 HashMap<String, JsonNode> jsonParams = new HashMap<>();
1927 boolean hasJson = false;
1929 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1930 LOGGER.debug("Parameter:'" + parm.getParamName()
1934 + parm.getParamAlias());
1936 String parameterType = parm.getParamType();
1937 if (parameterType == null || "".equals(parameterType.trim())) {
1938 parameterType = "String";
1940 JsonNode jsonNode = null;
1941 if ("json".equalsIgnoreCase(parameterType) && inputs != null) {
1942 if (inputs.containsKey(parm.getParamName())) {
1944 String jsonString = null;
1946 jsonString = inputs.get(parm.getParamName());
1947 jsonNode = new ObjectMapper().readTree(jsonString);
1948 } catch (JsonParseException jpe) {
1949 //TODO - what to do here?
1950 //for now - send the error to debug, but just leave it as a String
1951 String errorMessage = jpe.getMessage();
1952 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1955 } catch (Exception e) {
1957 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1961 if (jsonNode != null) {
1962 jsonParams.put(parm.getParamName(), jsonNode);
1964 } else if (inputs.containsKey(parm.getParamAlias())) {
1966 String jsonString = null;
1968 jsonString = inputs.get(parm.getParamAlias());
1969 jsonNode = new ObjectMapper().readTree(jsonString);
1970 } catch (JsonParseException jpe) {
1971 //TODO - what to do here?
1972 //for now - send the error to debug, but just leave it as a String
1973 String errorMessage = jpe.getMessage();
1974 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage, jpe);
1977 } catch (Exception e) {
1979 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(), e);
1983 if (jsonNode != null) {
1984 // Notice here - we add it to the jsonParams hashMap with the actual name -
1985 // then manipulate the inputs so when we check for aliases below - it will not
1987 jsonParams.put(parm.getParamName(), jsonNode);
1988 inputs.remove(parm.getParamAlias());
1989 inputs.put(parm.getParamName(), jsonString);
1991 } //TODO add a check for the parameter in the env file
1994 if (parm.isRequired() && (inputs == null || !inputs.containsKey(parm.getParamName()))) {
1995 if (inputs.containsKey(parm.getParamAlias())) {
1996 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
1997 String realParamName = parm.getParamName();
1998 String alias = parm.getParamAlias();
1999 String value = inputs.get(alias);
2000 LOGGER.debug("*Found an Alias: paramName=" + realParamName
2005 inputs.remove(alias);
2006 inputs.put(realParamName, value);
2007 LOGGER.debug(alias + " entry removed from inputs, added back using " + realParamName);
2009 // enhanced - check if it's in the Environment (note: that method
2010 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2012 LOGGER.debug("Required parameter " + parm.getParamName()
2013 + " appears to be in environment - do not count as missing");
2015 LOGGER.debug("adding to missing parameters list: " + parm.getParamName());
2016 if (missingParams == null) {
2017 missingParams = new StringBuilder(parm.getParamName());
2019 missingParams.append("," + parm.getParamName());
2023 paramList.add(parm.getParamName());
2025 if (missingParams != null) {
2026 // Problem - missing one or more required parameters
2027 if (checkRequiredParameters) {
2028 String error = "Update VNF: Missing Required inputs: " + missingParams;
2029 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missingParams.toString(), "OpenStack", "",
2030 MsoLogger.ErrorCode.DataError, error);
2031 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
2033 throw new VnfException(error, MsoExceptionCategory.USERDATA);
2035 LOGGER.debug("found missing parameters - but checkRequiredParameters is false - will not block");
2038 LOGGER.debug("No missing parameters found - ok to proceed");
2041 // Just submit the envt entry as received from the database
2042 String newEnvironmentString = null;
2044 newEnvironmentString = mhee.getRawEntry().toString();
2047 // Remove any extraneous parameters (don't throw an error)
2048 if (inputs != null) {
2049 List<String> extraParams = new ArrayList<>();
2050 extraParams.addAll(inputs.keySet());
2051 // This is not a valid parameter for this template
2052 extraParams.removeAll(paramList);
2053 if (!extraParams.isEmpty()) {
2054 LOGGER.warn(MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "",
2055 MsoLogger.ErrorCode.DataError, "Extra params");
2056 inputs.keySet().removeAll(extraParams);
2059 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2060 Map<String, Object> inputsTwo = null;
2061 if (hasJson && jsonParams.size() > 0) {
2062 inputsTwo = new HashMap<>();
2063 for (Map.Entry<String, String> entry : inputs.entrySet()) {
2064 String keyParamName = entry.getKey();
2065 String value = entry.getValue();
2066 if (jsonParams.containsKey(keyParamName)) {
2067 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2069 inputsTwo.put(keyParamName, value);
2074 // "Fix" the template if it has CR/LF (getting this from Oracle)
2075 String template = heatTemplate.getHeatTemplate();
2076 template = template.replaceAll("\r\n", "\n");
2078 // Have the tenant. Now deploy the stack itself
2079 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2080 // because we already checked for those.
2081 long updateStackStarttime = System.currentTimeMillis();
2084 heatStack = heatU.updateStack(cloudSiteId,
2088 copyStringInputs(inputs),
2090 heatTemplate.getTimeoutMinutes(),
2091 newEnvironmentString,
2092 //heatEnvironmentString,
2093 nestedTemplatesChecked,
2095 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2096 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2097 "UpdateStack", null);
2099 heatStack = heatU.updateStack(cloudSiteId,
2105 heatTemplate.getTimeoutMinutes(),
2106 newEnvironmentString,
2107 //heatEnvironmentString,
2108 nestedTemplatesChecked,
2110 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
2111 MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack",
2112 "UpdateStack", null);
2114 } catch (MsoException me) {
2115 me.addContext("UpdateVFModule");
2116 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2117 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.ERROR,
2118 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2119 LOGGER.error(MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "",
2120 MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2122 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError,
2124 throw new VnfException(me);
2127 // Make sure DB session is closed
2129 // Reach this point if updateStack is successful.
2130 // Populate remaining rollback info and response parameters.
2131 vfRollback.setVnfId (heatStack.getCanonicalName ());
2132 vfRollback.setVnfCreated (true);
2134 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2135 rollback.value = vfRollback;
2136 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2139 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2140 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2141 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2142 if (vfModuleStackId == null)
2144 int index = vfModuleStackId.lastIndexOf('/');
2147 String vfModuleName = null;
2149 vfModuleName = vfModuleStackId.substring(0, index);
2150 } catch (Exception e) {
2151 LOGGER.debug("Exception", e);
2152 vfModuleName = null;
2154 return vfModuleName;