2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.mso.adapters.vnf;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
28 import java.util.Scanner;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
32 import javax.jws.WebService;
33 import javax.xml.ws.Holder;
35 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
36 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
37 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
38 import org.openecomp.mso.cloud.CloudConfigFactory;
39 import org.openecomp.mso.cloud.CloudConfig;
40 import org.openecomp.mso.cloud.CloudSite;
41 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
42 import org.openecomp.mso.db.catalog.CatalogDatabase;
43 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
44 import org.openecomp.mso.db.catalog.beans.HeatFiles;
45 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
46 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
47 import org.openecomp.mso.db.catalog.beans.VnfResource;
48 import org.openecomp.mso.db.catalog.beans.VfModule;
49 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
50 import org.openecomp.mso.db.catalog.beans.VnfComponent;
51 import org.openecomp.mso.entity.MsoRequest;
52 import org.openecomp.mso.logger.MessageEnum;
53 import org.openecomp.mso.logger.MsoAlarmLogger;
54 import org.openecomp.mso.logger.MsoLogger;
55 import org.openecomp.mso.openstack.beans.HeatStatus;
56 import org.openecomp.mso.openstack.beans.StackInfo;
57 import org.openecomp.mso.openstack.beans.VnfStatus;
58 import org.openecomp.mso.openstack.beans.VnfRollback;
59 import org.openecomp.mso.openstack.exceptions.MsoException;
60 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
61 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
62 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
63 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
64 import org.openecomp.mso.properties.MsoPropertiesFactory;
66 import org.codehaus.jackson.JsonNode;
67 import org.codehaus.jackson.JsonParseException;
68 import org.codehaus.jackson.map.ObjectMapper;
70 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
71 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
73 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
74 protected CloudConfig cloudConfig = null;
76 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
78 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
79 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
80 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
81 private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN.";
82 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
83 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
84 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
85 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
86 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
89 * Health Check web method. Does nothing but return to show the adapter is deployed.
92 public void healthCheck () {
93 LOGGER.debug ("Health check call in VNF Adapter");
97 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
98 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
100 public MsoVnfAdapterImpl() {
105 * This constructor MUST be used if this class is called with the new operator.
106 * @param msoPropFactory
108 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
109 this.msoPropertiesFactory = msoPropFactory;
110 this.cloudConfigFactory = cloudConfigFact;
114 * This is the "Create VNF" web service implementation.
115 * It will create a new VNF of the requested type in the specified cloud
116 * and tenant. The tenant must exist before this service is called.
118 * If a VNF with the same name already exists, this can be considered a
119 * success or failure, depending on the value of the 'failIfExists' parameter.
121 * All VNF types will be defined in the MSO catalog. The caller must request
122 * one of these pre-defined types or an error will be returned. Within the
123 * catalog, each VNF type references (among other things) a Heat template
124 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
127 * Depending on the Heat template, a variable set of input parameters will
128 * be defined, some of which are required. The caller is responsible to
129 * pass the necessary input data for the VNF or an error will be thrown.
131 * The method returns the vnfId (the canonical name), a Map of VNF output
132 * attributes, and a VnfRollback object. This last object can be passed
133 * as-is to the rollbackVnf operation to undo everything that was created
134 * for the VNF. This is useful if a VNF is successfully created but the
135 * orchestrator fails on a subsequent operation.
137 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
138 * @param tenantId Openstack tenant identifier
139 * @param vnfType VNF type key, should match a VNF definition in catalog DB
140 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
141 * @param vnfName Name to be assigned to the new VNF
142 * @param inputs Map of key=value inputs for VNF stack creation
143 * @param failIfExists Flag whether already existing VNF should be considered
144 * a success or failure
145 * @param msoRequest Request tracking information for logs
146 * @param vnfId Holder for output VNF Openstack ID
147 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
148 * @param rollback Holder for returning VnfRollback object
151 public void createVnf (String cloudSiteId,
157 String volumeGroupHeatStackId,
158 Map <String, String> inputs,
159 Boolean failIfExists,
161 MsoRequest msoRequest,
162 Holder <String> vnfId,
163 Holder <Map <String, String>> outputs,
164 Holder <VnfRollback> rollback) throws VnfException {
165 // Create a hook here to catch shortcut createVf requests:
166 if (requestType != null) {
167 if (requestType.startsWith("VFMOD")) {
168 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
169 String newRequestType = requestType.substring(5);
170 String vfVolGroupHeatStackId = "";
171 String vfBaseHeatStackId = "";
173 if (volumeGroupHeatStackId != null) {
174 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
175 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
177 } catch (Exception e) {
178 // might be ok - both are just blank
179 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId);
181 this.createVfModule(cloudSiteId,
187 vfVolGroupHeatStackId,
200 // createVf will know if the requestType starts with "X" that it's the "old" way
201 StringBuilder newRequestTypeSb = new StringBuilder("X");
202 String vfVolGroupHeatStackId = "";
203 String vfBaseHeatStackId = "";
204 if (requestType != null) {
205 newRequestTypeSb.append(requestType);
207 this.createVfModule(cloudSiteId,
212 newRequestTypeSb.toString(),
213 vfVolGroupHeatStackId,
224 // End createVf shortcut
228 public void updateVnf (String cloudSiteId,
234 String volumeGroupHeatStackId,
235 Map <String, String> inputs,
236 MsoRequest msoRequest,
237 Holder <Map <String, String>> outputs,
238 Holder <VnfRollback> rollback) throws VnfException {
239 // As of 1707 - this method should no longer be called
240 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
241 MsoLogger.setServiceName ("UpdateVnf");
242 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
246 * This is the "Query VNF" web service implementation.
247 * It will look up a VNF by name or ID in the specified cloud and tenant.
249 * The method returns an indicator that the VNF exists, its Openstack internal
250 * ID, its status, and the set of outputs (from when the stack was created).
252 * @param cloudSiteId CLLI code of the cloud site in which to query
253 * @param tenantId Openstack tenant identifier
254 * @param vnfName VNF Name or Openstack ID
255 * @param msoRequest Request tracking information for logs
256 * @param vnfExists Flag reporting the result of the query
257 * @param vnfId Holder for output VNF Openstack ID
258 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
261 public void queryVnf (String cloudSiteId,
264 MsoRequest msoRequest,
265 Holder <Boolean> vnfExists,
266 Holder <String> vnfId,
267 Holder <VnfStatus> status,
268 Holder <Map <String, String>> outputs) throws VnfException {
269 MsoLogger.setLogContext (msoRequest);
270 MsoLogger.setServiceName ("QueryVnf");
271 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
273 // Will capture execution time for metrics
274 long startTime = System.currentTimeMillis ();
276 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
278 StackInfo heatStack = null;
279 long subStartTime = System.currentTimeMillis ();
281 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
282 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
283 } catch (MsoException me) {
284 me.addContext ("QueryVNF");
285 // Failed to query the Stack due to an openstack exception.
286 // Convert to a generic VnfException
287 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
288 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
289 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
290 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
291 throw new VnfException (me);
294 // Populate the outputs based on the returned Stack information
296 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
298 vnfExists.value = Boolean.FALSE;
299 status.value = VnfStatus.NOTFOUND;
301 outputs.value = new HashMap <String, String> (); // Return as an empty map
303 LOGGER.debug ("VNF " + vnfName + " not found");
305 vnfExists.value = Boolean.TRUE;
306 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
307 vnfId.value = heatStack.getCanonicalName ();
308 outputs.value = copyStringOutputs (heatStack.getOutputs ());
310 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
312 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
317 * This is the "Delete VNF" web service implementation.
318 * It will delete a VNF by name or ID in the specified cloud and tenant.
320 * The method has no outputs.
322 * @param cloudSiteId CLLI code of the cloud site in which to delete
323 * @param tenantId Openstack tenant identifier
324 * @param vnfName VNF Name or Openstack ID
325 * @param msoRequest Request tracking information for logs
328 public void deleteVnf (String cloudSiteId,
331 MsoRequest msoRequest) throws VnfException {
332 MsoLogger.setLogContext (msoRequest);
333 MsoLogger.setServiceName ("DeleteVnf");
334 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
335 // Will capture execution time for metrics
336 long startTime = System.currentTimeMillis ();
338 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
340 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
341 // The possible outcomes of deleteStack are a StackInfo object with status
342 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
344 long subStartTime = System.currentTimeMillis ();
346 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
347 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
348 } catch (MsoException me) {
349 me.addContext ("DeleteVNF");
350 // Failed to query the Stack due to an openstack exception.
351 // Convert to a generic VnfException
352 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
353 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
354 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
355 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
356 throw new VnfException (me);
359 // On success, nothing is returned.
360 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
365 * This web service endpoint will rollback a previous Create VNF operation.
366 * A rollback object is returned to the client in a successful creation
367 * response. The client can pass that object as-is back to the rollbackVnf
368 * operation to undo the creation.
371 public void rollbackVnf (VnfRollback rollback) throws VnfException {
372 long startTime = System.currentTimeMillis ();
373 MsoLogger.setServiceName ("RollbackVnf");
374 // rollback may be null (e.g. if stack already existed when Create was called)
375 if (rollback == null) {
376 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
377 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
381 // Get the elements of the VnfRollback object for easier access
382 String cloudSiteId = rollback.getCloudSiteId ();
383 String tenantId = rollback.getTenantId ();
384 String vnfId = rollback.getVnfId ();
386 MsoLogger.setLogContext (rollback.getMsoRequest());
388 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
390 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
392 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
393 // The possible outcomes of deleteStack are a StackInfo object with status
394 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
396 long subStartTime = System.currentTimeMillis ();
398 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
399 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
400 } catch (MsoException me) {
401 // Failed to rollback the Stack due to an openstack exception.
402 // Convert to a generic VnfException
403 me.addContext ("RollbackVNF");
404 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
405 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
406 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
407 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
408 throw new VnfException (me);
410 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 <String, String> ();
429 for (String key : stackOutputs.keySet ()) {
430 if (stackOutputs.get (key) instanceof String) {
431 stringOutputs.put (key, (String) stackOutputs.get (key));
432 } else if (stackOutputs.get(key) instanceof Integer) {
434 String str = "" + stackOutputs.get(key);
435 stringOutputs.put(key, str);
436 } catch (Exception e) {
437 LOGGER.debug("Unable to add " + key + " to outputs");
439 } else if (stackOutputs.get(key) instanceof JsonNode) {
441 String str = this.convertNode((JsonNode) stackOutputs.get(key));
442 stringOutputs.put(key, str);
443 } catch (Exception e) {
444 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode");
446 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
448 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
449 stringOutputs.put(key, str);
450 } catch (Exception e) {
451 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap");
455 String str = stackOutputs.get(key).toString();
456 stringOutputs.put(key, str);
457 } catch (Exception e) {
458 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage());
462 return stringOutputs;
465 private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
466 return new HashMap <String, Object> (stringInputs);
470 * a helper method to make sure that any resource_registry entry of the format
471 * "xx::xx" : yyy.yaml (or yyy.template)
472 * has the file name prepended with "file:///"
473 * Return a String of the environment body that's passed in.
474 * Have to be careful not to mess up the original formatting.
476 private String parseEnvironment (String environment) {
477 StringBuilder sb = new StringBuilder ();
478 try (Scanner scanner = new Scanner (environment)) {
479 scanner.useDelimiter ("\n");
481 Pattern resource = Pattern.compile ("\\s*\"\\w+::\\S+\"\\s*:");
482 LOGGER.debug ("regex pattern for finding a resource_registry: \\s*\"\\w+::\\S+\"\\s*:");
483 while (scanner.hasNextLine ()) {
484 line = scanner.nextLine ();
485 if (line.toLowerCase ().contains ("resource_registry")) {
486 sb.append (line + "\n");
487 boolean done = false;
488 // basically keep scanning until EOF or parameters: section
489 while (scanner.hasNextLine () && !done) {
490 line = scanner.nextLine ();
491 if ("parameters:".equalsIgnoreCase (line.trim ())) {
492 sb.append (line + "\n");
496 Matcher m = resource.matcher (line);
498 sb.append (m.group ());
499 String secondPart = line.substring (m.end ()).trim ();
500 String output = secondPart;
501 if (secondPart.endsWith (".yaml")
502 || secondPart.endsWith (".template") && !secondPart.startsWith ("file:///")) {
503 output = "file:///" + secondPart;
504 LOGGER.debug ("changed " + secondPart + " to " + output);
505 } // don't do anything if it's not .yaml or .template
506 sb.append (" " + output + "\n");
508 sb.append (line + "\n");
512 sb.append (line + "\n");
517 } catch (Exception e) {
518 LOGGER.debug ("Error trying to scan " + environment, e);
521 return sb.toString ();
525 * helper class to add file:/// to the Provider_Resource_File entry in HEAT_NESTED_TEMPLATE
526 * and the File_Name entry in HEAT_FILES if the file:/// part is missing.
528 private String enforceFilePrefix (String string) {
529 if (string.trim ().startsWith ("file:///")) {
533 if (string.trim ().endsWith (".yaml") || string.trim ().endsWith (".template")) {
534 // only .yaml or .template are valid anyway - otherwise don't bother
535 return "file:///" + string.trim ();
537 LOGGER.debug (string + " is NOT a .yaml or .template file");
542 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
544 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
545 if (inputs == null) {
548 else if (inputs.size() < 1) {
549 sb.append("\tEMPTY");
551 for (String str : inputs.keySet()) {
554 outputString = inputs.get(str).toString();
555 } catch (Exception e) {
556 outputString = "Unable to call toString() on the value for " + str;
558 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
561 LOGGER.debug(sb.toString());
565 private void sendMapToDebug(Map<String, String> inputs) {
567 StringBuilder sb = new StringBuilder("inputs:");
568 if (inputs == null) {
571 else if (inputs.size() < 1) {
572 sb.append("\tEMPTY");
574 for (String str : inputs.keySet()) {
575 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
578 LOGGER.debug(sb.toString());
582 private String convertNode(final JsonNode node) {
584 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
585 final String json = JSON_MAPPER.writeValueAsString(obj);
587 } catch (JsonParseException jpe) {
588 LOGGER.debug("Error converting json to string " + jpe.getMessage());
589 } catch (Exception e) {
590 LOGGER.debug("Error converting json to string " + e.getMessage());
592 return "[Error converting json to string]";
595 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
596 if (objectMap == null) {
599 Map<String, String> stringMap = new HashMap<String, String>();
600 for (String key : objectMap.keySet()) {
601 if (!stringMap.containsKey(key)) {
602 Object obj = objectMap.get(key);
603 if (obj instanceof String) {
604 stringMap.put(key, (String) objectMap.get(key));
605 } else if (obj instanceof JsonNode ){
606 // This is a bit of mess - but I think it's the least impacting
607 // let's convert it BACK to a string - then it will get converted back later
609 String str = this.convertNode((JsonNode) obj);
610 stringMap.put(key, str);
611 } catch (Exception e) {
612 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key);
613 //okay in this instance - only string values (fqdn) are expected to be needed
615 } else if (obj instanceof java.util.LinkedHashMap) {
616 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
618 String str = JSON_MAPPER.writeValueAsString(obj);
619 stringMap.put(key, str);
620 } catch (Exception e) {
621 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key);
623 } else if (obj instanceof Integer) {
625 String str = "" + obj;
626 stringMap.put(key, str);
627 } catch (Exception e) {
628 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key);
632 String str = obj.toString();
633 stringMap.put(key, str);
634 } catch (Exception e) {
635 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")");
644 public void createVfModule(String cloudSiteId,
650 String volumeGroupHeatStackId,
651 String baseVfHeatStackId,
652 String modelCustomizationUuid,
653 Map <String, String> inputs,
654 Boolean failIfExists,
656 MsoRequest msoRequest,
657 Holder <String> vnfId,
658 Holder <Map <String, String>> outputs,
659 Holder <VnfRollback> rollback) throws VnfException {
660 String vfModuleName = vnfName;
661 String vfModuleType = vnfType;
662 String vfVersion = vnfVersion;
663 String mcu = modelCustomizationUuid;
664 boolean useMCUuid = false;
665 if (mcu != null && !mcu.isEmpty()) {
666 if (mcu.equalsIgnoreCase("null")) {
667 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
671 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
675 MsoLogger.setLogContext (msoRequest);
676 MsoLogger.setServiceName ("CreateVfModule");
677 String requestTypeString = "";
678 if (requestType != null && !requestType.equals("")) {
679 requestTypeString = requestType;
681 String nestedStackId = null;
682 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
683 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
684 nestedStackId = volumeGroupHeatStackId;
687 String nestedBaseStackId = null;
688 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
689 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
690 nestedBaseStackId = baseVfHeatStackId;
694 if (inputs == null) {
695 // Create an empty set of inputs
696 inputs = new HashMap<String,String>();
697 LOGGER.debug("inputs == null - setting to empty");
699 this.sendMapToDebug(inputs);
701 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
702 boolean oldWay = false;
703 if (requestTypeString.startsWith("X")) {
705 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
706 requestTypeString = requestTypeString.substring(1);
709 // 1607 - let's parse out the request type we're being sent
710 boolean isBaseRequest = false;
711 boolean isVolumeRequest = false;
712 if (requestTypeString.startsWith("VOLUME")) {
713 isVolumeRequest = true;
716 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
717 // Will capture execution time for metrics
718 long startTime = System.currentTimeMillis ();
720 // Build a default rollback object (no actions performed)
721 VnfRollback vfRollback = new VnfRollback();
722 vfRollback.setCloudSiteId(cloudSiteId);
723 vfRollback.setTenantId(tenantId);
724 vfRollback.setMsoRequest(msoRequest);
725 vfRollback.setRequestType(requestTypeString);
726 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
727 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
728 vfRollback.setIsBase(isBaseRequest);
729 vfRollback.setModelCustomizationUuid(mcu);
731 // First, look up to see if the VF already exists.
732 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
734 StackInfo heatStack = null;
735 long subStartTime1 = System.currentTimeMillis ();
737 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
738 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
739 } catch (MsoException me) {
740 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
741 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
742 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
743 // Failed to query the Stack due to an openstack exception.
744 // Convert to a generic VnfException
745 me.addContext ("CreateVFModule");
746 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
747 throw new VnfException (me);
749 // New with 1607 - more precise handling/messaging if the stack already exists
750 if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
751 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
752 HeatStatus status = heatStack.getStatus();
753 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
754 // fail - it's in progress - return meaningful error
755 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.";
756 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
757 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
758 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
760 if (status == HeatStatus.FAILED) {
761 // fail - it exists and is in a FAILED state
762 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
763 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
764 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
765 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
767 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
768 // fail - it exists and is in a FAILED state
769 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
770 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");
771 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
772 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
774 if (status == HeatStatus.CREATED) {
776 if (failIfExists != null && failIfExists) {
777 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
778 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
779 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
780 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
782 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
783 // Populate the outputs from the existing stack.
784 vnfId.value = heatStack.getCanonicalName ();
785 outputs.value = copyStringOutputs (heatStack.getOutputs ());
786 rollback.value = vfRollback; // Default rollback - no updates performed
789 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
794 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
795 StackInfo nestedHeatStack = null;
796 long subStartTime2 = System.currentTimeMillis ();
797 Map<String, Object> nestedVolumeOutputs = null;
798 if (nestedStackId != null) {
800 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
801 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
802 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
803 } catch (MsoException me) {
804 // Failed to query the Stack due to an openstack exception.
805 // Convert to a generic VnfException
806 me.addContext ("CreateVFModule");
807 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
808 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
809 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
810 LOGGER.debug("ERROR trying to query nested stack= " + error);
811 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
812 throw new VnfException (me);
814 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
815 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
816 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
817 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
819 throw new VnfException (error, MsoExceptionCategory.USERDATA);
821 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
822 //this.sendMapToDebug(inputs);
823 nestedVolumeOutputs = nestedHeatStack.getOutputs();
824 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
826 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
827 //this.sendMapToDebug(inputs);
831 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
832 StackInfo nestedBaseHeatStack = null;
833 long subStartTime3 = System.currentTimeMillis ();
834 Map<String, Object> baseStackOutputs = null;
835 if (nestedBaseStackId != null) {
837 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
838 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
839 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
840 } catch (MsoException me) {
841 // Failed to query the Stack due to an openstack exception.
842 // Convert to a generic VnfException
843 me.addContext ("CreateVFModule");
844 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
845 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
846 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
847 LOGGER.debug("ERROR trying to query nested base stack= " + error);
848 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
849 throw new VnfException (me);
851 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
852 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
853 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");
854 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
856 throw new VnfException (error, MsoExceptionCategory.USERDATA);
858 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
859 //this.sendMapToDebug(inputs);
860 baseStackOutputs = nestedBaseHeatStack.getOutputs();
861 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
863 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
864 //this.sendMapToDebug(inputs);
868 // Ready to deploy the new VNF
870 CatalogDatabase db = CatalogDatabase.getInstance();
875 VnfResource vnfResource = null;
876 VfModuleCustomization vfmc = null;
877 LOGGER.debug("version: " + vfVersion);
879 // 1707 - db refactoring
880 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
881 vf = vfmc != null ? vfmc.getVfModule() : null;
882 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
883 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
885 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
886 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
887 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
888 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
889 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
890 throw new VnfException(error, MsoExceptionCategory.USERDATA);
892 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
895 isBaseRequest = true;
896 LOGGER.debug("This is a BASE VF request!");
898 LOGGER.debug("This is *not* a BASE VF request!");
899 if (!isVolumeRequest && nestedBaseStackId == null) {
900 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
906 // Need to handle old and new schema methods - for a time. Try the new way first.
907 if (vfVersion != null && !vfVersion.isEmpty()) {
908 vf = db.getVfModuleType(vfModuleType, vfVersion);
910 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME");
911 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
913 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
917 vf = db.getVfModuleType(vfModuleType);
919 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
920 vf = db.getVfModuleModelName(vfModuleType);
922 LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
927 String error = "Create VF Module: Unable to determine specific VF Module Type: "
929 if (vfVersion != null && !vfVersion.isEmpty()) {
930 error += " with version = " + vfVersion;
932 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
933 "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type");
934 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
935 throw new VnfException(error, MsoExceptionCategory.USERDATA);
937 LOGGER.debug("Got VF module definition from Catalog: "
941 isBaseRequest = true;
942 LOGGER.debug("This is a BASE VF request!");
944 LOGGER.debug("This is *not* a BASE VF request!");
945 if (!isVolumeRequest && nestedBaseStackId == null) {
946 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
950 else { // This is to support gamma only - get info from vnf_resource table
951 if (vfVersion != null && !vfVersion.isEmpty()) {
952 vnfResource = db.getVnfResource(vnfType, vnfVersion);
954 vnfResource = db.getVnfResource(vnfType);
956 if (vnfResource == null) {
957 String error = "Create VNF: Unknown VNF Type: " + vnfType;
958 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
959 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
960 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
961 throw new VnfException(error, MsoExceptionCategory.USERDATA);
963 LOGGER.debug("Got VNF module definition from Catalog: "
964 + vnfResource.toString());
966 // By here - we have either a vf or vnfResource
968 //1607 - Add version check
969 // First - see if it's in the VnfResource record
970 // if we have a vf Module - then we have to query to get the VnfResource record.
972 if (vf.getVnfResourceModelUUId() != null) {
973 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
974 //vnfResource = db.getVnfResourceById(vnfResourceId);
975 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
976 if (vnfResource == null) {
977 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
981 String minVersionVnf = null;
982 String maxVersionVnf = null;
983 if (vnfResource != null) {
985 minVersionVnf = vnfResource.getAicVersionMin();
986 maxVersionVnf = vnfResource.getAicVersionMax();
987 } catch (Exception e) {
988 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry");
989 minVersionVnf = null;
990 maxVersionVnf = null;
992 if (minVersionVnf != null && minVersionVnf.equals("")) {
993 minVersionVnf = null;
995 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
996 maxVersionVnf = null;
999 if (minVersionVnf != null && maxVersionVnf != null) {
1000 MavenLikeVersioning aicV = new MavenLikeVersioning();
1001 CloudSite cloudSite = null;
1002 String aicVersion = "";
1003 if (this.cloudConfig == null) {
1004 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1007 if (this.cloudConfig != null) {
1008 cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1009 if (cloudSite != null) {
1010 aicV.setVersion(cloudSite.getAic_version());
1011 // Add code to handle unexpected values in here
1012 boolean moreThanMin = true;
1013 boolean equalToMin = true;
1014 boolean moreThanMax = true;
1015 boolean equalToMax = true;
1016 boolean doNotTest = false;
1018 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1019 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1020 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1021 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1022 } catch (Exception e) {
1023 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check");
1027 if ((moreThanMin || equalToMin) // aic >= min
1028 && (equalToMax || !(moreThanMax))) { //aic <= max
1029 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1032 String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1033 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1034 LOGGER.debug(error);
1035 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1038 LOGGER.debug("bypassing testing AIC version...");
1040 } // let this error out downstream to avoid introducing uncertainty at this stage
1042 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1045 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1047 // End Version check 1607
1049 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
1050 // with VNF_RESOURCE - we use the old methods.
1051 //Integer heatTemplateId = null;
1052 //Integer heatEnvtId = null;
1054 String heatTemplateArtifactUuid = null;
1055 String heatEnvironmentArtifactUuid = null;
1058 if (isVolumeRequest) {
1059 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1060 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1062 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1063 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1066 if (isVolumeRequest) {
1067 LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
1069 VnfComponent vnfComponent = null;
1070 vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME");
1071 if (vnfComponent == null) {
1072 String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME";
1073 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry");
1074 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1075 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1077 heatTemplateId = vnfComponent.getHeatTemplateId();
1078 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1082 heatTemplateArtifactUuid = vnfResource.getTemplateId();
1083 heatEnvironmentArtifactUuid = null;
1086 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1087 HeatTemplate heatTemplate = null;
1088 if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) {
1089 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1090 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1091 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1092 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1093 MsoAlarmLogger.CRITICAL, error);
1094 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1096 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1098 if (heatTemplate == null) {
1099 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1100 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1102 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1103 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1104 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1105 MsoAlarmLogger.CRITICAL, error);
1106 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1108 LOGGER.debug("Got HEAT Template from DB");
1110 HeatEnvironment heatEnvironment = null;
1111 String heatEnvironmentString = null;
1113 if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals("")) {
1114 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1115 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1116 if (heatEnvironment == null) {
1117 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1118 + ", Environment ID="
1119 + heatEnvironmentArtifactUuid;
1120 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1121 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1122 // Alarm on this error, configuration must be fixed
1123 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1125 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1127 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1128 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1129 LOGGER.debug ("after parsing: " + heatEnvironmentString);
1132 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
1135 // 1510 - Add the files: for nested templates *if* there are any
1136 LOGGER.debug ("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1137 + heatTemplate.getArtifactUuid());
1138 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid());
1139 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1140 if (nestedTemplates != null) {
1141 // for debugging print them out
1142 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1143 for (String providerResourceFile : nestedTemplates.keySet ()) {
1144 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1145 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1146 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1147 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1150 LOGGER.debug ("No nested templates found - nothing to do here");
1151 nestedTemplatesChecked = null; // just to make sure
1154 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1155 // *if* there are any
1156 Map<String, HeatFiles> heatFiles = null;
1157 Map<String, Object> heatFilesObjects = new HashMap<String, Object>();
1159 // Add ability to turn on adding get_files with volume requests (by property).
1160 boolean addGetFilesOnVolumeReq = false;
1162 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1163 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1164 addGetFilesOnVolumeReq = true;
1165 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1167 } catch (Exception e) {
1168 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1171 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1173 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1174 //heatFiles = db.getHeatFiles(vnfResource.getId());
1176 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1177 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1178 + vf.getModelUUID());
1180 .getHeatFilesForVfModule(vf.getModelUUID());
1182 if (heatFiles != null) {
1183 // add these to stack - to be done in createStack
1184 // here, we will map them to Map<String, Object> from
1185 // Map<String, HeatFiles>
1186 // this will match the nested templates format
1187 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1189 for (String heatFileName : heatFiles.keySet()) {
1190 if (heatFileName.startsWith("_ERROR|")) {
1191 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1192 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1193 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1194 LOGGER.debug(error);
1195 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1196 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1197 // Alarm on this error, configuration must be fixed
1198 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1199 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1201 String heatFileBody = heatFiles.get(heatFileName)
1203 String heatFileNameChecked = heatFileName;
1204 LOGGER.debug(heatFileNameChecked + " -> "
1206 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1209 LOGGER.debug("No heat files found -nothing to do here");
1210 heatFilesObjects = null;
1213 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1216 // Check that required parameters have been supplied
1217 String missingParams = null;
1218 List <String> paramList = new ArrayList <String> ();
1220 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1221 // supplied an alias. Only check if we don't find it initially.
1222 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1223 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1225 boolean haveEnvironmentParameters = false;
1226 boolean checkRequiredParameters = true;
1228 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1229 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1230 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1231 checkRequiredParameters = false;
1232 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1233 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1235 } catch (Exception e) {
1236 // No problem - default is true
1237 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1239 // 1604 - Add enhanced environment & parameter checking
1240 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1241 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1242 // Note this also removes any comments
1243 MsoHeatEnvironmentEntry mhee = null;
1244 if (heatEnvironmentString != null && heatEnvironmentString.contains ("parameters:")) {
1245 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1246 LOGGER.debug("Enhanced environment checking enabled - 1604");
1247 haveEnvironmentParameters = true;
1248 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1249 //LOGGER.debug("About to create MHEE with " + sb);
1250 mhee = new MsoHeatEnvironmentEntry(sb);
1251 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1252 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1253 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1255 if (!mhee.isValid()) {
1256 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1258 sb2.append("\nEnvironment:");
1259 sb2.append(mhee.toFullString());
1261 LOGGER.debug(sb2.toString());
1263 LOGGER.debug("NO ENVIRONMENT for this entry");
1265 // New with 1707 - all variables converted to their native object types
1266 HashMap<String, Object> goldenInputs = null;
1268 LOGGER.debug("Now handle the inputs....first convert");
1269 ArrayList<String> parameterNames = new ArrayList<String>();
1270 HashMap<String, String> aliasToParam = new HashMap<String, String>();
1271 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1274 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1275 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1276 parameterNames.add(htp.getParamName());
1277 if (htp.getParamAlias() != null && !htp.getParamAlias().equals("")) {
1278 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1279 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1283 LOGGER.debug(sb.toString());
1284 } catch (Exception e) {
1285 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage());
1287 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1288 // Map<String, Object> - where the object matches the param type identified in the template
1289 // This will also not copy over params that aren't identified in the template
1290 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1291 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1292 LOGGER.debug("Now add in the base stack outputs if applicable");
1293 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1294 // Step 3 - add the volume inputs if any
1295 LOGGER.debug("Now add in the volume stack outputs if applicable");
1296 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1297 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1299 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1300 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1302 + parm.isRequired ()
1304 + parm.getParamAlias ());
1306 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1307 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1308 LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment");
1309 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1310 LOGGER.debug ("Required parameter " + parm.getParamName ()
1311 + " appears to be in environment - do not count as missing");
1313 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1314 if (missingParams == null) {
1315 missingParams = parm.getParamName ();
1317 missingParams += "," + parm.getParamName ();
1321 paramList.add (parm.getParamName ());
1323 if (missingParams != null) {
1324 if (checkRequiredParameters) {
1325 // Problem - missing one or more required parameters
1326 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1327 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1328 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1329 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1331 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1334 LOGGER.debug ("No missing parameters found - ok to proceed");
1336 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1337 // and it causes problems with json that has arrays
1338 String newEnvironmentString = null;
1340 newEnvironmentString = mhee.getRawEntry().toString();
1343 // "Fix" the template if it has CR/LF (getting this from Oracle)
1344 String template = heatTemplate.getHeatTemplate ();
1345 template = template.replaceAll ("\r\n", "\n");
1347 // Have the tenant. Now deploy the stack itself
1348 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1349 // because we already checked for those.
1350 long createStackStarttime = System.currentTimeMillis ();
1352 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1353 // heatTemplate.getTimeoutMinutes());
1354 if (backout == null) {
1358 LOGGER.debug("heat is not null!!");
1360 heatStack = heat.createStack (cloudSiteId,
1366 heatTemplate.getTimeoutMinutes (),
1367 newEnvironmentString,
1368 nestedTemplatesChecked,
1370 backout.booleanValue());
1371 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1372 } catch (MsoException me) {
1373 me.addContext ("CreateVFModule");
1374 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1375 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1376 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1377 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1378 throw new VnfException (me);
1379 } catch (NullPointerException npe) {
1380 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1381 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1382 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1383 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1384 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1385 //npe.addContext ("CreateVNF");
1386 throw new VnfException ("NullPointerException during heat.createStack");
1387 } catch (Exception e) {
1388 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1389 LOGGER.debug("unhandled exception at heat.createStack");
1390 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1391 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1393 } catch (Exception e) {
1394 LOGGER.debug("unhandled exception in create VF");
1395 throw new VnfException("Exception during create VF " + e.getMessage());
1398 // Make sure DB session is closed
1402 // Reach this point if createStack is successful.
1403 // Populate remaining rollback info and response parameters.
1404 vfRollback.setVnfId (heatStack.getCanonicalName ());
1405 vfRollback.setVnfCreated (true);
1407 vnfId.value = heatStack.getCanonicalName ();
1408 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1409 rollback.value = vfRollback;
1411 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1412 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1416 public void deleteVfModule (String cloudSiteId,
1419 MsoRequest msoRequest,
1420 Holder <Map <String, String>> outputs) throws VnfException {
1421 MsoLogger.setLogContext (msoRequest);
1422 MsoLogger.setServiceName ("DeleteVf");
1423 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1424 // Will capture execution time for metrics
1425 long startTime = System.currentTimeMillis ();
1427 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1429 // 1702 capture the output parameters on a delete
1430 // so we'll need to query first
1431 Map<String, Object> stackOutputs = null;
1433 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1434 } catch (MsoException me) {
1435 // Failed to query the Stack due to an openstack exception.
1436 // Convert to a generic VnfException
1437 me.addContext ("DeleteVFModule");
1438 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1439 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1440 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1441 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1442 throw new VnfException (me);
1444 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1445 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1447 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1448 // The possible outcomes of deleteStack are a StackInfo object with status
1449 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1451 long subStartTime = System.currentTimeMillis ();
1453 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1454 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1455 } catch (MsoException me) {
1456 me.addContext ("DeleteVNF");
1457 // Failed to query the Stack due to an openstack exception.
1458 // Convert to a generic VnfException
1459 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1460 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1461 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1462 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1463 throw new VnfException (me);
1466 // On success, nothing is returned.
1467 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1472 public void updateVfModule (String cloudSiteId,
1478 String volumeGroupHeatStackId,
1479 String baseVfHeatStackId,
1480 String vfModuleStackId,
1481 String modelCustomizationUuid,
1482 Map <String, String> inputs,
1483 MsoRequest msoRequest,
1484 Holder <Map <String, String>> outputs,
1485 Holder <VnfRollback> rollback) throws VnfException {
1486 String vfModuleName = vnfName;
1487 String vfModuleType = vnfType;
1488 String vfVersion = vnfVersion;
1489 String methodName = "updateVfModule";
1490 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1491 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1492 MsoLogger.setServiceName (serviceName);
1494 StringBuilder sbInit = new StringBuilder();
1495 sbInit.append("updateVfModule: \n");
1496 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1497 sbInit.append("tenantId=" + tenantId + "\n");
1498 sbInit.append("vnfType=" + vnfType + "\n");
1499 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1500 sbInit.append("vnfName=" + vnfName + "\n");
1501 sbInit.append("requestType=" + requestType + "\n");
1502 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1503 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1504 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1505 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1506 LOGGER.debug(sbInit.toString());
1508 String mcu = modelCustomizationUuid;
1509 boolean useMCUuid = false;
1510 if (mcu != null && !mcu.isEmpty()) {
1511 if (mcu.equalsIgnoreCase("null")) {
1512 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1516 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1521 String requestTypeString = "";
1522 if (requestType != null && !requestType.equals("")) {
1523 requestTypeString = requestType;
1525 String nestedStackId = null;
1526 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1527 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1528 nestedStackId = volumeGroupHeatStackId;
1531 String nestedBaseStackId = null;
1532 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1533 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1534 nestedBaseStackId = baseVfHeatStackId;
1538 if (inputs == null) {
1539 // Create an empty set of inputs
1540 inputs = new HashMap<String,String>();
1541 LOGGER.debug("inputs == null - setting to empty");
1543 this.sendMapToDebug(inputs);
1545 boolean isBaseRequest = false;
1546 boolean isVolumeRequest = false;
1547 if (requestTypeString.startsWith("VOLUME")) {
1548 isVolumeRequest = true;
1550 if (vfModuleName == null || vfModuleName.trim().equals("")) {
1551 if (vfModuleStackId != null) {
1552 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1556 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1557 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1559 // Will capture execution time for metrics
1560 long startTime = System.currentTimeMillis ();
1562 // Build a default rollback object (no actions performed)
1563 VnfRollback vfRollback = new VnfRollback ();
1564 vfRollback.setCloudSiteId (cloudSiteId);
1565 vfRollback.setTenantId (tenantId);
1566 vfRollback.setMsoRequest (msoRequest);
1567 vfRollback.setRequestType(requestTypeString);
1568 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1569 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1570 vfRollback.setIsBase(isBaseRequest);
1571 vfRollback.setVfModuleStackId(vfModuleStackId);
1572 vfRollback.setModelCustomizationUuid(mcu);
1574 // First, look up to see if the VNF already exists.
1575 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1576 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1578 StackInfo heatStack = null;
1579 long queryStackStarttime = System.currentTimeMillis ();
1580 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1582 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1583 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1584 } catch (MsoException me) {
1585 // Failed to query the Stack due to an openstack exception.
1586 // Convert to a generic VnfException
1587 me.addContext ("UpdateVFModule");
1588 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1589 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1590 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1591 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1592 throw new VnfException (me);
1595 //TODO - do we need to check for the other status possibilities?
1596 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1598 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1599 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1600 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1601 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1603 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1604 // Populate the outputs from the existing stack.
1605 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1606 rollback.value = vfRollback; // Default rollback - no updates performed
1609 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1610 StackInfo nestedHeatStack = null;
1611 long queryStackStarttime2 = System.currentTimeMillis ();
1612 Map<String, Object> nestedVolumeOutputs = null;
1613 if (nestedStackId != null) {
1615 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1616 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1617 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1618 } catch (MsoException me) {
1619 // Failed to query the Stack due to an openstack exception.
1620 // Convert to a generic VnfException
1621 me.addContext ("UpdateVFModule");
1622 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1623 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1624 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1625 LOGGER.debug("ERROR trying to query nested stack= " + error);
1626 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1627 throw new VnfException (me);
1629 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1630 MsoLogger.setServiceName (serviceName);
1631 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1632 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1633 LOGGER.debug(error);
1634 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1635 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1637 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1638 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1639 //this.sendMapToDebug(inputs);
1640 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1642 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1643 //this.sendMapToDebug(inputs);
1646 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1647 StackInfo nestedBaseHeatStack = null;
1648 Map<String, Object> baseStackOutputs = null;
1649 if (nestedBaseStackId != null) {
1650 long queryStackStarttime3 = System.currentTimeMillis ();
1652 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1653 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1654 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1655 } catch (MsoException me) {
1656 // Failed to query the Stack due to an openstack exception.
1657 // Convert to a generic VnfException
1658 me.addContext ("UpdateVfModule");
1659 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1660 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1661 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1662 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1663 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1664 throw new VnfException (me);
1666 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1667 MsoLogger.setServiceName (serviceName);
1668 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1669 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1670 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1671 LOGGER.debug(error);
1672 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1674 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1675 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1676 //this.sendMapToDebug(inputs);
1677 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1679 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1680 //this.sendMapToDebug(inputs);
1684 // Ready to deploy the new VNF
1686 // Get a handle to the Catalog Database
1687 CatalogDatabase db = CatalogDatabase.getInstance();
1689 // Make sure DB session is closed
1691 // Retrieve the VF definition
1692 VnfResource vnfResource = null;
1694 VfModuleCustomization vfmc = null;
1696 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1697 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1698 vf = vfmc != null ? vfmc.getVfModule() : null;
1700 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1703 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1706 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1707 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1708 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1709 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1711 LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
1713 isBaseRequest = true;
1714 LOGGER.debug("This a BASE update request");
1716 LOGGER.debug("This is *not* a BASE VF update request");
1717 if (!isVolumeRequest && nestedBaseStackId == null) {
1718 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1722 //1607 - Add version check
1723 // First - see if it's in the VnfResource record
1724 // if we have a vf Module - then we have to query to get the VnfResource record.
1725 if (vf.getVnfResourceModelUUId() != null) {
1726 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1727 //vnfResource = db.getVnfResourceById(vnfResourceId);
1728 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1729 if (vnfResource == null) {
1730 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1733 String minVersionVnf = null;
1734 String maxVersionVnf = null;
1735 if (vnfResource != null) {
1737 minVersionVnf = vnfResource.getAicVersionMin();
1738 maxVersionVnf = vnfResource.getAicVersionMax();
1739 } catch (Exception e) {
1740 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry");
1741 minVersionVnf = null;
1742 maxVersionVnf = null;
1744 if (minVersionVnf != null && minVersionVnf.equals("")) {
1745 minVersionVnf = null;
1747 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1748 maxVersionVnf = null;
1751 if (minVersionVnf != null && maxVersionVnf != null) {
1752 MavenLikeVersioning aicV = new MavenLikeVersioning();
1753 CloudSite cloudSite = null;
1754 //String aicVersion = "";
1755 if (this.cloudConfig == null) {
1756 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1759 if (this.cloudConfig != null) {
1760 cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1761 if (cloudSite != null) {
1762 aicV.setVersion(cloudSite.getAic_version());
1763 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1764 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV.isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1765 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1768 String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1769 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1770 LOGGER.debug(error);
1771 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1773 } // let this error out downstream to avoid introducing uncertainty at this stage
1775 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1779 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1781 // End Version check 1607
1783 String heatTemplateArtifactUuid = null;
1784 String heatEnvironmentArtifactUuid = null;
1786 HeatTemplate heatTemplate = null;
1787 if (isVolumeRequest) {
1788 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1789 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1791 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1792 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1794 if (heatTemplateArtifactUuid == null) {
1795 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1796 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1797 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1798 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1799 MsoAlarmLogger.CRITICAL, error);
1800 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1802 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1805 if (heatTemplate == null) {
1806 String error = "Update VNF: undefined Heat Template. VF="
1807 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1808 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1810 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1811 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1812 // Alarm on this error, configuration must be fixed
1813 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1814 MsoAlarmLogger.CRITICAL, error);
1816 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1819 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
1821 // Add check for any Environment variable
1822 HeatEnvironment heatEnvironment = null;
1823 String heatEnvironmentString = null;
1825 if (heatEnvironmentArtifactUuid != null) {
1826 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1827 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1828 if (heatEnvironment == null) {
1830 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1831 + ", Environment ID="
1832 + heatEnvironmentArtifactUuid;
1833 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1834 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1835 // Alarm on this error, configuration must be fixed
1836 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1838 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1840 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1841 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1842 LOGGER.debug ("After parsing: " + heatEnvironmentString);
1845 LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType);
1849 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1850 + heatTemplate.getArtifactUuid ());
1851 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid ());
1852 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1853 if (nestedTemplates != null) {
1854 // for debugging print them out
1855 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1856 for (String providerResourceFile : nestedTemplates.keySet ()) {
1857 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1858 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1859 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1860 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1863 LOGGER.debug ("No nested templates found - nothing to do here");
1864 nestedTemplatesChecked = null;
1867 // Also add the files: for any get_files associated with this VfModule
1868 // *if* there are any
1869 LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1870 + vf.getModelUUID());
1872 Map <String, HeatFiles> heatFiles = null;
1873 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1874 Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
1876 // Add ability to turn on adding get_files with volume requests (by property).
1877 boolean addGetFilesOnVolumeReq = false;
1879 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1880 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1881 addGetFilesOnVolumeReq = true;
1882 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1884 } catch (Exception e) {
1885 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1887 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1888 LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1889 + vf.getModelUUID());
1891 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1892 if (heatFiles != null) {
1893 // add these to stack - to be done in createStack
1894 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1895 // this will match the nested templates format
1896 LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
1898 for (String heatFileName : heatFiles.keySet ()) {
1899 if (heatFileName.startsWith("_ERROR|")) {
1900 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1901 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1902 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1903 LOGGER.debug(error);
1904 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1905 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1906 // Alarm on this error, configuration must be fixed
1907 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1908 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1910 String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
1911 LOGGER.debug (heatFileName + " -> " + heatFileBody);
1912 heatFilesObjects.put (heatFileName, heatFileBody);
1915 LOGGER.debug ("No heat files found -nothing to do here");
1916 heatFilesObjects = null;
1920 // Check that required parameters have been supplied
1921 String missingParams = null;
1922 List <String> paramList = new ArrayList <String> ();
1924 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1925 // supplied an alias. Only check if we don't find it initially.
1926 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1927 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1929 boolean haveEnvironmentParameters = false;
1930 boolean checkRequiredParameters = true;
1932 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1933 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1934 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1935 checkRequiredParameters = false;
1936 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1937 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1939 } catch (Exception e) {
1940 // No problem - default is true
1941 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1943 // 1604 - Add enhanced environment & parameter checking
1944 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1945 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1946 // Note this also removes any comments
1947 MsoHeatEnvironmentEntry mhee = null;
1948 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) {
1949 LOGGER.debug("Enhanced environment checking enabled - 1604");
1950 haveEnvironmentParameters = true;
1951 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1952 //LOGGER.debug("About to create MHEE with " + sb);
1953 mhee = new MsoHeatEnvironmentEntry(sb);
1954 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1955 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1956 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1958 if (!mhee.isValid()) {
1959 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1961 sb2.append("\nEnvironment:");
1962 sb2.append(mhee.toFullString());
1964 LOGGER.debug(sb2.toString());
1966 LOGGER.debug("NO ENVIRONMENT for this entry");
1969 // New for 1607 - support params of json type
1970 HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
1971 boolean hasJson = false;
1973 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1974 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1976 + parm.isRequired ()
1978 + parm.getParamAlias ());
1980 String parameterType = parm.getParamType();
1981 if (parameterType == null || parameterType.trim().equals("")) {
1982 parameterType = "String";
1984 JsonNode jsonNode = null;
1985 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
1986 if (inputs.containsKey(parm.getParamName()) ) {
1988 String jsonString = null;
1990 jsonString = inputs.get(parm.getParamName());
1991 jsonNode = new ObjectMapper().readTree(jsonString);
1992 } catch (JsonParseException jpe) {
1993 //TODO - what to do here?
1994 //for now - send the error to debug, but just leave it as a String
1995 String errorMessage = jpe.getMessage();
1996 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage);
1999 } catch (Exception e) {
2001 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
2005 if (jsonNode != null) {
2006 jsonParams.put(parm.getParamName(), jsonNode);
2008 } else if (inputs.containsKey(parm.getParamAlias())) {
2010 String jsonString = null;
2012 jsonString = inputs.get(parm.getParamAlias());
2013 jsonNode = new ObjectMapper().readTree(jsonString);
2014 } catch (JsonParseException jpe) {
2015 //TODO - what to do here?
2016 //for now - send the error to debug, but just leave it as a String
2017 String errorMessage = jpe.getMessage();
2018 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage);
2021 } catch (Exception e) {
2023 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage());
2027 if (jsonNode != null) {
2028 // Notice here - we add it to the jsonParams hashMap with the actual name -
2029 // then manipulate the inputs so when we check for aliases below - it will not
2031 jsonParams.put(parm.getParamName(), jsonNode);
2032 inputs.remove(parm.getParamAlias());
2033 inputs.put(parm.getParamName(), jsonString);
2035 } //TODO add a check for the parameter in the env file
2038 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
2039 if (inputs.containsKey (parm.getParamAlias ())) {
2040 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2041 String realParamName = parm.getParamName ();
2042 String alias = parm.getParamAlias ();
2043 String value = inputs.get (alias);
2044 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
2049 inputs.remove (alias);
2050 inputs.put (realParamName, value);
2051 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
2053 // enhanced - check if it's in the Environment (note: that method
2054 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2056 LOGGER.debug ("Required parameter " + parm.getParamName ()
2057 + " appears to be in environment - do not count as missing");
2060 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
2061 if (missingParams == null) {
2062 missingParams = parm.getParamName ();
2064 missingParams += "," + parm.getParamName ();
2068 paramList.add (parm.getParamName ());
2070 if (missingParams != null) {
2071 // Problem - missing one or more required parameters
2072 if (checkRequiredParameters) {
2073 String error = "Update VNF: Missing Required inputs: " + missingParams;
2074 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2075 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
2076 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2078 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
2081 LOGGER.debug ("No missing parameters found - ok to proceed");
2084 // Just submit the envt entry as received from the database
2085 String newEnvironmentString = null;
2087 newEnvironmentString = mhee.getRawEntry().toString();
2090 // Remove any extraneous parameters (don't throw an error)
2091 if (inputs != null) {
2092 List <String> extraParams = new ArrayList <String> ();
2093 extraParams.addAll (inputs.keySet ());
2094 // This is not a valid parameter for this template
2095 extraParams.removeAll (paramList);
2096 if (!extraParams.isEmpty ()) {
2097 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
2098 inputs.keySet ().removeAll (extraParams);
2101 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2102 Map<String, Object> inputsTwo = null;
2103 if (hasJson && jsonParams.size() > 0) {
2104 inputsTwo = new HashMap<String, Object>();
2105 for (String keyParamName : inputs.keySet()) {
2106 if (jsonParams.containsKey(keyParamName)) {
2107 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2109 inputsTwo.put(keyParamName, inputs.get(keyParamName));
2114 // "Fix" the template if it has CR/LF (getting this from Oracle)
2115 String template = heatTemplate.getHeatTemplate ();
2116 template = template.replaceAll ("\r\n", "\n");
2118 // Have the tenant. Now deploy the stack itself
2119 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2120 // because we already checked for those.
2121 long updateStackStarttime = System.currentTimeMillis ();
2124 heatStack = heatU.updateStack (cloudSiteId,
2128 copyStringInputs (inputs),
2130 heatTemplate.getTimeoutMinutes (),
2131 newEnvironmentString,
2132 //heatEnvironmentString,
2133 nestedTemplatesChecked,
2135 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2137 heatStack = heatU.updateStack (cloudSiteId,
2143 heatTemplate.getTimeoutMinutes (),
2144 newEnvironmentString,
2145 //heatEnvironmentString,
2146 nestedTemplatesChecked,
2148 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2151 } catch (MsoException me) {
2152 me.addContext ("UpdateVFModule");
2153 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2154 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2155 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2156 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2157 throw new VnfException (me);
2160 // Make sure DB session is closed
2164 // Reach this point if updateStack is successful.
2165 // Populate remaining rollback info and response parameters.
2166 vfRollback.setVnfId (heatStack.getCanonicalName ());
2167 vfRollback.setVnfCreated (true);
2169 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2170 rollback.value = vfRollback;
2171 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2175 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2176 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2177 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2178 if (vfModuleStackId == null)
2180 int index = vfModuleStackId.lastIndexOf('/');
2183 String vfModuleName = null;
2185 vfModuleName = vfModuleStackId.substring(0, index);
2186 } catch (Exception e) {
2187 vfModuleName = null;
2189 return vfModuleName;