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.io.BufferedReader;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
30 import java.util.Arrays;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
35 import java.util.concurrent.TimeUnit;
36 import java.util.Scanner;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
40 import javax.jws.WebService;
41 import javax.xml.ws.Holder;
43 import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists;
44 import org.openecomp.mso.adapters.vnf.exceptions.VnfException;
45 import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound;
46 import org.openecomp.mso.cloud.CloudConfigFactory;
47 import org.openecomp.mso.cloud.CloudConfig;
48 import org.openecomp.mso.cloud.CloudSite;
49 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
50 import org.openecomp.mso.db.catalog.CatalogDatabase;
51 import org.openecomp.mso.db.catalog.beans.HeatEnvironment;
52 import org.openecomp.mso.db.catalog.beans.HeatFiles;
53 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
54 import org.openecomp.mso.db.catalog.beans.HeatTemplateParam;
55 import org.openecomp.mso.db.catalog.beans.VnfResource;
56 import org.openecomp.mso.db.catalog.beans.VfModule;
57 import org.openecomp.mso.db.catalog.beans.VfModuleCustomization;
58 import org.openecomp.mso.db.catalog.beans.VnfComponent;
59 import org.openecomp.mso.entity.MsoRequest;
60 import org.openecomp.mso.logger.MessageEnum;
61 import org.openecomp.mso.logger.MsoAlarmLogger;
62 import org.openecomp.mso.logger.MsoLogger;
63 import org.openecomp.mso.openstack.beans.HeatStatus;
64 import org.openecomp.mso.openstack.beans.StackInfo;
65 import org.openecomp.mso.openstack.beans.VnfStatus;
66 import org.openecomp.mso.openstack.beans.VnfRollback;
67 import org.openecomp.mso.openstack.exceptions.MsoException;
68 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
69 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
70 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
71 import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry;
72 import org.openecomp.mso.properties.MsoPropertiesFactory;
74 import org.codehaus.jackson.JsonNode;
75 import org.codehaus.jackson.JsonParseException;
76 import org.codehaus.jackson.map.ObjectMapper;
78 @WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.openecomp.mso/vnf")
79 public class MsoVnfAdapterImpl implements MsoVnfAdapter {
81 CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
82 protected CloudConfig cloudConfig = null;
84 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
86 private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
87 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
88 private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter.";
89 private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN.";
90 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
91 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
92 private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters";
93 private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq";
94 private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
97 * Health Check web method. Does nothing but return to show the adapter is deployed.
100 public void healthCheck () {
101 LOGGER.debug ("Health check call in VNF Adapter");
105 * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL.
106 * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory)
108 public MsoVnfAdapterImpl() {
113 * This constructor MUST be used if this class is called with the new operator.
114 * @param msoPropFactory
116 public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) {
117 this.msoPropertiesFactory = msoPropFactory;
118 this.cloudConfigFactory = cloudConfigFact;
122 * This is the "Create VNF" web service implementation.
123 * It will create a new VNF of the requested type in the specified cloud
124 * and tenant. The tenant must exist before this service is called.
126 * If a VNF with the same name already exists, this can be considered a
127 * success or failure, depending on the value of the 'failIfExists' parameter.
129 * All VNF types will be defined in the MSO catalog. The caller must request
130 * one of these pre-defined types or an error will be returned. Within the
131 * catalog, each VNF type references (among other things) a Heat template
132 * which is used to deploy the required VNF artifacts (VMs, networks, etc.)
135 * Depending on the Heat template, a variable set of input parameters will
136 * be defined, some of which are required. The caller is responsible to
137 * pass the necessary input data for the VNF or an error will be thrown.
139 * The method returns the vnfId (the canonical name), a Map of VNF output
140 * attributes, and a VnfRollback object. This last object can be passed
141 * as-is to the rollbackVnf operation to undo everything that was created
142 * for the VNF. This is useful if a VNF is successfully created but the
143 * orchestrator fails on a subsequent operation.
145 * @param cloudSiteId CLLI code of the cloud site in which to create the VNF
146 * @param tenantId Openstack tenant identifier
147 * @param vnfType VNF type key, should match a VNF definition in catalog DB
148 * @param vnfVersion VNF version key, should match a VNF definition in catalog DB
149 * @param vnfName Name to be assigned to the new VNF
150 * @param inputs Map of key=value inputs for VNF stack creation
151 * @param failIfExists Flag whether already existing VNF should be considered
152 * a success or failure
153 * @param msoRequest Request tracking information for logs
154 * @param vnfId Holder for output VNF Openstack ID
155 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
156 * @param rollback Holder for returning VnfRollback object
159 public void createVnf (String cloudSiteId,
165 String volumeGroupHeatStackId,
166 Map <String, String> inputs,
167 Boolean failIfExists,
169 MsoRequest msoRequest,
170 Holder <String> vnfId,
171 Holder <Map <String, String>> outputs,
172 Holder <VnfRollback> rollback) throws VnfException {
173 // Create a hook here to catch shortcut createVf requests:
174 if (requestType != null) {
175 if (requestType.startsWith("VFMOD")) {
176 LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType);
177 String newRequestType = requestType.substring(5);
178 String vfVolGroupHeatStackId = "";
179 String vfBaseHeatStackId = "";
181 if (volumeGroupHeatStackId != null) {
182 vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|"));
183 vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1);
185 } catch (Exception e) {
186 // might be ok - both are just blank
187 LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId,e);
189 this.createVfModule(cloudSiteId,
195 vfVolGroupHeatStackId,
208 // createVf will know if the requestType starts with "X" that it's the "old" way
209 StringBuilder newRequestTypeSb = new StringBuilder("X");
210 String vfVolGroupHeatStackId = "";
211 String vfBaseHeatStackId = "";
212 if (requestType != null) {
213 newRequestTypeSb.append(requestType);
215 this.createVfModule(cloudSiteId,
220 newRequestTypeSb.toString(),
221 vfVolGroupHeatStackId,
232 // End createVf shortcut
236 public void updateVnf (String cloudSiteId,
242 String volumeGroupHeatStackId,
243 Map <String, String> inputs,
244 MsoRequest msoRequest,
245 Holder <Map <String, String>> outputs,
246 Holder <VnfRollback> rollback) throws VnfException {
247 // As of 1707 - this method should no longer be called
248 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
249 MsoLogger.setServiceName ("UpdateVnf");
250 LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule");
254 * This is the "Query VNF" web service implementation.
255 * It will look up a VNF by name or ID in the specified cloud and tenant.
257 * The method returns an indicator that the VNF exists, its Openstack internal
258 * ID, its status, and the set of outputs (from when the stack was created).
260 * @param cloudSiteId CLLI code of the cloud site in which to query
261 * @param tenantId Openstack tenant identifier
262 * @param vnfName VNF Name or Openstack ID
263 * @param msoRequest Request tracking information for logs
264 * @param vnfExists Flag reporting the result of the query
265 * @param vnfId Holder for output VNF Openstack ID
266 * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc)
269 public void queryVnf (String cloudSiteId,
272 MsoRequest msoRequest,
273 Holder <Boolean> vnfExists,
274 Holder <String> vnfId,
275 Holder <VnfStatus> status,
276 Holder <Map <String, String>> outputs) throws VnfException {
277 MsoLogger.setLogContext (msoRequest);
278 MsoLogger.setServiceName ("QueryVnf");
279 LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
281 // Will capture execution time for metrics
282 long startTime = System.currentTimeMillis ();
284 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
286 StackInfo heatStack = null;
287 long subStartTime = System.currentTimeMillis ();
289 heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName);
290 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName);
291 } catch (MsoException me) {
292 me.addContext ("QueryVNF");
293 // Failed to query the Stack due to an openstack exception.
294 // Convert to a generic VnfException
295 String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
296 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName);
297 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
298 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
299 throw new VnfException (me);
302 // Populate the outputs based on the returned Stack information
304 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
306 vnfExists.value = Boolean.FALSE;
307 status.value = VnfStatus.NOTFOUND;
309 outputs.value = new HashMap <String, String> (); // Return as an empty map
311 LOGGER.debug ("VNF " + vnfName + " not found");
313 vnfExists.value = Boolean.TRUE;
314 status.value = stackStatusToVnfStatus (heatStack.getStatus ());
315 vnfId.value = heatStack.getCanonicalName ();
316 outputs.value = copyStringOutputs (heatStack.getOutputs ());
318 LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value);
320 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF");
325 * This is the "Delete VNF" web service implementation.
326 * It will delete a VNF by name or ID in the specified cloud and tenant.
328 * The method has no outputs.
330 * @param cloudSiteId CLLI code of the cloud site in which to delete
331 * @param tenantId Openstack tenant identifier
332 * @param vnfName VNF Name or Openstack ID
333 * @param msoRequest Request tracking information for logs
336 public void deleteVnf (String cloudSiteId,
339 MsoRequest msoRequest) throws VnfException {
340 MsoLogger.setLogContext (msoRequest);
341 MsoLogger.setServiceName ("DeleteVnf");
342 LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
343 // Will capture execution time for metrics
344 long startTime = System.currentTimeMillis ();
346 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
348 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
349 // The possible outcomes of deleteStack are a StackInfo object with status
350 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
352 long subStartTime = System.currentTimeMillis ();
354 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
355 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
356 } catch (MsoException me) {
357 me.addContext ("DeleteVNF");
358 // Failed to query the Stack due to an openstack exception.
359 // Convert to a generic VnfException
360 String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
361 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
362 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me);
363 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
364 throw new VnfException (me);
367 // On success, nothing is returned.
368 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF");
373 * This web service endpoint will rollback a previous Create VNF operation.
374 * A rollback object is returned to the client in a successful creation
375 * response. The client can pass that object as-is back to the rollbackVnf
376 * operation to undo the creation.
379 public void rollbackVnf (VnfRollback rollback) throws VnfException {
380 long startTime = System.currentTimeMillis ();
381 MsoLogger.setServiceName ("RollbackVnf");
382 // rollback may be null (e.g. if stack already existed when Create was called)
383 if (rollback == null) {
384 LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf");
385 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null");
389 // Get the elements of the VnfRollback object for easier access
390 String cloudSiteId = rollback.getCloudSiteId ();
391 String tenantId = rollback.getTenantId ();
392 String vnfId = rollback.getVnfId ();
394 MsoLogger.setLogContext (rollback.getMsoRequest());
396 LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId);
398 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
400 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
401 // The possible outcomes of deleteStack are a StackInfo object with status
402 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
404 long subStartTime = System.currentTimeMillis ();
406 heat.deleteStack (tenantId, cloudSiteId, vnfId, true);
407 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
408 } catch (MsoException me) {
409 // Failed to rollback the Stack due to an openstack exception.
410 // Convert to a generic VnfException
411 me.addContext ("RollbackVNF");
412 String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
413 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
414 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me);
415 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
416 throw new VnfException (me);
418 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF");
422 private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) {
423 switch (stackStatus) {
425 return VnfStatus.ACTIVE;
427 return VnfStatus.ACTIVE;
429 return VnfStatus.FAILED;
431 return VnfStatus.UNKNOWN;
435 private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) {
436 Map <String, String> stringOutputs = new HashMap <String, String> ();
437 for (String key : stackOutputs.keySet ()) {
438 if (stackOutputs.get (key) instanceof String) {
439 stringOutputs.put (key, (String) stackOutputs.get (key));
440 } else if (stackOutputs.get(key) instanceof Integer) {
442 String str = "" + stackOutputs.get(key);
443 stringOutputs.put(key, str);
444 } catch (Exception e) {
445 LOGGER.debug("Unable to add " + key + " to outputs",e);
447 } else if (stackOutputs.get(key) instanceof JsonNode) {
449 String str = this.convertNode((JsonNode) stackOutputs.get(key));
450 stringOutputs.put(key, str);
451 } catch (Exception e) {
452 LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode",e);
454 } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) {
456 String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key));
457 stringOutputs.put(key, str);
458 } catch (Exception e) {
459 LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap",e);
463 String str = stackOutputs.get(key).toString();
464 stringOutputs.put(key, str);
465 } catch (Exception e) {
466 LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(),e);
470 return stringOutputs;
473 private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) {
474 return new HashMap <String, Object> (stringInputs);
478 * a helper method to make sure that any resource_registry entry of the format
479 * "xx::xx" : yyy.yaml (or yyy.template)
480 * has the file name prepended with "file:///"
481 * Return a String of the environment body that's passed in.
482 * Have to be careful not to mess up the original formatting.
484 private String parseEnvironment (String environment) {
485 StringBuilder sb = new StringBuilder ();
486 try (Scanner scanner = new Scanner (environment)) {
487 scanner.useDelimiter ("\n");
489 Pattern resource = Pattern.compile ("\\s*\"\\w+::\\S+\"\\s*:");
490 LOGGER.debug ("regex pattern for finding a resource_registry: \\s*\"\\w+::\\S+\"\\s*:");
491 while (scanner.hasNextLine ()) {
492 line = scanner.nextLine ();
493 if (line.toLowerCase ().contains ("resource_registry")) {
494 sb.append (line + "\n");
495 boolean done = false;
496 // basically keep scanning until EOF or parameters: section
497 while (scanner.hasNextLine () && !done) {
498 line = scanner.nextLine ();
499 if ("parameters:".equalsIgnoreCase (line.trim ())) {
500 sb.append (line + "\n");
504 Matcher m = resource.matcher (line);
506 sb.append (m.group ());
507 String secondPart = line.substring (m.end ()).trim ();
508 String output = secondPart;
509 if (secondPart.endsWith (".yaml")
510 || secondPart.endsWith (".template") && !secondPart.startsWith ("file:///")) {
511 output = "file:///" + secondPart;
512 LOGGER.debug ("changed " + secondPart + " to " + output);
513 } // don't do anything if it's not .yaml or .template
514 sb.append (" " + output + "\n");
516 sb.append (line + "\n");
520 sb.append (line + "\n");
525 } catch (Exception e) {
526 LOGGER.debug ("Error trying to scan " + environment, e);
529 return sb.toString ();
533 * helper class to add file:/// to the Provider_Resource_File entry in HEAT_NESTED_TEMPLATE
534 * and the File_Name entry in HEAT_FILES if the file:/// part is missing.
536 private String enforceFilePrefix (String string) {
537 if (string.trim ().startsWith ("file:///")) {
541 if (string.trim ().endsWith (".yaml") || string.trim ().endsWith (".template")) {
542 // only .yaml or .template are valid anyway - otherwise don't bother
543 return "file:///" + string.trim ();
545 LOGGER.debug (string + " is NOT a .yaml or .template file");
550 private boolean callHeatbridge(String heatStackId) {
551 String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge";
552 String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = "";
553 long waitTimeMs = 10000l;
555 String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId};
556 String[] envp = null;
557 File dir = new File(executionDir);
558 LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray));
559 Runtime r = Runtime.getRuntime();
560 Process p = r.exec(cmdarray, envp, dir);
562 BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
563 String linein = stdout.readLine();
564 while (linein!=null) {
565 System.out.println(linein);
566 linein = stdout.readLine();
569 boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS);
571 LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue());
572 return (wait && p.exitValue()==0);
573 } catch (IOException e) {
574 LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e);
576 } catch (InterruptedException e) {
577 LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e);
579 } catch (RuntimeException e) {
580 LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e);
585 private void sendMapToDebug(Map<String, Object> inputs, String optionalName) {
587 StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName);
588 if (inputs == null) {
591 else if (inputs.size() < 1) {
592 sb.append("\tEMPTY");
594 for (String str : inputs.keySet()) {
597 outputString = inputs.get(str).toString();
598 } catch (Exception e) {
599 LOGGER.debug("Exception :",e);
600 outputString = "Unable to call toString() on the value for " + str;
602 sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'");
605 LOGGER.debug(sb.toString());
609 private void sendMapToDebug(Map<String, String> inputs) {
611 StringBuilder sb = new StringBuilder("inputs:");
612 if (inputs == null) {
615 else if (inputs.size() < 1) {
616 sb.append("\tEMPTY");
618 for (String str : inputs.keySet()) {
619 sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str));
622 LOGGER.debug(sb.toString());
626 private String convertNode(final JsonNode node) {
628 final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
629 final String json = JSON_MAPPER.writeValueAsString(obj);
631 } catch (JsonParseException jpe) {
632 LOGGER.debug("Error converting json to string " + jpe.getMessage(),jpe);
633 } catch (Exception e) {
634 LOGGER.debug("Error converting json to string " + e.getMessage(),e);
636 return "[Error converting json to string]";
639 private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) {
640 if (objectMap == null) {
643 Map<String, String> stringMap = new HashMap<String, String>();
644 for (String key : objectMap.keySet()) {
645 if (!stringMap.containsKey(key)) {
646 Object obj = objectMap.get(key);
647 if (obj instanceof String) {
648 stringMap.put(key, (String) objectMap.get(key));
649 } else if (obj instanceof JsonNode ){
650 // This is a bit of mess - but I think it's the least impacting
651 // let's convert it BACK to a string - then it will get converted back later
653 String str = this.convertNode((JsonNode) obj);
654 stringMap.put(key, str);
655 } catch (Exception e) {
656 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e);
657 //okay in this instance - only string values (fqdn) are expected to be needed
659 } else if (obj instanceof java.util.LinkedHashMap) {
660 LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode");
662 String str = JSON_MAPPER.writeValueAsString(obj);
663 stringMap.put(key, str);
664 } catch (Exception e) {
665 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e);
667 } else if (obj instanceof Integer) {
669 String str = "" + obj;
670 stringMap.put(key, str);
671 } catch (Exception e) {
672 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e);
676 String str = obj.toString();
677 stringMap.put(key, str);
678 } catch (Exception e) {
679 LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e);
689 public void createVfModule(String cloudSiteId,
695 String volumeGroupHeatStackId,
696 String baseVfHeatStackId,
697 String modelCustomizationUuid,
698 Map <String, String> inputs,
699 Boolean failIfExists,
701 MsoRequest msoRequest,
702 Holder <String> vnfId,
703 Holder <Map <String, String>> outputs,
704 Holder <VnfRollback> rollback) throws VnfException {
705 String vfModuleName = vnfName;
706 String vfModuleType = vnfType;
707 String vfVersion = vnfVersion;
708 String mcu = modelCustomizationUuid;
709 boolean useMCUuid = false;
710 if (mcu != null && !mcu.isEmpty()) {
711 if (mcu.equalsIgnoreCase("null")) {
712 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
716 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
720 MsoLogger.setLogContext (msoRequest);
721 MsoLogger.setServiceName ("CreateVfModule");
722 String requestTypeString = "";
723 if (requestType != null && !requestType.equals("")) {
724 requestTypeString = requestType;
726 String nestedStackId = null;
727 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
728 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
729 nestedStackId = volumeGroupHeatStackId;
732 String nestedBaseStackId = null;
733 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
734 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
735 nestedBaseStackId = baseVfHeatStackId;
739 if (inputs == null) {
740 // Create an empty set of inputs
741 inputs = new HashMap<String,String>();
742 LOGGER.debug("inputs == null - setting to empty");
744 this.sendMapToDebug(inputs);
746 //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF
747 boolean oldWay = false;
748 if (requestTypeString.startsWith("X")) {
750 LOGGER.debug("orchestrating a VNF - *NOT* a module!");
751 requestTypeString = requestTypeString.substring(1);
754 // 1607 - let's parse out the request type we're being sent
755 boolean isBaseRequest = false;
756 boolean isVolumeRequest = false;
757 if (requestTypeString.startsWith("VOLUME")) {
758 isVolumeRequest = true;
761 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
762 // Will capture execution time for metrics
763 long startTime = System.currentTimeMillis ();
765 // Build a default rollback object (no actions performed)
766 VnfRollback vfRollback = new VnfRollback();
767 vfRollback.setCloudSiteId(cloudSiteId);
768 vfRollback.setTenantId(tenantId);
769 vfRollback.setMsoRequest(msoRequest);
770 vfRollback.setRequestType(requestTypeString);
771 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
772 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
773 vfRollback.setIsBase(isBaseRequest);
774 vfRollback.setModelCustomizationUuid(mcu);
776 // Put data into A&AI through Heatstack
777 boolean heatStackCallSuccess = callHeatbridge(baseVfHeatStackId);
779 // First, look up to see if the VF already exists.
780 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
782 StackInfo heatStack = null;
783 long subStartTime1 = System.currentTimeMillis ();
785 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
786 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
787 } catch (MsoException me) {
788 String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
789 LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
790 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me);
791 // Failed to query the Stack due to an openstack exception.
792 // Convert to a generic VnfException
793 me.addContext ("CreateVFModule");
794 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
795 throw new VnfException (me);
797 // New with 1607 - more precise handling/messaging if the stack already exists
798 if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
799 // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED
800 HeatStatus status = heatStack.getStatus();
801 if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) {
802 // fail - it's in progress - return meaningful error
803 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.";
804 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
805 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
806 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
808 if (status == HeatStatus.FAILED) {
809 // fail - it exists and is in a FAILED state
810 String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
811 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state");
812 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
813 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
815 if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) {
816 // fail - it exists and is in a FAILED state
817 String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention.";
818 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");
819 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
820 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
822 if (status == HeatStatus.CREATED) {
824 if (failIfExists != null && failIfExists) {
825 String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId;
826 LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists");
827 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
828 throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ());
830 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
831 // Populate the outputs from the existing stack.
832 vnfId.value = heatStack.getCanonicalName ();
833 outputs.value = copyStringOutputs (heatStack.getOutputs ());
834 rollback.value = vfRollback; // Default rollback - no updates performed
837 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
842 // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf
843 StackInfo nestedHeatStack = null;
844 long subStartTime2 = System.currentTimeMillis ();
845 Map<String, Object> nestedVolumeOutputs = null;
846 if (nestedStackId != null) {
848 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
849 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
850 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
851 } catch (MsoException me) {
852 // Failed to query the Stack due to an openstack exception.
853 // Convert to a generic VnfException
854 me.addContext ("CreateVFModule");
855 String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
856 LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
857 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me);
858 LOGGER.debug("ERROR trying to query nested stack= " + error);
859 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
860 throw new VnfException (me);
862 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
863 String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
864 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST");
865 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
867 throw new VnfException (error, MsoExceptionCategory.USERDATA);
869 LOGGER.debug("Found nested volume heat stack - copying values to inputs *later*");
870 //this.sendMapToDebug(inputs);
871 nestedVolumeOutputs = nestedHeatStack.getOutputs();
872 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
874 //heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
875 //this.sendMapToDebug(inputs);
879 // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests
880 StackInfo nestedBaseHeatStack = null;
881 long subStartTime3 = System.currentTimeMillis ();
882 Map<String, Object> baseStackOutputs = null;
883 if (nestedBaseStackId != null) {
885 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
886 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
887 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName);
888 } catch (MsoException me) {
889 // Failed to query the Stack due to an openstack exception.
890 // Convert to a generic VnfException
891 me.addContext ("CreateVFModule");
892 String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
893 LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName);
894 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me);
895 LOGGER.debug("ERROR trying to query nested base stack= " + error);
896 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
897 throw new VnfException (me);
899 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
900 String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
901 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");
902 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
904 throw new VnfException (error, MsoExceptionCategory.USERDATA);
906 LOGGER.debug("Found nested base heat stack - these values will be copied to inputs *later*");
907 //this.sendMapToDebug(inputs);
908 baseStackOutputs = nestedBaseHeatStack.getOutputs();
909 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
911 //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
912 //this.sendMapToDebug(inputs);
916 // Ready to deploy the new VNF
918 CatalogDatabase db = CatalogDatabase.getInstance();
923 VnfResource vnfResource = null;
924 VfModuleCustomization vfmc = null;
925 LOGGER.debug("version: " + vfVersion);
927 // 1707 - db refactoring
928 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
929 vf = vfmc != null ? vfmc.getVfModule() : null;
930 // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same.
931 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
933 LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu);
934 String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu;
935 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
936 "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu);
937 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
938 throw new VnfException(error, MsoExceptionCategory.USERDATA);
940 LOGGER.debug("Found vfModuleCust entry " + vfmc.toString());
943 isBaseRequest = true;
944 LOGGER.debug("This is a BASE VF request!");
946 LOGGER.debug("This is *not* a BASE VF request!");
947 if (!isVolumeRequest && nestedBaseStackId == null) {
948 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
954 // Need to handle old and new schema methods - for a time. Try the new way first.
955 if (vfVersion != null && !vfVersion.isEmpty()) {
956 vf = db.getVfModuleType(vfModuleType, vfVersion);
958 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME");
959 vf = db.getVfModuleModelName(vfModuleType, vfVersion);
961 LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR");
965 vf = db.getVfModuleType(vfModuleType);
967 LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME");
968 vf = db.getVfModuleModelName(vfModuleType);
970 LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR");
975 String error = "Create VF Module: Unable to determine specific VF Module Type: "
977 if (vfVersion != null && !vfVersion.isEmpty()) {
978 error += " with version = " + vfVersion;
980 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
981 "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type");
982 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
983 throw new VnfException(error, MsoExceptionCategory.USERDATA);
985 LOGGER.debug("Got VF module definition from Catalog: "
989 isBaseRequest = true;
990 LOGGER.debug("This is a BASE VF request!");
992 LOGGER.debug("This is *not* a BASE VF request!");
993 if (!isVolumeRequest && nestedBaseStackId == null) {
994 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
998 else { // This is to support gamma only - get info from vnf_resource table
999 if (vfVersion != null && !vfVersion.isEmpty()) {
1000 vnfResource = db.getVnfResource(vnfType, vnfVersion);
1002 vnfResource = db.getVnfResource(vnfType);
1004 if (vnfResource == null) {
1005 String error = "Create VNF: Unknown VNF Type: " + vnfType;
1006 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type",
1007 vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type");
1008 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1009 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1011 LOGGER.debug("Got VNF module definition from Catalog: "
1012 + vnfResource.toString());
1014 // By here - we have either a vf or vnfResource
1016 //1607 - Add version check
1017 // First - see if it's in the VnfResource record
1018 // if we have a vf Module - then we have to query to get the VnfResource record.
1020 if (vf.getVnfResourceModelUUId() != null) {
1021 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1022 //vnfResource = db.getVnfResourceById(vnfResourceId);
1023 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1024 if (vnfResource == null) {
1025 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1029 String minVersionVnf = null;
1030 String maxVersionVnf = null;
1031 if (vnfResource != null) {
1033 minVersionVnf = vnfResource.getAicVersionMin();
1034 maxVersionVnf = vnfResource.getAicVersionMax();
1035 } catch (Exception e) {
1036 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1037 minVersionVnf = null;
1038 maxVersionVnf = null;
1040 if (minVersionVnf != null && minVersionVnf.equals("")) {
1041 minVersionVnf = null;
1043 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1044 maxVersionVnf = null;
1047 if (minVersionVnf != null && maxVersionVnf != null) {
1048 MavenLikeVersioning aicV = new MavenLikeVersioning();
1049 CloudSite cloudSite = null;
1050 String aicVersion = "";
1051 if (this.cloudConfig == null) {
1052 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1055 if (this.cloudConfig != null) {
1056 cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1057 if (cloudSite != null) {
1058 aicV.setVersion(cloudSite.getAic_version());
1059 // Add code to handle unexpected values in here
1060 boolean moreThanMin = true;
1061 boolean equalToMin = true;
1062 boolean moreThanMax = true;
1063 boolean equalToMax = true;
1064 boolean doNotTest = false;
1066 moreThanMin = aicV.isMoreRecentThan(minVersionVnf);
1067 equalToMin = aicV.isTheSameVersion(minVersionVnf);
1068 moreThanMax = aicV.isMoreRecentThan(maxVersionVnf);
1069 equalToMax = aicV.isTheSameVersion(maxVersionVnf);
1070 } catch (Exception e) {
1071 LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e);
1075 if ((moreThanMin || equalToMin) // aic >= min
1076 && (equalToMax || !(moreThanMax))) { //aic <= max
1077 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUuid() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1080 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();
1081 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1082 LOGGER.debug(error);
1083 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1086 LOGGER.debug("bypassing testing AIC version...");
1088 } // let this error out downstream to avoid introducing uncertainty at this stage
1090 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1093 LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked.");
1095 // End Version check 1607
1097 // with VF_MODULE - we have both the non-vol and vol template/envs in that object
1098 // with VNF_RESOURCE - we use the old methods.
1099 //Integer heatTemplateId = null;
1100 //Integer heatEnvtId = null;
1102 String heatTemplateArtifactUuid = null;
1103 String heatEnvironmentArtifactUuid = null;
1106 if (isVolumeRequest) {
1107 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1108 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1110 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1111 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1114 if (isVolumeRequest) {
1115 LOGGER.debug("DANGER WILL ROBINSON! This should never apply - a VNF Request (gamma only now) *and* a volume request?");
1117 VnfComponent vnfComponent = null;
1118 vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME");
1119 if (vnfComponent == null) {
1120 String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME";
1121 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry");
1122 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1123 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1125 heatTemplateId = vnfComponent.getHeatTemplateId();
1126 heatEnvtId = vnfComponent.getHeatEnvironmentId();
1130 heatTemplateArtifactUuid = vnfResource.getTemplateId();
1131 heatEnvironmentArtifactUuid = null;
1134 // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null)
1135 HeatTemplate heatTemplate = null;
1136 if (heatTemplateArtifactUuid == null || heatTemplateArtifactUuid.equals("")) {
1137 String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString;
1138 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database");
1139 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1140 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1141 MsoAlarmLogger.CRITICAL, error);
1142 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1144 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1146 if (heatTemplate == null) {
1147 String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid;
1148 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1150 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateArtifactUuid);
1151 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1152 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1153 MsoAlarmLogger.CRITICAL, error);
1154 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1156 LOGGER.debug("Got HEAT Template from DB");
1158 HeatEnvironment heatEnvironment = null;
1159 String heatEnvironmentString = null;
1161 if (heatEnvironmentArtifactUuid != null && !heatEnvironmentArtifactUuid.equals("")) {
1162 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1163 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1164 if (heatEnvironment == null) {
1165 String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType
1166 + ", Environment ID="
1167 + heatEnvironmentArtifactUuid;
1168 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "getHeatEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment");
1169 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1170 // Alarm on this error, configuration must be fixed
1171 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1173 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1175 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1176 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1177 LOGGER.debug ("after parsing: " + heatEnvironmentString);
1180 LOGGER.debug ("no environment parameter found for this Type " + vfModuleType);
1183 // 1510 - Add the files: for nested templates *if* there are any
1184 LOGGER.debug ("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId="
1185 + heatTemplate.getArtifactUuid());
1186 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid());
1187 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1188 if (nestedTemplates != null) {
1189 // for debugging print them out
1190 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1191 for (String providerResourceFile : nestedTemplates.keySet ()) {
1192 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1193 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1194 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1195 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1198 LOGGER.debug ("No nested templates found - nothing to do here");
1199 nestedTemplatesChecked = null; // just to make sure
1202 // 1510 - Also add the files: for any get_files associated with this vnf_resource_id
1203 // *if* there are any
1204 Map<String, HeatFiles> heatFiles = null;
1205 Map<String, Object> heatFilesObjects = new HashMap<String, Object>();
1207 // Add ability to turn on adding get_files with volume requests (by property).
1208 boolean addGetFilesOnVolumeReq = false;
1210 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1211 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1212 addGetFilesOnVolumeReq = true;
1213 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1215 } catch (Exception e) {
1216 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1219 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1221 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, this should not happen - old way is gamma only - no heat files!");
1222 //heatFiles = db.getHeatFiles(vnfResource.getId());
1224 // 1607 - now use VF_MODULE_TO_HEAT_FILES table
1225 LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1226 + vf.getModelUUID());
1228 .getHeatFilesForVfModule(vf.getModelUUID());
1230 if (heatFiles != null) {
1231 // add these to stack - to be done in createStack
1232 // here, we will map them to Map<String, Object> from
1233 // Map<String, HeatFiles>
1234 // this will match the nested templates format
1235 LOGGER.debug("Contents of heatFiles - to be added to files: on stack:");
1237 for (String heatFileName : heatFiles.keySet()) {
1238 if (heatFileName.startsWith("_ERROR|")) {
1239 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1240 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1241 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1242 LOGGER.debug(error);
1243 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found");
1244 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1245 // Alarm on this error, configuration must be fixed
1246 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1247 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1249 String heatFileBody = heatFiles.get(heatFileName)
1251 String heatFileNameChecked = heatFileName;
1252 LOGGER.debug(heatFileNameChecked + " -> "
1254 heatFilesObjects.put(heatFileNameChecked, heatFileBody);
1257 LOGGER.debug("No heat files found -nothing to do here");
1258 heatFilesObjects = null;
1261 LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES");
1264 // Check that required parameters have been supplied
1265 String missingParams = null;
1266 List <String> paramList = new ArrayList <String> ();
1268 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1269 // supplied an alias. Only check if we don't find it initially.
1270 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1271 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1273 boolean haveEnvironmentParameters = false;
1274 boolean checkRequiredParameters = true;
1276 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1277 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1278 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1279 checkRequiredParameters = false;
1280 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1281 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1283 } catch (Exception e) {
1284 // No problem - default is true
1285 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1287 // 1604 - Add enhanced environment & parameter checking
1288 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1289 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1290 // Note this also removes any comments
1291 MsoHeatEnvironmentEntry mhee = null;
1292 if (heatEnvironmentString != null && heatEnvironmentString.contains ("parameters:")) {
1293 //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases");
1294 LOGGER.debug("Enhanced environment checking enabled - 1604");
1295 haveEnvironmentParameters = true;
1296 StringBuilder sb = new StringBuilder(heatEnvironmentString);
1297 //LOGGER.debug("About to create MHEE with " + sb);
1298 mhee = new MsoHeatEnvironmentEntry(sb);
1299 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
1300 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
1301 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
1303 if (!mhee.isValid()) {
1304 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
1306 sb2.append("\nEnvironment:");
1307 sb2.append(mhee.toFullString());
1309 LOGGER.debug(sb2.toString());
1311 LOGGER.debug("NO ENVIRONMENT for this entry");
1313 // New with 1707 - all variables converted to their native object types
1314 HashMap<String, Object> goldenInputs = null;
1316 LOGGER.debug("Now handle the inputs....first convert");
1317 ArrayList<String> parameterNames = new ArrayList<String>();
1318 HashMap<String, String> aliasToParam = new HashMap<String, String>();
1319 StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n");
1322 for (HeatTemplateParam htp : heatTemplate.getParameters()) {
1323 sb.append("param[" + cntr++ + "]=" + htp.getParamName());
1324 parameterNames.add(htp.getParamName());
1325 if (htp.getParamAlias() != null && !htp.getParamAlias().equals("")) {
1326 aliasToParam.put(htp.getParamAlias(), htp.getParamName());
1327 sb.append(" ** (alias=" + htp.getParamAlias() + ")");
1331 LOGGER.debug(sb.toString());
1332 } catch (Exception e) {
1333 LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e);
1335 // Step 1 - convert what we got as inputs (Map<String, String>) to a
1336 // Map<String, Object> - where the object matches the param type identified in the template
1337 // This will also not copy over params that aren't identified in the template
1338 goldenInputs = heat.convertInputMap(inputs, heatTemplate);
1339 // Step 2 - now simply add the outputs as we received them - no need to convert to string
1340 LOGGER.debug("Now add in the base stack outputs if applicable");
1341 heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam);
1342 // Step 3 - add the volume inputs if any
1343 LOGGER.debug("Now add in the volume stack outputs if applicable");
1344 heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam);
1345 this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack");
1347 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
1348 LOGGER.debug ("Parameter:'" + parm.getParamName ()
1350 + parm.isRequired ()
1352 + parm.getParamAlias ());
1354 if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) {
1355 // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object>
1356 LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment");
1357 if (mhee != null && mhee.containsParameter(parm.getParamName())) {
1358 LOGGER.debug ("Required parameter " + parm.getParamName ()
1359 + " appears to be in environment - do not count as missing");
1361 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
1362 if (missingParams == null) {
1363 missingParams = parm.getParamName ();
1365 missingParams += "," + parm.getParamName ();
1369 paramList.add (parm.getParamName ());
1371 if (missingParams != null) {
1372 if (checkRequiredParameters) {
1373 // Problem - missing one or more required parameters
1374 String error = "Create VFModule: Missing Required inputs: " + missingParams;
1375 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs");
1376 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1377 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1379 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
1382 LOGGER.debug ("No missing parameters found - ok to proceed");
1384 // We can now remove the recreating of the ENV with only legit params - that check is done for us,
1385 // and it causes problems with json that has arrays
1386 String newEnvironmentString = null;
1388 newEnvironmentString = mhee.getRawEntry().toString();
1391 // "Fix" the template if it has CR/LF (getting this from Oracle)
1392 String template = heatTemplate.getHeatTemplate ();
1393 template = template.replaceAll ("\r\n", "\n");
1395 // Have the tenant. Now deploy the stack itself
1396 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
1397 // because we already checked for those.
1398 long createStackStarttime = System.currentTimeMillis ();
1400 // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true,
1401 // heatTemplate.getTimeoutMinutes());
1402 if (backout == null) {
1406 LOGGER.debug("heat is not null!!");
1408 heatStack = heat.createStack (cloudSiteId,
1414 heatTemplate.getTimeoutMinutes (),
1415 newEnvironmentString,
1416 nestedTemplatesChecked,
1418 backout.booleanValue());
1419 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName);
1420 } catch (MsoException me) {
1421 me.addContext ("CreateVFModule");
1422 String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1423 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1424 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me);
1425 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1426 throw new VnfException (me);
1427 } catch (NullPointerException npe) {
1428 String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe;
1429 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName);
1430 LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe);
1431 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1432 LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack");
1433 //npe.addContext ("CreateVNF");
1434 throw new VnfException ("NullPointerException during heat.createStack");
1435 } catch (Exception e) {
1436 LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName);
1437 LOGGER.debug("unhandled exception at heat.createStack",e);
1438 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack");
1439 throw new VnfException("Exception during heat.createStack! " + e.getMessage());
1441 } catch (Exception e) {
1442 LOGGER.debug("unhandled exception in create VF",e);
1443 throw new VnfException("Exception during create VF " + e.getMessage());
1446 // Make sure DB session is closed
1450 // Reach this point if createStack is successful.
1451 // Populate remaining rollback info and response parameters.
1452 vfRollback.setVnfId (heatStack.getCanonicalName ());
1453 vfRollback.setVnfCreated (true);
1455 vnfId.value = heatStack.getCanonicalName ();
1456 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1457 rollback.value = vfRollback;
1459 LOGGER.debug ("VF Module " + vfModuleName + " successfully created");
1460 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module");
1465 public void deleteVfModule (String cloudSiteId,
1468 MsoRequest msoRequest,
1469 Holder <Map <String, String>> outputs) throws VnfException {
1470 MsoLogger.setLogContext (msoRequest);
1471 MsoLogger.setServiceName ("DeleteVf");
1472 LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId);
1473 // Will capture execution time for metrics
1474 long startTime = System.currentTimeMillis ();
1476 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1478 // 1702 capture the output parameters on a delete
1479 // so we'll need to query first
1480 Map<String, Object> stackOutputs = null;
1482 stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName);
1483 } catch (MsoException me) {
1484 // Failed to query the Stack due to an openstack exception.
1485 // Convert to a generic VnfException
1486 me.addContext ("DeleteVFModule");
1487 String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1488 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1489 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1490 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1491 throw new VnfException (me);
1493 // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types
1494 outputs.value = this.convertMapStringObjectToStringString(stackOutputs);
1496 // Use the MsoHeatUtils to delete the stack. Set the polling flag to true.
1497 // The possible outcomes of deleteStack are a StackInfo object with status
1498 // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException
1500 long subStartTime = System.currentTimeMillis ();
1502 heat.deleteStack (tenantId, cloudSiteId, vnfName, true);
1503 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName);
1504 } catch (MsoException me) {
1505 me.addContext ("DeleteVNF");
1506 // Failed to query the Stack due to an openstack exception.
1507 // Convert to a generic VnfException
1508 String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1509 LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName);
1510 LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me);
1511 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1512 throw new VnfException (me);
1515 // On success, nothing is returned.
1516 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF");
1521 public void updateVfModule (String cloudSiteId,
1527 String volumeGroupHeatStackId,
1528 String baseVfHeatStackId,
1529 String vfModuleStackId,
1530 String modelCustomizationUuid,
1531 Map <String, String> inputs,
1532 MsoRequest msoRequest,
1533 Holder <Map <String, String>> outputs,
1534 Holder <VnfRollback> rollback) throws VnfException {
1535 String vfModuleName = vnfName;
1536 String vfModuleType = vnfType;
1537 String vfVersion = vnfVersion;
1538 String methodName = "updateVfModule";
1539 MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ());
1540 String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName;
1541 MsoLogger.setServiceName (serviceName);
1543 StringBuilder sbInit = new StringBuilder();
1544 sbInit.append("updateVfModule: \n");
1545 sbInit.append("cloudSiteId=" + cloudSiteId + "\n");
1546 sbInit.append("tenantId=" + tenantId + "\n");
1547 sbInit.append("vnfType=" + vnfType + "\n");
1548 sbInit.append("vnfVersion=" + vnfVersion + "\n");
1549 sbInit.append("vnfName=" + vnfName + "\n");
1550 sbInit.append("requestType=" + requestType + "\n");
1551 sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n");
1552 sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n");
1553 sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n");
1554 sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n");
1555 LOGGER.debug(sbInit.toString());
1557 String mcu = modelCustomizationUuid;
1558 boolean useMCUuid = false;
1559 if (mcu != null && !mcu.isEmpty()) {
1560 if (mcu.equalsIgnoreCase("null")) {
1561 LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid);
1565 LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu);
1570 String requestTypeString = "";
1571 if (requestType != null && !requestType.equals("")) {
1572 requestTypeString = requestType;
1574 String nestedStackId = null;
1575 if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) {
1576 if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) {
1577 nestedStackId = volumeGroupHeatStackId;
1580 String nestedBaseStackId = null;
1581 if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) {
1582 if (!baseVfHeatStackId.equalsIgnoreCase("null")) {
1583 nestedBaseStackId = baseVfHeatStackId;
1587 if (inputs == null) {
1588 // Create an empty set of inputs
1589 inputs = new HashMap<String,String>();
1590 LOGGER.debug("inputs == null - setting to empty");
1592 this.sendMapToDebug(inputs);
1594 boolean isBaseRequest = false;
1595 boolean isVolumeRequest = false;
1596 if (requestTypeString.startsWith("VOLUME")) {
1597 isVolumeRequest = true;
1599 if (vfModuleName == null || vfModuleName.trim().equals("")) {
1600 if (vfModuleStackId != null) {
1601 vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId);
1605 LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId);
1606 LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId);
1608 // Will capture execution time for metrics
1609 long startTime = System.currentTimeMillis ();
1611 // Build a default rollback object (no actions performed)
1612 VnfRollback vfRollback = new VnfRollback ();
1613 vfRollback.setCloudSiteId (cloudSiteId);
1614 vfRollback.setTenantId (tenantId);
1615 vfRollback.setMsoRequest (msoRequest);
1616 vfRollback.setRequestType(requestTypeString);
1617 vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId);
1618 vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId);
1619 vfRollback.setIsBase(isBaseRequest);
1620 vfRollback.setVfModuleStackId(vfModuleStackId);
1621 vfRollback.setModelCustomizationUuid(mcu);
1623 // First, look up to see if the VNF already exists.
1624 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1625 MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
1627 StackInfo heatStack = null;
1628 long queryStackStarttime = System.currentTimeMillis ();
1629 LOGGER.debug("UpdateVfModule - querying for " + vfModuleName);
1631 heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName);
1632 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1633 } catch (MsoException me) {
1634 // Failed to query the Stack due to an openstack exception.
1635 // Convert to a generic VnfException
1636 me.addContext ("UpdateVFModule");
1637 String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1638 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1639 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
1640 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1641 throw new VnfException (me);
1644 //TODO - do we need to check for the other status possibilities?
1645 if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) {
1647 String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId;
1648 LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1649 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1650 throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName);
1652 LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ());
1653 // Populate the outputs from the existing stack.
1654 outputs.value = copyStringOutputs (heatStack.getOutputs ());
1655 rollback.value = vfRollback; // Default rollback - no updates performed
1658 // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId):
1659 StackInfo nestedHeatStack = null;
1660 long queryStackStarttime2 = System.currentTimeMillis ();
1661 Map<String, Object> nestedVolumeOutputs = null;
1662 if (nestedStackId != null) {
1664 LOGGER.debug("Querying for nestedStackId = " + nestedStackId);
1665 nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId);
1666 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1667 } catch (MsoException me) {
1668 // Failed to query the Stack due to an openstack exception.
1669 // Convert to a generic VnfException
1670 me.addContext ("UpdateVFModule");
1671 String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1672 LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1673 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1674 LOGGER.debug("ERROR trying to query nested stack= " + error);
1675 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1676 throw new VnfException (me);
1678 if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1679 MsoLogger.setServiceName (serviceName);
1680 String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1681 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1682 LOGGER.debug(error);
1683 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1684 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1686 LOGGER.debug("Found nested heat stack - copying values to inputs *later*");
1687 nestedVolumeOutputs = nestedHeatStack.getOutputs();
1688 //this.sendMapToDebug(inputs);
1689 this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs");
1691 heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false);
1692 //this.sendMapToDebug(inputs);
1695 // handle a nestedBaseStackId if sent - this is the stack ID of the base.
1696 StackInfo nestedBaseHeatStack = null;
1697 Map<String, Object> baseStackOutputs = null;
1698 if (nestedBaseStackId != null) {
1699 long queryStackStarttime3 = System.currentTimeMillis ();
1701 LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId);
1702 nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId);
1703 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null);
1704 } catch (MsoException me) {
1705 // Failed to query the Stack due to an openstack exception.
1706 // Convert to a generic VnfException
1707 me.addContext ("UpdateVfModule");
1708 String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ;
1709 LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
1710 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
1711 LOGGER.debug("ERROR trying to query nested base stack= " + error);
1712 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1713 throw new VnfException (me);
1715 if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) {
1716 MsoLogger.setServiceName (serviceName);
1717 String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ;
1718 LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error);
1719 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1720 LOGGER.debug(error);
1721 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1723 LOGGER.debug("Found nested base heat stack - copying values to inputs *later*");
1724 baseStackOutputs = nestedBaseHeatStack.getOutputs();
1725 //this.sendMapToDebug(inputs);
1726 this.sendMapToDebug(baseStackOutputs, "baseStackOutputs");
1728 heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false);
1729 //this.sendMapToDebug(inputs);
1733 // Ready to deploy the new VNF
1735 // Get a handle to the Catalog Database
1736 CatalogDatabase db = CatalogDatabase.getInstance();
1738 // Make sure DB session is closed
1740 // Retrieve the VF definition
1741 VnfResource vnfResource = null;
1743 VfModuleCustomization vfmc = null;
1745 //vf = db.getVfModuleByModelCustomizationUuid(mcu);
1746 vfmc = db.getVfModuleCustomizationByModelCustomizationId(mcu);
1747 vf = vfmc != null ? vfmc.getVfModule() : null;
1749 LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu);
1752 LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!");
1755 String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu;
1756 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1757 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1758 throw new VnfException (error, MsoExceptionCategory.USERDATA);
1760 LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ());
1762 isBaseRequest = true;
1763 LOGGER.debug("This a BASE update request");
1765 LOGGER.debug("This is *not* a BASE VF update request");
1766 if (!isVolumeRequest && nestedBaseStackId == null) {
1767 LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request");
1771 //1607 - Add version check
1772 // First - see if it's in the VnfResource record
1773 // if we have a vf Module - then we have to query to get the VnfResource record.
1774 if (vf.getVnfResourceModelUUId() != null) {
1775 String vnfResourceModelUuid = vf.getVnfResourceModelUUId();
1776 //vnfResource = db.getVnfResourceById(vnfResourceId);
1777 vnfResource = db.getVnfResourceByModelUuid(vnfResourceModelUuid);
1778 if (vnfResource == null) {
1779 LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " will not error for now...");
1782 String minVersionVnf = null;
1783 String maxVersionVnf = null;
1784 if (vnfResource != null) {
1786 minVersionVnf = vnfResource.getAicVersionMin();
1787 maxVersionVnf = vnfResource.getAicVersionMax();
1788 } catch (Exception e) {
1789 LOGGER.debug("Unable to pull min/max version for this VNF Resource entry",e);
1790 minVersionVnf = null;
1791 maxVersionVnf = null;
1793 if (minVersionVnf != null && minVersionVnf.equals("")) {
1794 minVersionVnf = null;
1796 if (maxVersionVnf != null && maxVersionVnf.equals("")) {
1797 maxVersionVnf = null;
1800 if (minVersionVnf != null && maxVersionVnf != null) {
1801 MavenLikeVersioning aicV = new MavenLikeVersioning();
1802 CloudSite cloudSite = null;
1803 //String aicVersion = "";
1804 if (this.cloudConfig == null) {
1805 this.cloudConfig = this.cloudConfigFactory.getCloudConfig();
1808 if (this.cloudConfig != null) {
1809 cloudSite = this.cloudConfig.getCloudSite(cloudSiteId);
1810 if (cloudSite != null) {
1811 aicV.setVersion(cloudSite.getAic_version());
1812 if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min
1813 && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV.isMoreRecentThan(maxVersionVnf)))) { //aic <= max
1814 LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version());
1817 String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version();
1818 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion");
1819 LOGGER.debug(error);
1820 throw new VnfException(error, MsoExceptionCategory.USERDATA);
1822 } // let this error out downstream to avoid introducing uncertainty at this stage
1824 LOGGER.debug("cloudConfig is NULL - cannot check cloud site version");
1828 LOGGER.debug("AIC Version not set in VNF_Resource - do not error for now - not checked.");
1830 // End Version check 1607
1832 String heatTemplateArtifactUuid = null;
1833 String heatEnvironmentArtifactUuid = null;
1835 HeatTemplate heatTemplate = null;
1836 if (isVolumeRequest) {
1837 heatTemplateArtifactUuid = vf.getVolHeatTemplateArtifactUUId();
1838 heatEnvironmentArtifactUuid = vfmc.getVolEnvironmentArtifactUuid();
1840 heatTemplateArtifactUuid = vf.getHeatTemplateArtifactUUId();
1841 heatEnvironmentArtifactUuid = vfmc.getHeatEnvironmentArtifactUuid();
1843 if (heatTemplateArtifactUuid == null) {
1844 String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString;
1845 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1846 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1847 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1848 MsoAlarmLogger.CRITICAL, error);
1849 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1851 heatTemplate = db.getHeatTemplateByArtifactUuidRegularQuery(heatTemplateArtifactUuid);
1854 if (heatTemplate == null) {
1855 String error = "Update VNF: undefined Heat Template. VF="
1856 + vfModuleType + ", heat template id = " + heatTemplateArtifactUuid;
1857 LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM,
1859 String.valueOf(heatTemplateArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1860 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1861 // Alarm on this error, configuration must be fixed
1862 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1863 MsoAlarmLogger.CRITICAL, error);
1865 throw new VnfException(error, MsoExceptionCategory.INTERNAL);
1868 LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
1870 // Add check for any Environment variable
1871 HeatEnvironment heatEnvironment = null;
1872 String heatEnvironmentString = null;
1874 if (heatEnvironmentArtifactUuid != null) {
1875 LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvironmentArtifactUuid + ":");
1876 heatEnvironment = db.getHeatEnvironmentByArtifactUuid(heatEnvironmentArtifactUuid);
1877 if (heatEnvironment == null) {
1879 String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType
1880 + ", Environment ID="
1881 + heatEnvironmentArtifactUuid;
1882 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvironmentArtifactUuid), "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1883 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1884 // Alarm on this error, configuration must be fixed
1885 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1887 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1889 LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ());
1890 heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ());
1891 LOGGER.debug ("After parsing: " + heatEnvironmentString);
1894 LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType);
1898 LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId="
1899 + heatTemplate.getArtifactUuid ());
1900 Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getArtifactUuid ());
1901 Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> ();
1902 if (nestedTemplates != null) {
1903 // for debugging print them out
1904 LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:");
1905 for (String providerResourceFile : nestedTemplates.keySet ()) {
1906 String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile);
1907 String childTemplateBody = (String) nestedTemplates.get (providerResourceFile);
1908 nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody);
1909 LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody);
1912 LOGGER.debug ("No nested templates found - nothing to do here");
1913 nestedTemplatesChecked = null;
1916 // Also add the files: for any get_files associated with this VfModule
1917 // *if* there are any
1918 LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId="
1919 + vf.getModelUUID());
1921 Map <String, HeatFiles> heatFiles = null;
1922 // Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ());
1923 Map <String, Object> heatFilesObjects = new HashMap <String, Object> ();
1925 // Add ability to turn on adding get_files with volume requests (by property).
1926 boolean addGetFilesOnVolumeReq = false;
1928 String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null);
1929 if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) {
1930 addGetFilesOnVolumeReq = true;
1931 LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString);
1933 } catch (Exception e) {
1934 LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e);
1936 if (!isVolumeRequest || addGetFilesOnVolumeReq) {
1937 LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId="
1938 + vf.getModelUUID());
1940 heatFiles = db.getHeatFilesForVfModule(vf.getModelUUID());
1941 if (heatFiles != null) {
1942 // add these to stack - to be done in createStack
1943 // here, we will map them to Map<String, Object> from Map<String, HeatFiles>
1944 // this will match the nested templates format
1945 LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:");
1947 for (String heatFileName : heatFiles.keySet ()) {
1948 if (heatFileName.startsWith("_ERROR|")) {
1949 // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found.
1950 String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1);
1951 String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId;
1952 LOGGER.debug(error);
1953 LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
1954 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
1955 // Alarm on this error, configuration must be fixed
1956 alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1957 throw new VnfException (error, MsoExceptionCategory.INTERNAL);
1959 String heatFileBody = heatFiles.get (heatFileName).getFileBody ();
1960 LOGGER.debug (heatFileName + " -> " + heatFileBody);
1961 heatFilesObjects.put (heatFileName, heatFileBody);
1964 LOGGER.debug ("No heat files found -nothing to do here");
1965 heatFilesObjects = null;
1969 // Check that required parameters have been supplied
1970 String missingParams = null;
1971 List <String> paramList = new ArrayList <String> ();
1973 // New for 1510 - consult the PARAM_ALIAS field to see if we've been
1974 // supplied an alias. Only check if we don't find it initially.
1975 // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there.
1976 // And also new - add parameter to turn off checking all together if we find we're blocking orders we
1978 boolean haveEnvironmentParameters = false;
1979 boolean checkRequiredParameters = true;
1981 String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER)
1982 .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null);
1983 if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) {
1984 checkRequiredParameters = false;
1985 LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..."
1986 + MsoVnfAdapterImpl.CHECK_REQD_PARAMS);
1988 } catch (Exception e) {
1989 // No problem - default is true
1990 LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e);
1992 // 1604 - Add enhanced environment & parameter checking
1993 // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep
1994 // Part 2: only submit to openstack the parameters in the envt that are in the heat template
1995 // Note this also removes any comments
1996 MsoHeatEnvironmentEntry mhee = null;
1997 if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) {
1998 LOGGER.debug("Enhanced environment checking enabled - 1604");
1999 haveEnvironmentParameters = true;
2000 StringBuilder sb = new StringBuilder(heatEnvironmentString);
2001 //LOGGER.debug("About to create MHEE with " + sb);
2002 mhee = new MsoHeatEnvironmentEntry(sb);
2003 StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n");
2004 for (HeatTemplateParam parm : heatTemplate.getParameters()) {
2005 sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired());
2007 if (!mhee.isValid()) {
2008 sb2.append("Environment says it's not valid! " + mhee.getErrorString());
2010 sb2.append("\nEnvironment:");
2011 sb2.append(mhee.toFullString());
2013 LOGGER.debug(sb2.toString());
2015 LOGGER.debug("NO ENVIRONMENT for this entry");
2018 // New for 1607 - support params of json type
2019 HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>();
2020 boolean hasJson = false;
2022 for (HeatTemplateParam parm : heatTemplate.getParameters ()) {
2023 LOGGER.debug ("Parameter:'" + parm.getParamName ()
2025 + parm.isRequired ()
2027 + parm.getParamAlias ());
2029 String parameterType = parm.getParamType();
2030 if (parameterType == null || parameterType.trim().equals("")) {
2031 parameterType = "String";
2033 JsonNode jsonNode = null;
2034 if (parameterType.equalsIgnoreCase("json") && inputs != null) {
2035 if (inputs.containsKey(parm.getParamName()) ) {
2037 String jsonString = null;
2039 jsonString = inputs.get(parm.getParamName());
2040 jsonNode = new ObjectMapper().readTree(jsonString);
2041 } catch (JsonParseException jpe) {
2042 //TODO - what to do here?
2043 //for now - send the error to debug, but just leave it as a String
2044 String errorMessage = jpe.getMessage();
2045 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
2048 } catch (Exception e) {
2050 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2054 if (jsonNode != null) {
2055 jsonParams.put(parm.getParamName(), jsonNode);
2057 } else if (inputs.containsKey(parm.getParamAlias())) {
2059 String jsonString = null;
2061 jsonString = inputs.get(parm.getParamAlias());
2062 jsonNode = new ObjectMapper().readTree(jsonString);
2063 } catch (JsonParseException jpe) {
2064 //TODO - what to do here?
2065 //for now - send the error to debug, but just leave it as a String
2066 String errorMessage = jpe.getMessage();
2067 LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage,jpe);
2070 } catch (Exception e) {
2072 LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e);
2076 if (jsonNode != null) {
2077 // Notice here - we add it to the jsonParams hashMap with the actual name -
2078 // then manipulate the inputs so when we check for aliases below - it will not
2080 jsonParams.put(parm.getParamName(), jsonNode);
2081 inputs.remove(parm.getParamAlias());
2082 inputs.put(parm.getParamName(), jsonString);
2084 } //TODO add a check for the parameter in the env file
2087 if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) {
2088 if (inputs.containsKey (parm.getParamAlias ())) {
2089 // They've submitted using an alias name. Remove that from inputs, and add back using real name.
2090 String realParamName = parm.getParamName ();
2091 String alias = parm.getParamAlias ();
2092 String value = inputs.get (alias);
2093 LOGGER.debug ("*Found an Alias: paramName=" + realParamName
2098 inputs.remove (alias);
2099 inputs.put (realParamName, value);
2100 LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName);
2102 // enhanced - check if it's in the Environment (note: that method
2103 else if (mhee != null && mhee.containsParameter(parm.getParamName())) {
2105 LOGGER.debug ("Required parameter " + parm.getParamName ()
2106 + " appears to be in environment - do not count as missing");
2109 LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ());
2110 if (missingParams == null) {
2111 missingParams = parm.getParamName ();
2113 missingParams += "," + parm.getParamName ();
2117 paramList.add (parm.getParamName ());
2119 if (missingParams != null) {
2120 // Problem - missing one or more required parameters
2121 if (checkRequiredParameters) {
2122 String error = "Update VNF: Missing Required inputs: " + missingParams;
2123 LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error);
2124 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
2125 throw new VnfException (error, MsoExceptionCategory.USERDATA);
2127 LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block");
2130 LOGGER.debug ("No missing parameters found - ok to proceed");
2133 // Just submit the envt entry as received from the database
2134 String newEnvironmentString = null;
2136 newEnvironmentString = mhee.getRawEntry().toString();
2139 // Remove any extraneous parameters (don't throw an error)
2140 if (inputs != null) {
2141 List <String> extraParams = new ArrayList <String> ();
2142 extraParams.addAll (inputs.keySet ());
2143 // This is not a valid parameter for this template
2144 extraParams.removeAll (paramList);
2145 if (!extraParams.isEmpty ()) {
2146 LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params");
2147 inputs.keySet ().removeAll (extraParams);
2150 // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json
2151 Map<String, Object> inputsTwo = null;
2152 if (hasJson && jsonParams.size() > 0) {
2153 inputsTwo = new HashMap<String, Object>();
2154 for (String keyParamName : inputs.keySet()) {
2155 if (jsonParams.containsKey(keyParamName)) {
2156 inputsTwo.put(keyParamName, jsonParams.get(keyParamName));
2158 inputsTwo.put(keyParamName, inputs.get(keyParamName));
2163 // "Fix" the template if it has CR/LF (getting this from Oracle)
2164 String template = heatTemplate.getHeatTemplate ();
2165 template = template.replaceAll ("\r\n", "\n");
2167 // Have the tenant. Now deploy the stack itself
2168 // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions
2169 // because we already checked for those.
2170 long updateStackStarttime = System.currentTimeMillis ();
2173 heatStack = heatU.updateStack (cloudSiteId,
2177 copyStringInputs (inputs),
2179 heatTemplate.getTimeoutMinutes (),
2180 newEnvironmentString,
2181 //heatEnvironmentString,
2182 nestedTemplatesChecked,
2184 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2186 heatStack = heatU.updateStack (cloudSiteId,
2192 heatTemplate.getTimeoutMinutes (),
2193 newEnvironmentString,
2194 //heatEnvironmentString,
2195 nestedTemplatesChecked,
2197 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null);
2200 } catch (MsoException me) {
2201 me.addContext ("UpdateVFModule");
2202 String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me;
2203 LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
2204 LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me);
2205 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
2206 throw new VnfException (me);
2209 // Make sure DB session is closed
2213 // Reach this point if updateStack is successful.
2214 // Populate remaining rollback info and response parameters.
2215 vfRollback.setVnfId (heatStack.getCanonicalName ());
2216 vfRollback.setVnfCreated (true);
2218 outputs.value = copyStringOutputs (heatStack.getOutputs ());
2219 rollback.value = vfRollback;
2220 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module");
2224 private String getVfModuleNameFromModuleStackId(String vfModuleStackId) {
2225 // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24"
2226 // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack
2227 if (vfModuleStackId == null)
2229 int index = vfModuleStackId.lastIndexOf('/');
2232 String vfModuleName = null;
2234 vfModuleName = vfModuleStackId.substring(0, index);
2235 } catch (Exception e) {
2236 LOGGER.debug("Exception", e);
2237 vfModuleName = null;
2239 return vfModuleName;