2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.mso.adapters.vnf;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
29 import java.util.Scanner;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
33 import javax.jws.WebService;
34 import javax.xml.ws.Holder;
36 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
37 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
38 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
39 import org.openecomp.mso.cloud.CloudConfigFactory;
40 import org.openecomp.mso.cloud.CloudConfig;
41 import org.openecomp.mso.cloud.CloudSite;
42 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
43 import org.openecomp.mso.db.catalog.CatalogDatabase;
44 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
45 import org.openecomp.mso.db.catalog.beans.HeatFiles;
46 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
47 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
48 import org.openecomp.mso.db.catalog.beans.VnfResource;
49 import org.openecomp.mso.db.catalog.beans.VfModule;
50 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
51 import org.openecomp.mso.db.catalog.beans.VnfComponent;
52 import org.openecomp.mso.entity.MsoRequest;
53 import org.openecomp.mso.logger.MessageEnum;
54 import org.openecomp.mso.logger.MsoAlarmLogger;
55 import org.openecomp.mso.logger.MsoLogger;
56 import org.openecomp.mso.openstack.beans.HeatStatus;
57 import org.openecomp.mso.openstack.beans.StackInfo;
58 import org.openecomp.mso.openstack.beans.VnfStatus;
59 import org.openecomp.mso.openstack.beans.VnfRollback;
60 import org.openecomp.mso.openstack.exceptions.MsoException;
61 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
62 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
63 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
64 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
65 import org.openecomp.mso.properties.MsoPropertiesFactory;
67 import org.codehaus.jackson.JsonNode;
68 import org.codehaus.jackson.JsonParseException;
69 import org.codehaus.jackson.map.ObjectMapper;
71 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
72 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
74 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
75 protected CloudConfig cloudConfig = null;
77 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
79 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
80 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
81 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
82 private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN.";
83 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
84 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
85 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
86 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
87 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
90 * Health Check web method. Does nothing but return to show the adapter is deployed.
93 public void healthCheck () {
94 LOGGER.debug ("Health check call in VNF Adapter");
98 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
99 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
101 public MsoVnfAdapterImpl() {
106 * This constructor MUST be used if this class is called with the new operator.
107 * @param msoPropFactory
109 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
110 this.msoPropertiesFactory = msoPropFactory;
111 this.cloudConfigFactory = cloudConfigFact;
115 * This is the "Create VNF" web service implementation.
116 * It will create a new VNF of the requested type in the specified cloud
117 * and tenant. The tenant must exist before this service is called.
119 * If a VNF with the same name already exists, this can be considered a
120 * success or failure, depending on the value of the 'failIfExists' parameter.
122 * All VNF types will be defined in the MSO catalog. The caller must request
123 * one of these pre-defined types or an error will be returned. Within the
124 * catalog, each VNF type references (among other things) a Heat template
125 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
128 * Depending on the Heat template, a variable set of input parameters will
129 * be defined, some of which are required. The caller is responsible to
130 * pass the necessary input data for the VNF or an error will be thrown.
132 * The method returns the vnfId (the canonical name), a Map of VNF output
133 * attributes, and a VnfRollback object. This last object can be passed
134 * as-is to the rollbackVnf operation to undo everything that was created
135 * for the VNF. This is useful if a VNF is successfully created but the
136 * orchestrator fails on a subsequent operation.
138 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
139 * @param tenantId Openstack tenant identifier
140 * @param vnfType VNF type key, should match a VNF definition in catalog DB
141 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
142 * @param vnfName Name to be assigned to the new VNF
143 * @param inputs Map of key=value inputs for VNF stack creation
144 * @param failIfExists Flag whether already existing VNF should be considered
145 * a success or failure
146 * @param msoRequest Request tracking information for logs
147 * @param vnfId Holder for output VNF Openstack ID
148 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
149 * @param rollback Holder for returning VnfRollback object
152 public void createVnf (String cloudSiteId,
158 String volumeGroupHeatStackId,
159 Map <String, String> inputs,
160 Boolean failIfExists,
162 MsoRequest msoRequest,
163 Holder <String> vnfId,
164 Holder <Map <String, String>> outputs,
165 Holder <VnfRollback> rollback) throws VnfException {
166 // Create a hook here to catch shortcut createVf requests:
167 if (requestType != null) {
168 if (requestType.startsWith("VFMOD")) {
169 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
170 String newRequestType = requestType.substring(5);
171 String vfVolGroupHeatStackId = "";
172 String vfBaseHeatStackId = "";
174 if (volumeGroupHeatStackId != null) {
175 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
176 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
178 } catch (Exception e) {
179 // might be ok - both are just blank
180 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
182 this.createVfModule(cloudSiteId,
188 vfVolGroupHeatStackId,
201 // createVf will know if the requestType starts with "X" that it's the "old" way
202 StringBuilder newRequestTypeSb = new StringBuilder("X");
203 String vfVolGroupHeatStackId = "";
204 String vfBaseHeatStackId = "";
205 if (requestType != null) {
206 newRequestTypeSb.append(requestType);
208 this.createVfModule(cloudSiteId,
213 newRequestTypeSb.toString(),
214 vfVolGroupHeatStackId,
225 // End createVf shortcut
229 public void updateVnf (String cloudSiteId,
235 String volumeGroupHeatStackId,
236 Map <String, String> inputs,
237 MsoRequest msoRequest,
238 Holder <Map <String, String>> outputs,
239 Holder <VnfRollback> rollback) throws VnfException {
240 // As of 1707 - this method should no longer be called
241 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
242 MsoLogger.setServiceName ("UpdateVnf");
243 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
247 * This is the "Query VNF" web service implementation.
248 * It will look up a VNF by name or ID in the specified cloud and tenant.
250 * The method returns an indicator that the VNF exists, its Openstack internal
251 * ID, its status, and the set of outputs (from when the stack was created).
253 * @param cloudSiteId CLLI code of the cloud site in which to query
254 * @param tenantId Openstack tenant identifier
255 * @param vnfName VNF Name or Openstack ID
256 * @param msoRequest Request tracking information for logs
257 * @param vnfExists Flag reporting the result of the query
258 * @param vnfId Holder for output VNF Openstack ID
259 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
262 public void queryVnf (String cloudSiteId,
265 MsoRequest msoRequest,
266 Holder <Boolean> vnfExists,
267 Holder <String> vnfId,
268 Holder <VnfStatus> status,
269 Holder <Map <String, String>> outputs) throws VnfException {
270 MsoLogger.setLogContext (msoRequest);
271 MsoLogger.setServiceName ("QueryVnf");
272 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
274 // Will capture execution time for metrics
275 long startTime = System.currentTimeMillis ();
277 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
279 StackInfo heatStack = null;
280 long subStartTime = System.currentTimeMillis ();
282 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
283 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
284 } catch (MsoException me) {
285 me.addContext ("QueryVNF");
286 // Failed to query the Stack due to an openstack exception.
287 // Convert to a generic VnfException
288 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
289 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
290 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
291 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
292 throw new VnfException (me);
295 // Populate the outputs based on the returned Stack information
297 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
299 vnfExists.value = Boolean.FALSE;
300 status.value = VnfStatus.NOTFOUND;
302 outputs.value = new HashMap <String, String> (); // Return as an empty map
304 LOGGER.debug ("VNF " + vnfName + " not found");
306 vnfExists.value = Boolean.TRUE;
307 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
308 vnfId.value = heatStack.getCanonicalName ();
309 outputs.value = copyStringOutputs (heatStack.getOutputs ());
311 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
313 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
318 * This is the "Delete VNF" web service implementation.
319 * It will delete a VNF by name or ID in the specified cloud and tenant.
321 * The method has no outputs.
323 * @param cloudSiteId CLLI code of the cloud site in which to delete
324 * @param tenantId Openstack tenant identifier
325 * @param vnfName VNF Name or Openstack ID
326 * @param msoRequest Request tracking information for logs
329 public void deleteVnf (String cloudSiteId,
332 MsoRequest msoRequest) throws VnfException {
333 MsoLogger.setLogContext (msoRequest);
334 MsoLogger.setServiceName ("DeleteVnf");
335 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
336 // Will capture execution time for metrics
337 long startTime = System.currentTimeMillis ();
339 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
341 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
342 // The possible outcomes of deleteStack are a StackInfo object with status
343 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
345 long subStartTime = System.currentTimeMillis ();
347 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
348 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
349 } catch (MsoException me) {
350 me.addContext ("DeleteVNF");
351 // Failed to query the Stack due to an openstack exception.
352 // Convert to a generic VnfException
353 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
354 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
355 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
356 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
357 throw new VnfException (me);
360 // On success, nothing is returned.
361 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
366 * This web service endpoint will rollback a previous Create VNF operation.
367 * A rollback object is returned to the client in a successful creation
368 * response. The client can pass that object as-is back to the rollbackVnf
369 * operation to undo the creation.
372 public void rollbackVnf (VnfRollback rollback) throws VnfException {
373 long startTime = System.currentTimeMillis ();
374 MsoLogger.setServiceName ("RollbackVnf");
375 // rollback may be null (e.g. if stack already existed when Create was called)
376 if (rollback == null) {
377 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
378 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
382 // Get the elements of the VnfRollback object for easier access
383 String cloudSiteId = rollback.getCloudSiteId ();
384 String tenantId = rollback.getTenantId ();
385 String vnfId = rollback.getVnfId ();
387 MsoLogger.setLogContext (rollback.getMsoRequest());
389 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
391 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
393 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
394 // The possible outcomes of deleteStack are a StackInfo object with status
395 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
397 long subStartTime = System.currentTimeMillis ();
399 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
400 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
401 } catch (MsoException me) {
402 // Failed to rollback the Stack due to an openstack exception.
403 // Convert to a generic VnfException
404 me.addContext ("RollbackVNF");
405 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
406 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
407 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
408 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
409 throw new VnfException (me);
411 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
415 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
416 switch (stackStatus) {
418 return VnfStatus.ACTIVE;
420 return VnfStatus.ACTIVE;
422 return VnfStatus.FAILED;
424 return VnfStatus.UNKNOWN;
428 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
429 Map <String, String> stringOutputs = new HashMap <String, String> ();
430 for (String key : stackOutputs.keySet ()) {
431 if (stackOutputs.get (key) instanceof String) {
432 stringOutputs.put (key, (String) stackOutputs.get (key));
433 } else if (stackOutputs.get(key) instanceof Integer) {
435 String str = "" + stackOutputs.get(key);
436 stringOutputs.put(key, str);
437 } catch (Exception e) {
438 LOGGER.debug("Unable to add " + key + " to outputs",e);
440 } else if (stackOutputs.get(key) instanceof JsonNode) {
442 String str = this.convertNode((JsonNode) stackOutputs.get(key));
443 stringOutputs.put(key, str);
444 } catch (Exception e) {
445 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode",e);
447 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
449 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
450 stringOutputs.put(key, str);
451 } catch (Exception e) {
452 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap",e);
456 String str = stackOutputs.get(key).toString();
457 stringOutputs.put(key, str);
458 } catch (Exception e) {
459 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),e);
463 return stringOutputs;
466 private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
467 return new HashMap <String, Object> (stringInputs);
471 * a helper method to make sure that any resource_registry entry of the format
472 * "xx::xx" : yyy.yaml (or yyy.template)
473 * has the file name prepended with "file:///"
474 * Return a String of the environment body that's passed in.
475 * Have to be careful not to mess up the original formatting.
477 private String parseEnvironment (String environment) {
478 StringBuilder sb = new StringBuilder ();
479 try (Scanner scanner = new Scanner (environment)) {
480 scanner.useDelimiter ("\n");
482 Pattern resource = Pattern.compile ("\\s*\"\\w+::\\S+\"\\s*:");
483 LOGGER.debug ("regex pattern for finding a resource_registry: \\s*\"\\w+::\\S+\"\\s*:");
484 while (scanner.hasNextLine ()) {
485 line = scanner.nextLine ();
486 if (line.toLowerCase ().contains ("resource_registry")) {
487 sb.append (line + "\n");
488 boolean done = false;
489 // basically keep scanning until EOF or parameters: section
490 while (scanner.hasNextLine () && !done) {
491 line = scanner.nextLine ();
492 if ("parameters:".equalsIgnoreCase (line.trim ())) {
493 sb.append (line + "\n");
497 Matcher m = resource.matcher (line);
499 sb.append (m.group ());
500 String secondPart = line.substring (m.end ()).trim ();
501 String output = secondPart;
502 if (secondPart.endsWith (".yaml")
503 || secondPart.endsWith (".template") && !secondPart.startsWith ("file:///")) {
504 output = "file:///" + secondPart;
505 LOGGER.debug ("changed " + secondPart + " to " + output);
506 } // don't do anything if it's not .yaml or .template
507 sb.append (" " + output + "\n");
509 sb.append (line + "\n");
513 sb.append (line + "\n");
518 } catch (Exception e) {
519 LOGGER.debug ("Error trying to scan " + environment, e);
522 return sb.toString ();
526 * helper class to add file:/// to the Provider_Resource_File entry in HEAT_NESTED_TEMPLATE
527 * and the File_Name entry in HEAT_FILES if the file:/// part is missing.
529 private String enforceFilePrefix (String string) {
530 if (string.trim ().startsWith ("file:///")) {
534 if (string.trim ().endsWith (".yaml") || string.trim ().endsWith (".template")) {
535 // only .yaml or .template are valid anyway - otherwise don't bother
536 return "file:///" + string.trim ();
538 LOGGER.debug (string + " is NOT a .yaml or .template file");
543 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
545 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
546 if (inputs == null) {
549 else if (inputs.size() < 1) {
550 sb.append("\tEMPTY");
552 for (String str : inputs.keySet()) {
555 outputString = inputs.get(str).toString();
556 } catch (Exception e) {
557 LOGGER.debug("Exception :",e);
558 outputString = "Unable to call toString() on the value for " + str;
560 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
563 LOGGER.debug(sb.toString());
567 private void sendMapToDebug(Map<String, String> inputs) {
569 StringBuilder sb = new StringBuilder("inputs:");
570 if (inputs == null) {
573 else if (inputs.size() < 1) {
574 sb.append("\tEMPTY");
576 for (String str : inputs.keySet()) {
577 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
580 LOGGER.debug(sb.toString());
584 private String convertNode(final JsonNode node) {
586 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
587 final String json = JSON_MAPPER.writeValueAsString(obj);
589 } catch (JsonParseException jpe) {
590 LOGGER.debug("Error converting json to string " + jpe.getMessage(),jpe);
591 } catch (Exception e) {
592 LOGGER.debug("Error converting json to string " + e.getMessage(),e);
594 return "[Error converting json to string]";
597 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
598 if (objectMap == null) {
601 Map<String, String> stringMap = new HashMap<String, String>();
602 for (String key : objectMap.keySet()) {
603 if (!stringMap.containsKey(key)) {
604 Object obj = objectMap.get(key);
605 if (obj instanceof String) {
606 stringMap.put(key, (String) objectMap.get(key));
607 } else if (obj instanceof JsonNode ){
608 // This is a bit of mess - but I think it's the least impacting
609 // let's convert it BACK to a string - then it will get converted back later
611 String str = this.convertNode((JsonNode) obj);
612 stringMap.put(key, str);
613 } catch (Exception e) {
614 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
615 //okay in this instance - only string values (fqdn) are expected to be needed
617 } else if (obj instanceof java.util.LinkedHashMap) {
618 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
620 String str = JSON_MAPPER.writeValueAsString(obj);
621 stringMap.put(key, str);
622 } catch (Exception e) {
623 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
625 } else if (obj instanceof Integer) {
627 String str = "" + obj;
628 stringMap.put(key, str);
629 } catch (Exception e) {
630 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
634 String str = obj.toString();
635 stringMap.put(key, str);
636 } catch (Exception e) {
637 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
647 public void createVfModule(String cloudSiteId,
653 String volumeGroupHeatStackId,
654 String baseVfHeatStackId,
655 String modelCustomizationUuid,
656 Map <String, String> inputs,
657 Boolean failIfExists,
659 MsoRequest msoRequest,
660 Holder <String> vnfId,
661 Holder <Map <String, String>> outputs,
662 Holder <VnfRollback> rollback) throws VnfException {
663 String vfModuleName = vnfName;
664 String vfModuleType = vnfType;
665 String vfVersion = vnfVersion;
666 String mcu = modelCustomizationUuid;
667 boolean useMCUuid = false;
668 if (mcu != null && !mcu.isEmpty()) {
669 if (mcu.equalsIgnoreCase("null")) {
670 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
674 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
678 MsoLogger.setLogContext (msoRequest);
679 MsoLogger.setServiceName ("CreateVfModule");
680 String requestTypeString = "";
681 if (requestType != null && !requestType.equals("")) {
682 requestTypeString = requestType;
684 String nestedStackId = null;
685 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
686 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
687 nestedStackId = volumeGroupHeatStackId;
690 String nestedBaseStackId = null;
691 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
692 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
693 nestedBaseStackId = baseVfHeatStackId;
697 if (inputs == null) {
698 // Create an empty set of inputs
699 inputs = new HashMap<String,String>();
700 LOGGER.debug("inputs == null - setting to empty");
702 this.sendMapToDebug(inputs);
704 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
705 boolean oldWay = false;
706 if (requestTypeString.startsWith("X")) {
708 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
709 requestTypeString = requestTypeString.substring(1);
712 // 1607 - let's parse out the request type we're being sent
713 boolean isBaseRequest = false;
714 boolean isVolumeRequest = false;
715 if (requestTypeString.startsWith("VOLUME")) {
716 isVolumeRequest = true;
719 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
720 // Will capture execution time for metrics
721 long startTime = System.currentTimeMillis ();
723 // Build a default rollback object (no actions performed)
724 VnfRollback vfRollback = new VnfRollback();
725 vfRollback.setCloudSiteId(cloudSiteId);
726 vfRollback.setTenantId(tenantId);
727 vfRollback.setMsoRequest(msoRequest);
728 vfRollback.setRequestType(requestTypeString);
729 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
730 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
731 vfRollback.setIsBase(isBaseRequest);
732 vfRollback.setModelCustomizationUuid(mcu);
734 // First, look up to see if the VF already exists.
735 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
737 StackInfo heatStack = null;
738 long subStartTime1 = System.currentTimeMillis ();
740 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
741 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
742 } catch (MsoException me) {
743 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
744 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
745 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
746 // Failed to query the Stack due to an openstack exception.
747 // Convert to a generic VnfException
748 me.addContext ("CreateVFModule");
749 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
750 throw new VnfException (me);
752 // New with 1607 - more precise handling/messaging if the stack already exists
753 if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
754 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
755 HeatStatus status = heatStack.getStatus();
756 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
757 // fail - it's in progress - return meaningful error
758 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.";
759 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
760 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
761 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
763 if (status == HeatStatus.FAILED) {
764 // fail - it exists and is in a FAILED state
765 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
766 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
767 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
768 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
770 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
771 // fail - it exists and is in a FAILED state
772 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
773 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");
774 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
775 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
777 if (status == HeatStatus.CREATED) {
779 if (failIfExists != null && failIfExists) {
780 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
781 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
782 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
783 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
785 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
786 // Populate the outputs from the existing stack.
787 vnfId.value = heatStack.getCanonicalName ();
788 outputs.value = copyStringOutputs (heatStack.getOutputs ());
789 rollback.value = vfRollback; // Default rollback - no updates performed
792 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
797 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
798 StackInfo nestedHeatStack = null;
799 long subStartTime2 = System.currentTimeMillis ();
800 Map<String, Object> nestedVolumeOutputs = null;
801 if (nestedStackId != null) {
803 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
804 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
805 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
806 } catch (MsoException me) {
807 // Failed to query the Stack due to an openstack exception.
808 // Convert to a generic VnfException
809 me.addContext ("CreateVFModule");
810 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
811 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
812 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
813 LOGGER.debug("ERROR trying to query nested stack= " + error);
814 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
815 throw new VnfException (me);
817 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
818 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
819 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
820 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
822 throw new VnfException (error, MsoExceptionCategory.USERDATA);
824 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
825 //this.sendMapToDebug(inputs);
826 nestedVolumeOutputs = nestedHeatStack.getOutputs();
827 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
829 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
830 //this.sendMapToDebug(inputs);
834 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
835 StackInfo nestedBaseHeatStack = null;
836 long subStartTime3 = System.currentTimeMillis ();
837 Map<String, Object> baseStackOutputs = null;
838 if (nestedBaseStackId != null) {
840 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
841 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
842 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
843 } catch (MsoException me) {
844 // Failed to query the Stack due to an openstack exception.
845 // Convert to a generic VnfException
846 me.addContext ("CreateVFModule");
847 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
848 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
849 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
850 LOGGER.debug("ERROR trying to query nested base stack= " + error);
851 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
852 throw new VnfException (me);
854 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
855 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
856 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");
857 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
859 throw new VnfException (error, MsoExceptionCategory.USERDATA);
861 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
862 //this.sendMapToDebug(inputs);
863 baseStackOutputs = nestedBaseHeatStack.getOutputs();
864 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
866 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
867 //this.sendMapToDebug(inputs);
871 // Ready to deploy the new VNF
873 CatalogDatabase db = CatalogDatabase.getInstance();
878 VnfResource vnfResource = null;
879 VfModuleCustomization vfmc = null;
880 LOGGER.debug("version: " + vfVersion);
882 // 1707 - db refactoring
883 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
884 vf = vfmc != null ? vfmc.getVfModule() : null;
885 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
886 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
888 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
889 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
890 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
891 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
892 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
893 throw new VnfException(error, MsoExceptionCategory.USERDATA);
895 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
898 isBaseRequest = true;
899 LOGGER.debug("This is a BASE VF request!");
901 LOGGER.debug("This is *not* a BASE VF request!");
902 if (!isVolumeRequest && nestedBaseStackId == null) {
903 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
909 // Need to handle old and new schema methods - for a time. Try the new way first.
910 if (vfVersion != null && !vfVersion.isEmpty()) {
911 vf = db.getVfModuleType(vfModuleType, vfVersion);
913 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME");
914 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
916 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
920 vf = db.getVfModuleType(vfModuleType);
922 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
923 vf = db.getVfModuleModelName(vfModuleType);
925 LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
930 String error = "Create VF Module: Unable to determine specific VF Module Type: "
932 if (vfVersion != null && !vfVersion.isEmpty()) {
933 error += " with version = " + vfVersion;
935 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
936 "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type");
937 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
938 throw new VnfException(error, MsoExceptionCategory.USERDATA);
940 LOGGER.debug("Got VF module definition from Catalog: "
944 isBaseRequest = true;
945 LOGGER.debug("This is a BASE VF request!");
947 LOGGER.debug("This is *not* a BASE VF request!");
948 if (!isVolumeRequest && nestedBaseStackId == null) {
949 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
953 else { // This is to support gamma only - get info from vnf_resource table
954 if (vfVersion != null && !vfVersion.isEmpty()) {
955 vnfResource = db.getVnfResource(vnfType, vnfVersion);
957 vnfResource = db.getVnfResource(vnfType);
959 if (vnfResource == null) {
960 String error = "Create VNF: Unknown VNF Type: " + vnfType;
961 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
962 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
963 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
964 throw new VnfException(error, MsoExceptionCategory.USERDATA);
966 LOGGER.debug("Got VNF module definition from Catalog: "
967 + vnfResource.toString());
969 // By here - we have either a vf or vnfResource
971 //1607 - Add version check
972 // First - see if it's in the VnfResource record
973 // if we have a vf Module - then we have to query to get the VnfResource record.
975 if (vf.getVnfResourceModelUUId() != null) {
976 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
977 //vnfResource = db.getVnfResourceById(vnfResourceId);
978 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
979 if (vnfResource == null) {
980 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
984 String minVersionVnf = null;
985 String maxVersionVnf = null;
986 if (vnfResource != null) {
988 minVersionVnf = vnfResource.getAicVersionMin();
989 maxVersionVnf = vnfResource.getAicVersionMax();
990 } catch (Exception e) {
991 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
992 minVersionVnf = null;
993 maxVersionVnf = null;
995 if (minVersionVnf != null && minVersionVnf.equals("")) {
996 minVersionVnf = null;
998 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
999 maxVersionVnf = null;
1002 if (minVersionVnf != null && maxVersionVnf != null) {
1003 MavenLikeVersioning aicV = new MavenLikeVersioning();
1004 CloudSite cloudSite = null;
1005 String aicVersion = "";
1006 if (this.cloudConfig == null) {
1007 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1010 if (this.cloudConfig != null) {
1011 cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1012 if (cloudSite != null) {
1013 aicV.setVersion(cloudSite.getAic_version());
1014 // Add code to handle unexpected values in here
1015 boolean moreThanMin = true;
1016 boolean equalToMin = true;
1017 boolean moreThanMax = true;
1018 boolean equalToMax = true;
1019 boolean doNotTest = false;
1021 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1022 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1023 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1024 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1025 } catch (Exception e) {
1026 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e);
1030 if ((moreThanMin || equalToMin) // aic >= min
1031 && (equalToMax || !(moreThanMax))) { //aic <= max
1032 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1035 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();
1036 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1037 LOGGER.debug(error);
1038 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1041 LOGGER.debug("bypassing testing AIC version...");
1043 } // let this error out downstream to avoid introducing uncertainty at this stage
1045 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1048 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1050 // End Version check 1607
1052 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
1053 // with VNF_RESOURCE - we use the old methods.
1054 //Integer heatTemplateId = null;
1055 //Integer heatEnvtId = null;
1057 String heatTemplateArtifactUuid = null;
1058 String heatEnvironmentArtifactUuid = null;
1061 if (isVolumeRequest) {
1062 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1063 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1065 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1066 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1069 if (isVolumeRequest) {
1070 LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
1072 VnfComponent vnfComponent = null;
1073 vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME");
1074 if (vnfComponent == null) {
1075 String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME";
1076 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry");
1077 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1078 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1080 heatTemplateId = vnfComponent.getHeatTemplateId();
1081 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1085 heatTemplateArtifactUuid = vnfResource.getTemplateId();
1086 heatEnvironmentArtifactUuid = null;
1089 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1090 HeatTemplate heatTemplate = null;
1091 if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) {
1092 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1093 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1094 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1095 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1096 MsoAlarmLogger.CRITICAL, error);
1097 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1099 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1101 if (heatTemplate == null) {
1102 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1103 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1105 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1106 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1107 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1108 MsoAlarmLogger.CRITICAL, error);
1109 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1111 LOGGER.debug("Got HEAT Template from DB");
1113 HeatEnvironment heatEnvironment = null;
1114 String heatEnvironmentString = null;
1116 if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals("")) {
1117 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1118 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1119 if (heatEnvironment == null) {
1120 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1121 + ", Environment ID="
1122 + heatEnvironmentArtifactUuid;
1123 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1124 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1125 // Alarm on this error, configuration must be fixed
1126 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1128 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1130 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1131 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1132 LOGGER.debug ("after parsing: " + heatEnvironmentString);
1135 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
1138 // 1510 - Add the files: for nested templates *if* there are any
1139 LOGGER.debug ("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1140 + heatTemplate.getArtifactUuid());
1141 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid());
1142 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1143 if (nestedTemplates != null) {
1144 // for debugging print them out
1145 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1146 for (String providerResourceFile : nestedTemplates.keySet ()) {
1147 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1148 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1149 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1150 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1153 LOGGER.debug ("No nested templates found - nothing to do here");
1154 nestedTemplatesChecked = null; // just to make sure
1157 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1158 // *if* there are any
1159 Map<String, HeatFiles> heatFiles = null;
1160 Map<String, Object> heatFilesObjects = new HashMap<String, Object>();
1162 // Add ability to turn on adding get_files with volume requests (by property).
1163 boolean addGetFilesOnVolumeReq = false;
1165 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1166 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1167 addGetFilesOnVolumeReq = true;
1168 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1170 } catch (Exception e) {
1171 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1174 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1176 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1177 //heatFiles = db.getHeatFiles(vnfResource.getId());
1179 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1180 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1181 + vf.getModelUUID());
1183 .getHeatFilesForVfModule(vf.getModelUUID());
1185 if (heatFiles != null) {
1186 // add these to stack - to be done in createStack
1187 // here, we will map them to Map<String, Object> from
1188 // Map<String, HeatFiles>
1189 // this will match the nested templates format
1190 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1192 for (String heatFileName : heatFiles.keySet()) {
1193 if (heatFileName.startsWith("_ERROR|")) {
1194 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1195 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1196 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1197 LOGGER.debug(error);
1198 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1199 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1200 // Alarm on this error, configuration must be fixed
1201 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1202 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1204 String heatFileBody = heatFiles.get(heatFileName)
1206 String heatFileNameChecked = heatFileName;
1207 LOGGER.debug(heatFileNameChecked + " -> "
1209 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1212 LOGGER.debug("No heat files found -nothing to do here");
1213 heatFilesObjects = null;
1216 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1219 // Check that required parameters have been supplied
1220 String missingParams = null;
1221 List <String> paramList = new ArrayList <String> ();
1223 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1224 // supplied an alias. Only check if we don't find it initially.
1225 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1226 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1228 boolean haveEnvironmentParameters = false;
1229 boolean checkRequiredParameters = true;
1231 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1232 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1233 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1234 checkRequiredParameters = false;
1235 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1236 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1238 } catch (Exception e) {
1239 // No problem - default is true
1240 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1242 // 1604 - Add enhanced environment & parameter checking
1243 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1244 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1245 // Note this also removes any comments
1246 MsoHeatEnvironmentEntry mhee = null;
1247 if (heatEnvironmentString != null && heatEnvironmentString.contains ("parameters:")) {
1248 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1249 LOGGER.debug("Enhanced environment checking enabled - 1604");
1250 haveEnvironmentParameters = true;
1251 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1252 //LOGGER.debug("About to create MHEE with " + sb);
1253 mhee = new MsoHeatEnvironmentEntry(sb);
1254 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1255 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1256 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1258 if (!mhee.isValid()) {
1259 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1261 sb2.append("\nEnvironment:");
1262 sb2.append(mhee.toFullString());
1264 LOGGER.debug(sb2.toString());
1266 LOGGER.debug("NO ENVIRONMENT for this entry");
1268 // New with 1707 - all variables converted to their native object types
1269 HashMap<String, Object> goldenInputs = null;
1271 LOGGER.debug("Now handle the inputs....first convert");
1272 ArrayList<String> parameterNames = new ArrayList<String>();
1273 HashMap<String, String> aliasToParam = new HashMap<String, String>();
1274 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1277 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1278 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1279 parameterNames.add(htp.getParamName());
1280 if (htp.getParamAlias() != null && !htp.getParamAlias().equals("")) {
1281 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1282 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1286 LOGGER.debug(sb.toString());
1287 } catch (Exception e) {
1288 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e);
1290 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1291 // Map<String, Object> - where the object matches the param type identified in the template
1292 // This will also not copy over params that aren't identified in the template
1293 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1294 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1295 LOGGER.debug("Now add in the base stack outputs if applicable");
1296 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1297 // Step 3 - add the volume inputs if any
1298 LOGGER.debug("Now add in the volume stack outputs if applicable");
1299 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1300 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1302 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1303 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1305 + parm.isRequired ()
1307 + parm.getParamAlias ());
1309 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1310 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1311 LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment");
1312 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1313 LOGGER.debug ("Required parameter " + parm.getParamName ()
1314 + " appears to be in environment - do not count as missing");
1316 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1317 if (missingParams == null) {
1318 missingParams = parm.getParamName ();
1320 missingParams += "," + parm.getParamName ();
1324 paramList.add (parm.getParamName ());
1326 if (missingParams != null) {
1327 if (checkRequiredParameters) {
1328 // Problem - missing one or more required parameters
1329 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1330 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1331 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1332 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1334 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1337 LOGGER.debug ("No missing parameters found - ok to proceed");
1339 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1340 // and it causes problems with json that has arrays
1341 String newEnvironmentString = null;
1343 newEnvironmentString = mhee.getRawEntry().toString();
1346 // "Fix" the template if it has CR/LF (getting this from Oracle)
1347 String template = heatTemplate.getHeatTemplate ();
1348 template = template.replaceAll ("\r\n", "\n");
1350 // Have the tenant. Now deploy the stack itself
1351 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1352 // because we already checked for those.
1353 long createStackStarttime = System.currentTimeMillis ();
1355 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1356 // heatTemplate.getTimeoutMinutes());
1357 if (backout == null) {
1361 LOGGER.debug("heat is not null!!");
1363 heatStack = heat.createStack (cloudSiteId,
1369 heatTemplate.getTimeoutMinutes (),
1370 newEnvironmentString,
1371 nestedTemplatesChecked,
1373 backout.booleanValue());
1374 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1375 } catch (MsoException me) {
1376 me.addContext ("CreateVFModule");
1377 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1378 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1379 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1380 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1381 throw new VnfException (me);
1382 } catch (NullPointerException npe) {
1383 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1384 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1385 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1386 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1387 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1388 //npe.addContext ("CreateVNF");
1389 throw new VnfException ("NullPointerException during heat.createStack");
1390 } catch (Exception e) {
1391 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1392 LOGGER.debug("unhandled exception at heat.createStack",e);
1393 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1394 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1396 } catch (Exception e) {
1397 LOGGER.debug("unhandled exception in create VF",e);
1398 throw new VnfException("Exception during create VF " + e.getMessage());
1401 // Make sure DB session is closed
1405 // Reach this point if createStack is successful.
1406 // Populate remaining rollback info and response parameters.
1407 vfRollback.setVnfId (heatStack.getCanonicalName ());
1408 vfRollback.setVnfCreated (true);
1410 vnfId.value = heatStack.getCanonicalName ();
1411 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1412 rollback.value = vfRollback;
1414 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1415 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1420 public void deleteVfModule (String cloudSiteId,
1423 MsoRequest msoRequest,
1424 Holder <Map <String, String>> outputs) throws VnfException {
1425 MsoLogger.setLogContext (msoRequest);
1426 MsoLogger.setServiceName ("DeleteVf");
1427 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1428 // Will capture execution time for metrics
1429 long startTime = System.currentTimeMillis ();
1431 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1433 // 1702 capture the output parameters on a delete
1434 // so we'll need to query first
1435 Map<String, Object> stackOutputs = null;
1437 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1438 } catch (MsoException me) {
1439 // Failed to query the Stack due to an openstack exception.
1440 // Convert to a generic VnfException
1441 me.addContext ("DeleteVFModule");
1442 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1443 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1444 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1445 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1446 throw new VnfException (me);
1448 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1449 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1451 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1452 // The possible outcomes of deleteStack are a StackInfo object with status
1453 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1455 long subStartTime = System.currentTimeMillis ();
1457 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1458 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1459 } catch (MsoException me) {
1460 me.addContext ("DeleteVNF");
1461 // Failed to query the Stack due to an openstack exception.
1462 // Convert to a generic VnfException
1463 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1464 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1465 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1466 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1467 throw new VnfException (me);
1470 // On success, nothing is returned.
1471 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1476 public void updateVfModule (String cloudSiteId,
1482 String volumeGroupHeatStackId,
1483 String baseVfHeatStackId,
1484 String vfModuleStackId,
1485 String modelCustomizationUuid,
1486 Map <String, String> inputs,
1487 MsoRequest msoRequest,
1488 Holder <Map <String, String>> outputs,
1489 Holder <VnfRollback> rollback) throws VnfException {
1490 String vfModuleName = vnfName;
1491 String vfModuleType = vnfType;
1492 String vfVersion = vnfVersion;
1493 String methodName = "updateVfModule";
1494 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1495 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1496 MsoLogger.setServiceName (serviceName);
1498 StringBuilder sbInit = new StringBuilder();
1499 sbInit.append("updateVfModule: \n");
1500 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1501 sbInit.append("tenantId=" + tenantId + "\n");
1502 sbInit.append("vnfType=" + vnfType + "\n");
1503 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1504 sbInit.append("vnfName=" + vnfName + "\n");
1505 sbInit.append("requestType=" + requestType + "\n");
1506 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1507 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1508 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1509 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1510 LOGGER.debug(sbInit.toString());
1512 String mcu = modelCustomizationUuid;
1513 boolean useMCUuid = false;
1514 if (mcu != null && !mcu.isEmpty()) {
1515 if (mcu.equalsIgnoreCase("null")) {
1516 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1520 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1525 String requestTypeString = "";
1526 if (requestType != null && !requestType.equals("")) {
1527 requestTypeString = requestType;
1529 String nestedStackId = null;
1530 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1531 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1532 nestedStackId = volumeGroupHeatStackId;
1535 String nestedBaseStackId = null;
1536 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1537 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1538 nestedBaseStackId = baseVfHeatStackId;
1542 if (inputs == null) {
1543 // Create an empty set of inputs
1544 inputs = new HashMap<String,String>();
1545 LOGGER.debug("inputs == null - setting to empty");
1547 this.sendMapToDebug(inputs);
1549 boolean isBaseRequest = false;
1550 boolean isVolumeRequest = false;
1551 if (requestTypeString.startsWith("VOLUME")) {
1552 isVolumeRequest = true;
1554 if (vfModuleName == null || vfModuleName.trim().equals("")) {
1555 if (vfModuleStackId != null) {
1556 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1560 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1561 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1563 // Will capture execution time for metrics
1564 long startTime = System.currentTimeMillis ();
1566 // Build a default rollback object (no actions performed)
1567 VnfRollback vfRollback = new VnfRollback ();
1568 vfRollback.setCloudSiteId (cloudSiteId);
1569 vfRollback.setTenantId (tenantId);
1570 vfRollback.setMsoRequest (msoRequest);
1571 vfRollback.setRequestType(requestTypeString);
1572 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1573 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1574 vfRollback.setIsBase(isBaseRequest);
1575 vfRollback.setVfModuleStackId(vfModuleStackId);
1576 vfRollback.setModelCustomizationUuid(mcu);
1578 // First, look up to see if the VNF already exists.
1579 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1580 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1582 StackInfo heatStack = null;
1583 long queryStackStarttime = System.currentTimeMillis ();
1584 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1586 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1587 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1588 } catch (MsoException me) {
1589 // Failed to query the Stack due to an openstack exception.
1590 // Convert to a generic VnfException
1591 me.addContext ("UpdateVFModule");
1592 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1593 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1594 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1595 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1596 throw new VnfException (me);
1599 //TODO - do we need to check for the other status possibilities?
1600 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1602 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1603 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1604 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1605 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1607 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1608 // Populate the outputs from the existing stack.
1609 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1610 rollback.value = vfRollback; // Default rollback - no updates performed
1613 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1614 StackInfo nestedHeatStack = null;
1615 long queryStackStarttime2 = System.currentTimeMillis ();
1616 Map<String, Object> nestedVolumeOutputs = null;
1617 if (nestedStackId != null) {
1619 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1620 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1621 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1622 } catch (MsoException me) {
1623 // Failed to query the Stack due to an openstack exception.
1624 // Convert to a generic VnfException
1625 me.addContext ("UpdateVFModule");
1626 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1627 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1628 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1629 LOGGER.debug("ERROR trying to query nested stack= " + error);
1630 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1631 throw new VnfException (me);
1633 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1634 MsoLogger.setServiceName (serviceName);
1635 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1636 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1637 LOGGER.debug(error);
1638 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1639 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1641 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1642 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1643 //this.sendMapToDebug(inputs);
1644 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1646 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1647 //this.sendMapToDebug(inputs);
1650 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1651 StackInfo nestedBaseHeatStack = null;
1652 Map<String, Object> baseStackOutputs = null;
1653 if (nestedBaseStackId != null) {
1654 long queryStackStarttime3 = System.currentTimeMillis ();
1656 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1657 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1658 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1659 } catch (MsoException me) {
1660 // Failed to query the Stack due to an openstack exception.
1661 // Convert to a generic VnfException
1662 me.addContext ("UpdateVfModule");
1663 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1664 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1665 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1666 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1667 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1668 throw new VnfException (me);
1670 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1671 MsoLogger.setServiceName (serviceName);
1672 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1673 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1674 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1675 LOGGER.debug(error);
1676 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1678 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1679 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1680 //this.sendMapToDebug(inputs);
1681 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1683 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1684 //this.sendMapToDebug(inputs);
1688 // Ready to deploy the new VNF
1690 // Get a handle to the Catalog Database
1691 CatalogDatabase db = CatalogDatabase.getInstance();
1693 // Make sure DB session is closed
1695 // Retrieve the VF definition
1696 VnfResource vnfResource = null;
1698 VfModuleCustomization vfmc = null;
1700 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1701 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1702 vf = vfmc != null ? vfmc.getVfModule() : null;
1704 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1707 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1710 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1711 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1712 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1713 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1715 LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
1717 isBaseRequest = true;
1718 LOGGER.debug("This a BASE update request");
1720 LOGGER.debug("This is *not* a BASE VF update request");
1721 if (!isVolumeRequest && nestedBaseStackId == null) {
1722 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1726 //1607 - Add version check
1727 // First - see if it's in the VnfResource record
1728 // if we have a vf Module - then we have to query to get the VnfResource record.
1729 if (vf.getVnfResourceModelUUId() != null) {
1730 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1731 //vnfResource = db.getVnfResourceById(vnfResourceId);
1732 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1733 if (vnfResource == null) {
1734 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1737 String minVersionVnf = null;
1738 String maxVersionVnf = null;
1739 if (vnfResource != null) {
1741 minVersionVnf = vnfResource.getAicVersionMin();
1742 maxVersionVnf = vnfResource.getAicVersionMax();
1743 } catch (Exception e) {
1744 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1745 minVersionVnf = null;
1746 maxVersionVnf = null;
1748 if (minVersionVnf != null && minVersionVnf.equals("")) {
1749 minVersionVnf = null;
1751 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1752 maxVersionVnf = null;
1755 if (minVersionVnf != null && maxVersionVnf != null) {
1756 MavenLikeVersioning aicV = new MavenLikeVersioning();
1757 CloudSite cloudSite = null;
1758 //String aicVersion = "";
1759 if (this.cloudConfig == null) {
1760 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1763 if (this.cloudConfig != null) {
1764 cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1765 if (cloudSite != null) {
1766 aicV.setVersion(cloudSite.getAic_version());
1767 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1768 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV.isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1769 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1772 String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1773 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1774 LOGGER.debug(error);
1775 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1777 } // let this error out downstream to avoid introducing uncertainty at this stage
1779 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1783 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1785 // End Version check 1607
1787 String heatTemplateArtifactUuid = null;
1788 String heatEnvironmentArtifactUuid = null;
1790 HeatTemplate heatTemplate = null;
1791 if (isVolumeRequest) {
1792 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1793 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1795 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1796 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1798 if (heatTemplateArtifactUuid == null) {
1799 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1800 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1801 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1802 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1803 MsoAlarmLogger.CRITICAL, error);
1804 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1806 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1809 if (heatTemplate == null) {
1810 String error = "Update VNF: undefined Heat Template. VF="
1811 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1812 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1814 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1815 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1816 // Alarm on this error, configuration must be fixed
1817 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1818 MsoAlarmLogger.CRITICAL, error);
1820 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1823 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
1825 // Add check for any Environment variable
1826 HeatEnvironment heatEnvironment = null;
1827 String heatEnvironmentString = null;
1829 if (heatEnvironmentArtifactUuid != null) {
1830 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1831 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1832 if (heatEnvironment == null) {
1834 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1835 + ", Environment ID="
1836 + heatEnvironmentArtifactUuid;
1837 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1838 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1839 // Alarm on this error, configuration must be fixed
1840 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1842 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1844 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1845 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1846 LOGGER.debug ("After parsing: " + heatEnvironmentString);
1849 LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType);
1853 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1854 + heatTemplate.getArtifactUuid ());
1855 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid ());
1856 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1857 if (nestedTemplates != null) {
1858 // for debugging print them out
1859 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1860 for (String providerResourceFile : nestedTemplates.keySet ()) {
1861 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1862 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1863 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1864 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1867 LOGGER.debug ("No nested templates found - nothing to do here");
1868 nestedTemplatesChecked = null;
1871 // Also add the files: for any get_files associated with this VfModule
1872 // *if* there are any
1873 LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1874 + vf.getModelUUID());
1876 Map <String, HeatFiles> heatFiles = null;
1877 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1878 Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
1880 // Add ability to turn on adding get_files with volume requests (by property).
1881 boolean addGetFilesOnVolumeReq = false;
1883 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1884 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1885 addGetFilesOnVolumeReq = true;
1886 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1888 } catch (Exception e) {
1889 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1891 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1892 LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1893 + vf.getModelUUID());
1895 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1896 if (heatFiles != null) {
1897 // add these to stack - to be done in createStack
1898 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1899 // this will match the nested templates format
1900 LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
1902 for (String heatFileName : heatFiles.keySet ()) {
1903 if (heatFileName.startsWith("_ERROR|")) {
1904 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1905 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1906 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1907 LOGGER.debug(error);
1908 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1909 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1910 // Alarm on this error, configuration must be fixed
1911 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1912 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1914 String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
1915 LOGGER.debug (heatFileName + " -> " + heatFileBody);
1916 heatFilesObjects.put (heatFileName, heatFileBody);
1919 LOGGER.debug ("No heat files found -nothing to do here");
1920 heatFilesObjects = null;
1924 // Check that required parameters have been supplied
1925 String missingParams = null;
1926 List <String> paramList = new ArrayList <String> ();
1928 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1929 // supplied an alias. Only check if we don't find it initially.
1930 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1931 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1933 boolean haveEnvironmentParameters = false;
1934 boolean checkRequiredParameters = true;
1936 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1937 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1938 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1939 checkRequiredParameters = false;
1940 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1941 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1943 } catch (Exception e) {
1944 // No problem - default is true
1945 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1947 // 1604 - Add enhanced environment & parameter checking
1948 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1949 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1950 // Note this also removes any comments
1951 MsoHeatEnvironmentEntry mhee = null;
1952 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) {
1953 LOGGER.debug("Enhanced environment checking enabled - 1604");
1954 haveEnvironmentParameters = true;
1955 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1956 //LOGGER.debug("About to create MHEE with " + sb);
1957 mhee = new MsoHeatEnvironmentEntry(sb);
1958 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1959 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1960 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1962 if (!mhee.isValid()) {
1963 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1965 sb2.append("\nEnvironment:");
1966 sb2.append(mhee.toFullString());
1968 LOGGER.debug(sb2.toString());
1970 LOGGER.debug("NO ENVIRONMENT for this entry");
1973 // New for 1607 - support params of json type
1974 HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
1975 boolean hasJson = false;
1977 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1978 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1980 + parm.isRequired ()
1982 + parm.getParamAlias ());
1984 String parameterType = parm.getParamType();
1985 if (parameterType == null || parameterType.trim().equals("")) {
1986 parameterType = "String";
1988 JsonNode jsonNode = null;
1989 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
1990 if (inputs.containsKey(parm.getParamName()) ) {
1992 String jsonString = null;
1994 jsonString = inputs.get(parm.getParamName());
1995 jsonNode = new ObjectMapper().readTree(jsonString);
1996 } catch (JsonParseException jpe) {
1997 //TODO - what to do here?
1998 //for now - send the error to debug, but just leave it as a String
1999 String errorMessage = jpe.getMessage();
2000 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
2003 } catch (Exception e) {
2005 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2009 if (jsonNode != null) {
2010 jsonParams.put(parm.getParamName(), jsonNode);
2012 } else if (inputs.containsKey(parm.getParamAlias())) {
2014 String jsonString = null;
2016 jsonString = inputs.get(parm.getParamAlias());
2017 jsonNode = new ObjectMapper().readTree(jsonString);
2018 } catch (JsonParseException jpe) {
2019 //TODO - what to do here?
2020 //for now - send the error to debug, but just leave it as a String
2021 String errorMessage = jpe.getMessage();
2022 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
2025 } catch (Exception e) {
2027 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2031 if (jsonNode != null) {
2032 // Notice here - we add it to the jsonParams hashMap with the actual name -
2033 // then manipulate the inputs so when we check for aliases below - it will not
2035 jsonParams.put(parm.getParamName(), jsonNode);
2036 inputs.remove(parm.getParamAlias());
2037 inputs.put(parm.getParamName(), jsonString);
2039 } //TODO add a check for the parameter in the env file
2042 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
2043 if (inputs.containsKey (parm.getParamAlias ())) {
2044 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2045 String realParamName = parm.getParamName ();
2046 String alias = parm.getParamAlias ();
2047 String value = inputs.get (alias);
2048 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
2053 inputs.remove (alias);
2054 inputs.put (realParamName, value);
2055 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
2057 // enhanced - check if it's in the Environment (note: that method
2058 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2060 LOGGER.debug ("Required parameter " + parm.getParamName ()
2061 + " appears to be in environment - do not count as missing");
2064 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
2065 if (missingParams == null) {
2066 missingParams = parm.getParamName ();
2068 missingParams += "," + parm.getParamName ();
2072 paramList.add (parm.getParamName ());
2074 if (missingParams != null) {
2075 // Problem - missing one or more required parameters
2076 if (checkRequiredParameters) {
2077 String error = "Update VNF: Missing Required inputs: " + missingParams;
2078 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2079 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
2080 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2082 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
2085 LOGGER.debug ("No missing parameters found - ok to proceed");
2088 // Just submit the envt entry as received from the database
2089 String newEnvironmentString = null;
2091 newEnvironmentString = mhee.getRawEntry().toString();
2094 // Remove any extraneous parameters (don't throw an error)
2095 if (inputs != null) {
2096 List <String> extraParams = new ArrayList <String> ();
2097 extraParams.addAll (inputs.keySet ());
2098 // This is not a valid parameter for this template
2099 extraParams.removeAll (paramList);
2100 if (!extraParams.isEmpty ()) {
2101 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
2102 inputs.keySet ().removeAll (extraParams);
2105 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2106 Map<String, Object> inputsTwo = null;
2107 if (hasJson && jsonParams.size() > 0) {
2108 inputsTwo = new HashMap<String, Object>();
2109 for (String keyParamName : inputs.keySet()) {
2110 if (jsonParams.containsKey(keyParamName)) {
2111 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2113 inputsTwo.put(keyParamName, inputs.get(keyParamName));
2118 // "Fix" the template if it has CR/LF (getting this from Oracle)
2119 String template = heatTemplate.getHeatTemplate ();
2120 template = template.replaceAll ("\r\n", "\n");
2122 // Have the tenant. Now deploy the stack itself
2123 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2124 // because we already checked for those.
2125 long updateStackStarttime = System.currentTimeMillis ();
2128 heatStack = heatU.updateStack (cloudSiteId,
2132 copyStringInputs (inputs),
2134 heatTemplate.getTimeoutMinutes (),
2135 newEnvironmentString,
2136 //heatEnvironmentString,
2137 nestedTemplatesChecked,
2139 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2141 heatStack = heatU.updateStack (cloudSiteId,
2147 heatTemplate.getTimeoutMinutes (),
2148 newEnvironmentString,
2149 //heatEnvironmentString,
2150 nestedTemplatesChecked,
2152 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2155 } catch (MsoException me) {
2156 me.addContext ("UpdateVFModule");
2157 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2158 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2159 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2160 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2161 throw new VnfException (me);
2164 // Make sure DB session is closed
2168 // Reach this point if updateStack is successful.
2169 // Populate remaining rollback info and response parameters.
2170 vfRollback.setVnfId (heatStack.getCanonicalName ());
2171 vfRollback.setVnfCreated (true);
2173 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2174 rollback.value = vfRollback;
2175 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2179 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2180 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2181 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2182 if (vfModuleStackId == null)
2184 int index = vfModuleStackId.lastIndexOf('/');
2187 String vfModuleName = null;
2189 vfModuleName = vfModuleStackId.substring(0, index);
2190 } catch (Exception e) {
2191 LOGGER.debug("Exception", e);
2192 vfModuleName = null;
2194 return vfModuleName;