diff options
author | ChrisC <cc697w@intl.att.com> | 2017-01-31 11:40:03 +0100 |
---|---|---|
committer | ChrisC <cc697w@intl.att.com> | 2017-01-31 12:59:33 +0100 |
commit | 025301d08b061482c1f046d562bf017c8cbcfe8d (patch) | |
tree | 68a2a549736c9bf0f7cd4e71c76e40ef7e2606f2 /adapters/mso-vnf-adapter/src | |
parent | 2754ad52f833278a5c925bd788a16d1dce16a598 (diff) |
Initial OpenECOMP MSO commit
Change-Id: Ia6a7574859480717402cc2f22534d9973a78fa6d
Signed-off-by: ChrisC <cc697w@intl.att.com>
Diffstat (limited to 'adapters/mso-vnf-adapter/src')
19 files changed, 5553 insertions, 0 deletions
diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/BpelRestClient.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/BpelRestClient.java new file mode 100644 index 0000000000..e76aa40304 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/BpelRestClient.java @@ -0,0 +1,304 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import java.io.IOException; +import java.util.Set; +import java.util.TreeSet; + +import javax.xml.bind.DatatypeConverter; + +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.properties.MsoJavaProperties; +import org.openecomp.mso.properties.MsoPropertiesException; +import org.openecomp.mso.properties.MsoPropertiesFactory; + +/** + * This is the class that is used to POST replies from the MSO adapters to the BPEL engine. + * It can be configured via property file, or modified using the member methods. + * The properties to use are: + * org.openecomp.mso.adapters.vnf.bpelauth encrypted authorization string to send to BEPL engine + * org.openecomp.mso.adapters.vnf.sockettimeout socket timeout value + * org.openecomp.mso.adapters.vnf.connecttimeout connect timeout value + * org.openecomp.mso.adapters.vnf.retrycount number of times to retry failed connections + * org.openecomp.mso.adapters.vnf.retryinterval interval (in seconds) between retries + * org.openecomp.mso.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code + * 900 means "connection was not established") + */ +public class BpelRestClient { + public static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER"; + private static final String PROPERTY_DOMAIN = "org.openecomp.mso.adapters.vnf"; + private static final String BPEL_AUTH_PROPERTY = PROPERTY_DOMAIN+".bpelauth"; + private static final String SOCKET_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".sockettimeout"; + private static final String CONN_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".connecttimeout"; + private static final String RETRY_COUNT_PROPERTY = PROPERTY_DOMAIN+".retrycount"; + private static final String RETRY_INTERVAL_PROPERTY = PROPERTY_DOMAIN+".retryinterval"; + private static final String RETRY_LIST_PROPERTY = PROPERTY_DOMAIN+".retrylist"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + + /** Default socket timeout (in seconds) */ + public static final int DEFAULT_SOCKET_TIMEOUT = 5; + /** Default connect timeout (in seconds) */ + public static final int DEFAULT_CONNECT_TIMEOUT = 5; + /** By default, retry up to five times */ + public static final int DEFAULT_RETRY_COUNT = 5; + /** Default interval to wait between retries (in seconds), negative means use backoff algorithm */ + public static final int DEFAULT_RETRY_INTERVAL = -15; + /** Default list of response codes to trigger a retry */ + public static final String DEFAULT_RETRY_LIST = "408,429,500,502,503,504,900"; // 900 is "connection failed" + /** Default credentials */ + public static final String DEFAULT_CREDENTIALS = ""; + + // Properties of the BPEL client -- all are configurable + private int socketTimeout; + private int connectTimeout; + private int retryCount; + private int retryInterval; + private Set<Integer> retryList; + private String credentials; + + // last response from BPEL engine + private int lastResponseCode; + private String lastResponse; + + /** + * Create a client to send results to the BPEL engine, using configuration from the + * MSO_PROP_VNF_ADAPTER properties. + */ + public BpelRestClient() { + socketTimeout = DEFAULT_SOCKET_TIMEOUT; + connectTimeout = DEFAULT_CONNECT_TIMEOUT; + retryCount = DEFAULT_RETRY_COUNT; + retryInterval = DEFAULT_RETRY_INTERVAL; + setRetryList(DEFAULT_RETRY_LIST); + credentials = DEFAULT_CREDENTIALS; + lastResponseCode = 0; + lastResponse = ""; + + try { + MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + MsoJavaProperties jp = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER); + socketTimeout = jp.getIntProperty(SOCKET_TIMEOUT_PROPERTY, DEFAULT_SOCKET_TIMEOUT); + connectTimeout = jp.getIntProperty(CONN_TIMEOUT_PROPERTY, DEFAULT_CONNECT_TIMEOUT); + retryCount = jp.getIntProperty(RETRY_COUNT_PROPERTY, DEFAULT_RETRY_COUNT); + retryInterval = jp.getIntProperty(RETRY_INTERVAL_PROPERTY, DEFAULT_RETRY_INTERVAL); + setRetryList(jp.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST)); + credentials = jp.getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY); + } catch (MsoPropertiesException e) { + String error = "Unable to get properties:" + MSO_PROP_VNF_ADAPTER; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Camunda", "", MsoLogger.ErrorCode.AvailabilityError, "MsoPropertiesException - Unable to get properties", e); + } + } + + public int getSocketTimeout() { + return socketTimeout; + } + + public void setSocketTimeout(int socketTimeout) { + this.socketTimeout = socketTimeout; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getRetryCount() { + return retryCount; + } + + public void setRetryCount(int retryCount) { + if (retryCount < 0) + retryCount = DEFAULT_RETRY_COUNT; + this.retryCount = retryCount; + } + + public int getRetryInterval() { + return retryInterval; + } + + public void setRetryInterval(int retryInterval) { + this.retryInterval = retryInterval; + } + + public String getCredentials() { + return credentials; + } + + public void setCredentials(String credentials) { + this.credentials = credentials; + } + + public String getRetryList() { + if (retryList.size() == 0) + return ""; + String t = retryList.toString(); + return t.substring(1, t.length()-1); + } + + public void setRetryList(String retryList) { + Set<Integer> s = new TreeSet<Integer>(); + for (String t : retryList.split("[, ]")) { + try { + s.add(Integer.parseInt(t)); + } catch (NumberFormatException x) { + // ignore + } + } + this.retryList = s; + } + + public int getLastResponseCode() { + return lastResponseCode; + } + + public String getLastResponse() { + return lastResponse; + } + + /** + * Post a response to the URL of the BPEL engine. As long as the response code is one of those in + * the retryList, the post will be retried up to "retrycount" times with an interval (in seconds) + * of "retryInterval". If retryInterval is negative, then each successive retry interval will be + * double the previous one. + * @param toBpelStr the content (XML or JSON) to post + * @param bpelUrl the URL to post to + * @param isxml true if the content is XML, otherwise assumed to be JSON + * @return true if the post succeeded, false if all retries failed + */ + public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml) { + debug("Sending response to BPEL: " + toBpelStr); + int totalretries = 0; + int retryint = retryInterval; + while (true) { + sendOne(toBpelStr, bpelUrl, isxml); + // Note: really should handle response code 415 by switching between content types if needed + if (!retryList.contains(lastResponseCode)) { + debug("Got response code: " + lastResponseCode + ": returning."); + return true; + } + if (totalretries >= retryCount) { + debug("Retried " + totalretries + " times, giving up."); + LOGGER.error(MessageEnum.RA_SEND_VNF_NOTIF_ERR, "Could not deliver response to BPEL after "+totalretries+" tries: "+toBpelStr, "Camunda", "", MsoLogger.ErrorCode.BusinessProcesssError, "Could not deliver response to BPEL"); + return false; + } + totalretries++; + int sleepinterval = retryint; + if (retryint < 0) { + // if retry interval is negative double the retry on each pass + sleepinterval = -retryint; + retryint *= 2; + } + debug("Sleeping for " + sleepinterval + " seconds."); + try { + Thread.sleep(sleepinterval * 1000L); + } catch (InterruptedException e) { + // ignore + } + } + } + private void debug(String m) { + LOGGER.debug(m); +// System.err.println(m); + } + private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) { + LOGGER.debug("Sending to BPEL server: "+bpelUrl); + LOGGER.debug("Content is: "+toBpelStr); + + //POST + HttpPost post = new HttpPost(bpelUrl); + if (credentials != null && !credentials.isEmpty()) + post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes())); + + //ContentType + ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON; + post.setEntity(new StringEntity(toBpelStr, ctype)); + + //Timeouts + RequestConfig requestConfig = RequestConfig + .custom() + .setSocketTimeout(socketTimeout * 1000) + .setConnectTimeout(connectTimeout * 1000) + .build(); + post.setConfig(requestConfig); + + //Client 4.3+ + //Execute & GetResponse + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = client.execute(post)) { + if (response != null) { + lastResponseCode = response.getStatusLine().getStatusCode(); + HttpEntity entity = response.getEntity(); + lastResponse = (entity != null) ? EntityUtils.toString(entity) : ""; + } else { + lastResponseCode = 900; + lastResponse = ""; + } + } catch (Exception e) { + String error = "Error sending Bpel notification:" + toBpelStr; + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, error, "Camunda", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Error sending Bpel notification", e); + lastResponseCode = 900; + lastResponse = ""; + } + LOGGER.debug("Response code from BPEL server: "+lastResponseCode); + LOGGER.debug("Response body is: "+lastResponse); + } + + public static void main(String[] a) throws MsoPropertiesException { + final String bpelengine = "http://mtmac1.research.att.com:8080/catch.jsp"; + final String propfile = "/tmp/mso.vnf.properties"; + // "/Users/eby/src/mso.rest/mso/packages/mso-config-centralized/mso-po-adapter-config/mso.vnf.properties" + final String xml = + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + + "<updateVolumeGroupResponse><volumeGroupId>1464013300723</volumeGroupId><volumeGroupOutputs>" + + "<entry><key>clyde</key><value>10</value></entry>" + + "<entry><key>wayne</key><value>99</value></entry>" + + "<entry><key>mickey</key><value>7</value></entry>" + + "</volumeGroupOutputs></updateVolumeGroupResponse>"; + + MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + msoPropertiesFactory.initializeMsoProperties (MSO_PROP_VNF_ADAPTER, propfile); + + BpelRestClient bc = new BpelRestClient(); + System.out.println(bc.getRetryList()); + System.out.println(bc.getCredentials()); // poAvos:Domain2.0! + + bc.bpelPost(xml, bpelengine, true); + System.out.println("respcode = "+bc.getLastResponseCode()); + System.out.println("resp = "+bc.getLastResponse()); + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/HealthCheckHandler.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/HealthCheckHandler.java new file mode 100644 index 0000000000..108baf3444 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/HealthCheckHandler.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import javax.ws.rs.GET; +import javax.ws.rs.HEAD; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.HealthCheckUtils; +import org.openecomp.mso.utils.UUIDChecker; + + +@Path("/") +public class HealthCheckHandler { + + private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA); + private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER"; + + @HEAD + @GET + @Path("/healthcheck") + @Produces(MediaType.TEXT_HTML) + public Response healthcheck (@QueryParam("requestId") String requestId) { + long startTime = System.currentTimeMillis (); + MsoLogger.setServiceName ("Healthcheck"); + UUIDChecker.verifyOldUUID(requestId, msoLogger); + HealthCheckUtils healthCheck = new HealthCheckUtils (); + if (!healthCheck.siteStatusCheck(msoLogger, startTime)) { + return HealthCheckUtils.HEALTH_CHECK_NOK_RESPONSE; + } + + if (!healthCheck.configFileCheck(msoLogger, startTime, MSO_PROP_VNF_ADAPTER)) { + return HealthCheckUtils.NOT_STARTED_RESPONSE; + } + + if (!healthCheck.catalogDBCheck (msoLogger, startTime)) { + return HealthCheckUtils.NOT_STARTED_RESPONSE; + } + msoLogger.debug("healthcheck - Successful"); + return HealthCheckUtils.HEALTH_CHECK_RESPONSE; + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapter.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapter.java new file mode 100644 index 0000000000..95d8ee23a0 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapter.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebParam.Mode; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.ws.Holder; + +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.openstack.beans.VnfRollback; +import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; +import org.openecomp.mso.entity.MsoRequest; + +import java.util.Map; + +@WebService (name="VnfAdapter", targetNamespace="http://com.att.mso/vnf") +public interface MsoVnfAdapter +{ + /** + * This is the "Create VNF" Web Service Endpoint definition. + */ + @WebMethod + public void createVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map<String,String> inputs, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="vnfId", mode=Mode.OUT) Holder<String> vnfId, + @WebParam(name="outputs", mode=Mode.OUT) Holder<Map<String,String>> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder<VnfRollback> rollback ) + throws VnfException, VnfAlreadyExists; + + @WebMethod + public void updateVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map<String,String> inputs, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="outputs", mode=Mode.OUT) Holder<Map<String,String>> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder<VnfRollback> rollback ) + throws VnfException; + + @WebMethod + public void queryVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="vnfExists", mode=Mode.OUT) Holder<Boolean> vnfExists, + @WebParam(name="vnfId", mode=Mode.OUT) Holder<String> vnfId, + @WebParam(name="status", mode=Mode.OUT) Holder<VnfStatus> status, + @WebParam(name="outputs", mode=Mode.OUT) Holder<Map<String,String>> outputs ) + throws VnfException; + + @WebMethod + public void deleteVnf (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="request") MsoRequest msoRequest) + throws VnfException; + + + @WebMethod + public void rollbackVnf (@WebParam(name="rollback") @XmlElement(required=true) VnfRollback rollback) + throws VnfException; + + @WebMethod + public void createVfModule (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="baseVfHeatStackId") @XmlElement(required=false) String baseVfHeatStackId, + @WebParam(name="inputs") Map<String,String> inputs, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="vnfId", mode=Mode.OUT) Holder<String> vnfId, + @WebParam(name="outputs", mode=Mode.OUT) Holder<Map<String,String>> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder<VnfRollback> rollback ) + throws VnfException, VnfAlreadyExists; + + @WebMethod + public void deleteVfModule (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vfName") @XmlElement(required=true) String vfName, + @WebParam(name="request") MsoRequest msoRequest) + throws VnfException; + + @WebMethod + public void updateVfModule (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="baseVfHeatStackId") @XmlElement(required=false) String baseVfHeatStackId, + @WebParam(name="vfModuleStackId") @XmlElement(required=false) String vfModuleStackId, + @WebParam(name="inputs") Map<String,String> inputs, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="outputs", mode=Mode.OUT) Holder<Map<String,String>> outputs, + @WebParam(name="rollback", mode=Mode.OUT) Holder<VnfRollback> rollback ) + throws VnfException; + + @WebMethod + public void healthCheck (); +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterAsync.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterAsync.java new file mode 100644 index 0000000000..d58e9ee6a8 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterAsync.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; + +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.openstack.beans.VnfRollback; +import java.util.Map; + +/** + * This webservice defines the Asynchronous versions of VNF adapter calls. + * The notification messages for final responses are documented elsewhere + * (by the client service WSDL). + * + */ +@WebService (name="VnfAdapterAsync", targetNamespace="http://com.att.mso/vnfA") +public interface MsoVnfAdapterAsync +{ + /** + * This is the "Create VNF" Web Service Endpoint definition. + */ + @WebMethod + @Oneway + public void createVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map<String,String> inputs, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void updateVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfType") @XmlElement(required=true) String vnfType, + @WebParam(name="vnfVersion") @XmlElement(required=false) String vnfVersion, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="requestType") @XmlElement(required=false) String requestType, + @WebParam(name="volumeGroupHeatStackId") @XmlElement(required=false) String volumeGroupHeatStackId, + @WebParam(name="inputs") Map<String,String> inputs, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void queryVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void deleteVnfA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="vnfName") @XmlElement(required=true) String vnfName, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + @WebMethod + @Oneway + public void rollbackVnfA (@WebParam(name="rollback") @XmlElement(required=true) VnfRollback rollback, + @WebParam(name="messageId") @XmlElement(required=true) String messageId, + @WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl ); + + + @WebMethod + public void healthCheckA (); +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterAsyncImpl.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterAsyncImpl.java new file mode 100644 index 0000000000..c192eb6063 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterAsyncImpl.java @@ -0,0 +1,652 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jws.WebService; +import javax.xml.bind.DatatypeConverter; +import javax.xml.namespace.QName; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Holder; +import javax.xml.ws.handler.MessageContext; + +import org.openecomp.mso.adapters.vnf.async.client.CreateVnfNotification; +import org.openecomp.mso.adapters.vnf.async.client.QueryVnfNotification; +import org.openecomp.mso.adapters.vnf.async.client.UpdateVnfNotification; +import org.openecomp.mso.adapters.vnf.async.client.VnfAdapterNotify; +import org.openecomp.mso.adapters.vnf.async.client.VnfAdapterNotify_Service; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoAlarmLogger; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.properties.MsoPropertiesFactory; +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.openstack.beans.VnfRollback; + +@WebService(serviceName = "VnfAdapterAsync", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapterAsync", targetNamespace = "http://com.att.mso/vnfA") +public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { + + MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + + CloudConfigFactory cloudConfigFactory=new CloudConfigFactory(); + + public static final String MSO_PROP_VNF_ADAPTER="MSO_PROP_VNF_ADAPTER"; + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String BPEL_AUTH_PROP = "org.openecomp.mso.adapters.vnf.bpelauth"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheckA () { + LOGGER.debug ("Health check call in VNF Adapter"); + } + + /** + * This is the asynchronous "Create VNF" web service implementation. + * It will create a new VNF of the requested type in the specified cloud + * and tenant. The tenant must exist before this service is called. + * + * If a VNF with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * All VNF types will be defined in the MSO catalog. The caller must request + * one of these pre-defined types or an error will be returned. Within the + * catalog, each VNF type references (among other things) a Heat template + * which is used to deploy the required VNF artifacts (VMs, networks, etc.) + * to the cloud. + * + * Depending on the Heat template, a variable set of input parameters will + * be defined, some of which are required. The caller is responsible to + * pass the necessary input data for the VNF or an error will be thrown. + * + * The method sends an asynchronous response to the notification URL when + * processing completes. The createAsyncResponse contains the vnfId (the + * canonical name of the stack), a Map of VNF output attributes, and a + * VnfRollback object. This last object can be passed as-is to the + * rollbackVnf operation to undo everything that was created for the VNF. + * This is useful if a VNF is successfully created but the orchestrator + * fails on a subsequent operation. + * + * Note: this method is implemented by calling the synchronous web method + * and translating the response to an asynchronous notification. + * + * @param cloudSiteId CLLI code of the cloud site in which to create the VNF + * @param tenantId Openstack tenant identifier + * @param vnfType VNF type key, should match a VNF definition in catalog DB + * @param vnfName Name to be assigned to the new VNF + * @param inputs Map of key=value inputs for VNF stack creation + * @param failIfExists Flag whether already existing VNF should be considered + * a success or failure + * @param msoRequest Request tracking information for logs + * @param notificationURL the target URL for asynchronous response + */ + @Override + public void createVnfA (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map <String, String> inputs, + Boolean failIfExists, + Boolean backout, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "CreateVnfA"; + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (serviceName); + LOGGER.info (MessageEnum.RA_ASYNC_CREATE_VNF, vnfName, vnfType, cloudSiteId, tenantId, "", "createVnfA"); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + // Use the synchronous method to perform the actual Create + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory, cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <String> vnfId = new Holder <String> (); + Holder <Map <String, String>> outputs = new Holder <Map <String, String>> (); + Holder <VnfRollback> vnfRollback = new Holder <VnfRollback> (); + + try { + vnfAdapter.createVnf (cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + requestType, + volumeGroupHeatStackId, + inputs, + failIfExists, + backout, + msoRequest, + vnfId, + outputs, + vnfRollback); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException in createVnfA", e); + org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createVnfNotification (messageId, false, exCat, eMsg, null, null, null); + } catch (Exception e1) { + error = "Error sending createVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending createVnf notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_CREATE_VNF_COMPLETE, "", "createVnfA", "", "createVnfA"); + return; + } + LOGGER.debug ("Async Create VNF: " + vnfName + " VnfId:" + vnfId.value); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createVnfNotification (messageId, + true, + null, + null, + vnfId.value, + copyCreateOutputs (outputs), + copyVrb (vnfRollback)); + } catch (Exception e) { + error = "Error sending createVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "createVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending createVnf notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_CREATE_VNF_COMPLETE, "", "createVnfA"); + return; + } + + @Override + public void updateVnfA (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map <String, String> inputs, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "UpdateVnfA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + LOGGER.info (MessageEnum.RA_ASYNC_UPDATE_VNF, vnfName, vnfType, cloudSiteId, tenantId, "", "UpdateVnfA"); + + // Use the synchronous method to perform the actual Create + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <String> vnfId = new Holder <String> (); + Holder <Map <String, String>> outputs = new Holder <Map <String, String>> (); + Holder <VnfRollback> vnfRollback = new Holder <VnfRollback> (); + + try { + vnfAdapter.updateVnf (cloudSiteId, tenantId, vnfType,vnfVersion, vnfName, requestType, volumeGroupHeatStackId, inputs, msoRequest, outputs, vnfRollback); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending updateVnf notification", e); + org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateVnfNotification (messageId, false, exCat, eMsg, null, null); + } catch (Exception e1) { + error = "Error sending updateVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending updateVnf notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_UPDATE_VNF_COMPLETE, "", "UpdateVnfA"); + return; + } + LOGGER.debug ("Async Update VNF: " + vnfName + " VnfId:" + vnfId.value); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateVnfNotification (messageId, + true, + null, + null, + copyUpdateOutputs (outputs), + copyVrb (vnfRollback)); + } catch (Exception e) { + error = "Error sending updateVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "UpdateVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending updateVnf notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_UPDATE_VNF_COMPLETE, "", "UpdateVnfA"); + return; + } + + /** + * This is the "Query VNF" web service implementation. + * It will look up a VNF by name or ID in the specified cloud and tenant. + * + * The method returns an indicator that the VNF exists, its Openstack internal + * ID, its status, and the set of outputs (from when the stack was created). + * + * @param cloudSiteId CLLI code of the cloud site in which to query + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + * @param notificationURL the target URL for asynchronous response + */ + @Override + public void queryVnfA (String cloudSiteId, + String tenantId, + String vnfName, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "QueryVnfA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + LOGGER.info (MessageEnum.RA_ASYNC_QUERY_VNF, vnfName, cloudSiteId, tenantId); + + // Use the synchronous method to perform the actual query + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <Boolean> vnfExists = new Holder <Boolean> (); + Holder <String> vnfId = new Holder <String> (); + Holder <VnfStatus> status = new Holder <VnfStatus> (); + Holder <Map <String, String>> outputs = new Holder <Map <String, String>> (); + + try { + vnfAdapter.queryVnf (cloudSiteId, tenantId, vnfName, msoRequest, vnfExists, vnfId, status, outputs); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending queryVnfA notification", e); + org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.queryVnfNotification (messageId, false, exCat, eMsg, null, null, null, null); + } catch (Exception e1) { + error = "Error sending queryVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending queryVnf notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_QUERY_VNF_COMPLETE, "", "queryVnfA"); + return; + } + + if (!vnfExists.value) { + LOGGER.debug ("Async Query, VNF not found"); + } else { + LOGGER.debug ("Async Query, VNF=" + vnfId.value + ", status=" + status.value); + } + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + org.openecomp.mso.adapters.vnf.async.client.VnfStatus vnfS = org.openecomp.mso.adapters.vnf.async.client.VnfStatus.fromValue (status.value.name ()); + notifyPort.queryVnfNotification (messageId, + true, + null, + null, + vnfExists.value, + vnfId.value, + vnfS, + copyQueryOutputs (outputs)); + } catch (Exception e) { + error = "Error sending queryVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "queryVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending queryVnf notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + + LOGGER.info (MessageEnum.RA_ASYNC_QUERY_VNF_COMPLETE, "", "queryVnfA"); + return; + } + + /** + * This is the Asynchronous "Delete VNF" web service implementation. + * It will delete a VNF by name or ID in the specified cloud and tenant. + * + * The method has no outputs. + * + * @param cloudSiteId CLLI code of the cloud site in which to delete + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + * @param notificationURL the target URL for asynchronous response + */ + @Override + public void deleteVnfA (String cloudSiteId, + String tenantId, + String vnfName, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + String serviceName = "DeleteVnfA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + LOGGER.info (MessageEnum.RA_ASYNC_DELETE_VNF, vnfName, cloudSiteId, tenantId); + + // Use the synchronous method to perform the actual delete + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + try { + vnfAdapter.deleteVnf (cloudSiteId, tenantId, vnfName, msoRequest); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending deleteVnfA notification", e); + org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteVnfNotification (messageId, false, exCat, eMsg); + } catch (Exception e1) { + error = "Error sending deleteVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending deleteVnfA notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_DELETE_VNF_COMPLETE, "", "deleteVnfA"); + return; + } + + LOGGER.debug ("Async Delete VNF: " + vnfName); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteVnfNotification (messageId, true, null, null); + + } catch (Exception e) { + error = "Error sending deleteVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "deleteVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending deleteVnfA notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + + LOGGER.info (MessageEnum.RA_ASYNC_DELETE_VNF_COMPLETE, "", "deleteVnfA"); + return; + } + + /** + * This web service endpoint will rollback a previous Create VNF operation. + * A rollback object is returned to the client in a successful creation + * response. The client can pass that object as-is back to the rollbackVnf + * operation to undo the creation. + */ + @Override + public void rollbackVnfA (VnfRollback rollback, String messageId, String notificationUrl) { + String serviceName = "RollbackVnfA"; + MsoLogger.setServiceName (serviceName); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + String error; + // rollback may be null (e.g. if stack already existed when Create was called) + if (rollback == null) { + error = "Empty Rollback: No action to perform"; + LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "", "rollbackVnfA"); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + return; + } + + MsoLogger.setLogContext (rollback.getMsoRequest ()); + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK_VNF, "", "rollbackVnfA"); + + // Use the synchronous method to perform the actual rollback + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + try { + vnfAdapter.rollbackVnf (rollback); + MsoLogger.setServiceName (serviceName); + } catch (VnfException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending rollbackVnfA notification", e); + org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.openecomp.mso.adapters.vnf.async.client.MsoExceptionCategory.fromValue (e.getFaultInfo () + .getCategory () + .name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackVnfNotification (messageId, false, exCat, eMsg); + } catch (Exception e1) { + error = "Error sending rollbackVnf notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending rollbackVnfA notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK_VNF_COMPLETE, "", "rollbackVnfA"); + return; + } + + LOGGER.debug ("Async Rollback VNF:" + rollback.getVnfId ()); + // Build and send Asynchronous response + try { + VnfAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackVnfNotification (messageId, true, null, null); + } catch (Exception e) { + error = "Error sending rollbackVnf notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, "", "rollbackVnfA", MsoLogger.ErrorCode.BusinessProcesssError, "Exception sending rollbackVnfA notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK_VNF_COMPLETE, "", "rollbackVnfA"); + return; + } + + private org.openecomp.mso.adapters.vnf.async.client.VnfRollback copyVrb (Holder <VnfRollback> hVrb) { + org.openecomp.mso.adapters.vnf.async.client.VnfRollback cvrb = new org.openecomp.mso.adapters.vnf.async.client.VnfRollback (); + + if (hVrb != null && hVrb.value != null) { + org.openecomp.mso.adapters.vnf.async.client.MsoRequest cmr = new org.openecomp.mso.adapters.vnf.async.client.MsoRequest (); + + cvrb.setCloudSiteId (hVrb.value.getCloudSiteId ()); + if (hVrb.value.getMsoRequest() != null) { + cmr.setRequestId (hVrb.value.getMsoRequest ().getRequestId ()); + cmr.setServiceInstanceId (hVrb.value.getMsoRequest ().getServiceInstanceId ()); + } else { + cmr.setRequestId (null); + cmr.setServiceInstanceId (null); + } + cvrb.setMsoRequest (cmr); + cvrb.setVnfId (hVrb.value.getVnfId ()); + cvrb.setTenantId (hVrb.value.getTenantId ()); + cvrb.setTenantCreated (hVrb.value.getTenantCreated ()); + cvrb.setVnfCreated (hVrb.value.getVnfCreated ()); + } + return cvrb; + } + + private CreateVnfNotification.Outputs copyCreateOutputs (Holder <Map <String, String>> hMap) { + + CreateVnfNotification.Outputs outputs = new CreateVnfNotification.Outputs (); + + if (hMap != null && hMap.value != null) { + Map <String, String> sMap = new HashMap <String, String> (); + sMap = hMap.value; + CreateVnfNotification.Outputs.Entry entry = new CreateVnfNotification.Outputs.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + outputs.getEntry ().add (entry); + } + } + return outputs; + } + + private UpdateVnfNotification.Outputs copyUpdateOutputs (Holder <Map <String, String>> hMap) { + + UpdateVnfNotification.Outputs outputs = new UpdateVnfNotification.Outputs (); + + if (hMap != null && hMap.value != null) { + Map <String, String> sMap = new HashMap <String, String> (); + sMap = hMap.value; + UpdateVnfNotification.Outputs.Entry entry = new UpdateVnfNotification.Outputs.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + outputs.getEntry ().add (entry); + } + } + return outputs; + } + + private QueryVnfNotification.Outputs copyQueryOutputs (Holder <Map <String, String>> hMap) { + + QueryVnfNotification.Outputs outputs = new QueryVnfNotification.Outputs (); + + if (hMap != null && hMap.value != null) { + Map <String, String> sMap = new HashMap <String, String> (); + sMap = hMap.value; + + QueryVnfNotification.Outputs.Entry entry = new QueryVnfNotification.Outputs.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + outputs.getEntry ().add (entry); + } + } + return outputs; + } + + private VnfAdapterNotify getNotifyEP (String notificationUrl) { + + URL warWsdlLoc = null; + try { + warWsdlLoc = Thread.currentThread ().getContextClassLoader ().getResource ("VnfAdapterNotify.wsdl"); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "VnfAdapterNotify.wsdl", "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - WSDL not found", e); + } + if (warWsdlLoc == null) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "VnfAdapterNotify.wsdl", "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "WSDL not found"); + } else { + try { + LOGGER.debug ("VnfAdpaterNotify.wsdl location:" + warWsdlLoc.toURI ().toString ()); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_URL_CONVENTION_EXC, "VnfAdapterNotify.wsdl", "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - WSDL URL convention", e); + } + } + + VnfAdapterNotify_Service notifySvc = new VnfAdapterNotify_Service (warWsdlLoc, + new QName ("http://com.att.mso/vnfNotify", + "vnfAdapterNotify")); + + VnfAdapterNotify notifyPort = notifySvc.getMsoVnfAdapterAsyncImplPort (); + + BindingProvider bp = (BindingProvider) notifyPort; + + URL epUrl = null; + try { + epUrl = new URL (notificationUrl); + } catch (MalformedURLException e1) { + LOGGER.error (MessageEnum.RA_INIT_NOTIF_EXC, "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "MalformedURLException", e1); + } + + LOGGER.debug ("Notification Endpoint URL: " + epUrl.toExternalForm ()); + + bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY, epUrl.toExternalForm ()); + + // authentication + try { + Map <String, Object> req_ctx = bp.getRequestContext (); + Map <String, List <String>> headers = new HashMap <String, List <String>> (); + + String userCredentials = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER).getEncryptedProperty (BPEL_AUTH_PROP, + "", + ENCRYPTION_KEY); + + String basicAuth = "Basic " + DatatypeConverter.printBase64Binary (userCredentials.getBytes ()); + req_ctx.put (MessageContext.HTTP_REQUEST_HEADERS, headers); + headers.put ("Authorization", Collections.singletonList (basicAuth)); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_SET_CALLBACK_AUTH_EXC, "", "getNotifyEP", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Unable to set authorization in callback request", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, "Unable to set authorization in callback request"); + } + + return notifyPort; + } + +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterImpl.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterImpl.java new file mode 100644 index 0000000000..757f875128 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/MsoVnfAdapterImpl.java @@ -0,0 +1,2391 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.openecomp.mso.adapters.vnf.exceptions.VnfAlreadyExists; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; +import org.openecomp.mso.adapters.vnf.exceptions.VnfNotFound; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.cloud.CloudConfig; +import org.openecomp.mso.cloud.CloudSite; +import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning; +import org.openecomp.mso.db.catalog.CatalogDatabase; +import org.openecomp.mso.db.catalog.beans.HeatEnvironment; +import org.openecomp.mso.db.catalog.beans.HeatFiles; +import org.openecomp.mso.db.catalog.beans.HeatTemplate; +import org.openecomp.mso.db.catalog.beans.HeatTemplateParam; +import org.openecomp.mso.db.catalog.beans.VnfResource; +import org.openecomp.mso.db.catalog.beans.VfModule; +import org.openecomp.mso.db.catalog.beans.VnfComponent; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoAlarmLogger; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.HeatStatus; +import org.openecomp.mso.openstack.beans.StackInfo; +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.openstack.beans.VnfRollback; +import org.openecomp.mso.openstack.exceptions.MsoException; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; +import org.openecomp.mso.openstack.utils.MsoHeatUtils; +import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate; +import org.openecomp.mso.openstack.utils.MsoHeatEnvironmentEntry; +import org.openecomp.mso.properties.MsoPropertiesFactory; + +import org.codehaus.jackson.JsonFactory; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.ObjectMapper; + +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.openecomp.mso.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://com.att.mso/vnf") +public class MsoVnfAdapterImpl implements MsoVnfAdapter { + + CloudConfigFactory cloudConfigFactory = new CloudConfigFactory(); + protected CloudConfig cloudConfig = null; + + MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory(); + + private static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER"; + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter."; + private static final String LOG_REPLY_NAME = "MSO-VnfAdapter:MSO-BPMN."; + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.openecomp.mso.adapters.vnf.checkRequiredParameters"; + private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.openecomp.mso.adapters.vnf.addGetFilesOnVolumeReq"; + + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheck () { + LOGGER.debug ("Health check call in VNF Adapter"); + } + + /** + * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL. + * @see MsoVnfAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory) + */ + public MsoVnfAdapterImpl() { + + } + + /** + * This constructor MUST be used if this class is called with the new operator. + * @param msoPropFactory + */ + public MsoVnfAdapterImpl(MsoPropertiesFactory msoPropFactory, CloudConfigFactory cloudConfigFact) { + this.msoPropertiesFactory = msoPropFactory; + this.cloudConfigFactory = cloudConfigFact; + } + + /** + * This is the "Create VNF" web service implementation. + * It will create a new VNF of the requested type in the specified cloud + * and tenant. The tenant must exist before this service is called. + * + * If a VNF with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * All VNF types will be defined in the MSO catalog. The caller must request + * one of these pre-defined types or an error will be returned. Within the + * catalog, each VNF type references (among other things) a Heat template + * which is used to deploy the required VNF artifacts (VMs, networks, etc.) + * to the cloud. + * + * Depending on the Heat template, a variable set of input parameters will + * be defined, some of which are required. The caller is responsible to + * pass the necessary input data for the VNF or an error will be thrown. + * + * The method returns the vnfId (the canonical name), a Map of VNF output + * attributes, and a VnfRollback object. This last object can be passed + * as-is to the rollbackVnf operation to undo everything that was created + * for the VNF. This is useful if a VNF is successfully created but the + * orchestrator fails on a subsequent operation. + * + * @param cloudSiteId CLLI code of the cloud site in which to create the VNF + * @param tenantId Openstack tenant identifier + * @param vnfType VNF type key, should match a VNF definition in catalog DB + * @param vnfVersion VNF version key, should match a VNF definition in catalog DB + * @param vnfName Name to be assigned to the new VNF + * @param inputs Map of key=value inputs for VNF stack creation + * @param failIfExists Flag whether already existing VNF should be considered + * a success or failure + * @param msoRequest Request tracking information for logs + * @param vnfId Holder for output VNF Openstack ID + * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc) + * @param rollback Holder for returning VnfRollback object + */ + @Override + public void createVnf (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map <String, String> inputs, + Boolean failIfExists, + Boolean backout, + MsoRequest msoRequest, + Holder <String> vnfId, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException { + // Create a hook here to catch shortcut createVf requests: + if (requestType != null) { + if (requestType.startsWith("VFMOD")) { + LOGGER.debug("Calling createVfModule from createVnf -- requestType=" + requestType); + String newRequestType = requestType.substring(5); + String vfVolGroupHeatStackId = ""; + String vfBaseHeatStackId = ""; + try { + if (volumeGroupHeatStackId != null) { + vfVolGroupHeatStackId = volumeGroupHeatStackId.substring(0, volumeGroupHeatStackId.lastIndexOf("|")); + vfBaseHeatStackId = volumeGroupHeatStackId.substring(volumeGroupHeatStackId.lastIndexOf("|")+1); + } + } catch (Exception e) { + // might be ok - both are just blank + LOGGER.debug("ERROR trying to parse the volumeGroupHeatStackId " + volumeGroupHeatStackId); + } + this.createVfModule(cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + newRequestType, + vfVolGroupHeatStackId, + vfBaseHeatStackId, + inputs, + failIfExists, + backout, + msoRequest, + vnfId, + outputs, + rollback); + return; + } + } + // createVf will know if the requestType starts with "X" that it's the "old" way + StringBuilder newRequestTypeSb = new StringBuilder("X"); + String vfVolGroupHeatStackId = ""; + String vfBaseHeatStackId = ""; + if (requestType != null) { + newRequestTypeSb.append(requestType); + } + this.createVfModule(cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + newRequestTypeSb.toString(), + vfVolGroupHeatStackId, + vfBaseHeatStackId, + inputs, + failIfExists, + backout, + msoRequest, + vnfId, + outputs, + rollback); + return; + // End createVf shortcut + } + + @Override + public void updateVnf (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + Map <String, String> inputs, + MsoRequest msoRequest, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException { + MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ()); + MsoLogger.setServiceName ("UpdateVnf"); + String requestTypeString = ""; + if (requestType != null && !requestType.equals("")) { + requestTypeString = requestType; + } + String nestedStackId = null; + if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) { + nestedStackId = volumeGroupHeatStackId; + } + + LOGGER.debug ("Updating VNF: " + vnfName + " of type " + vnfType + "in " + cloudSiteId + "/" + tenantId); + LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + VnfRollback vnfRollback = new VnfRollback (); + vnfRollback.setCloudSiteId (cloudSiteId); + vnfRollback.setTenantId (tenantId); + vnfRollback.setMsoRequest (msoRequest); + vnfRollback.setRequestType(requestTypeString); + + // First, look up to see if the VNF already exists. + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + StackInfo heatStack = null; + long queryStackStarttime1 = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName); + LOGGER.recordMetricEvent (queryStackStarttime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVNF"); + String error = "Update VNF: Query " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (queryStackStarttime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in updateVnf", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) { + // Not Found + String error = "Update VNF: Stack " + vnfName + " does not exist in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Stack " + vnfName + " does not exist"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfNotFound (cloudSiteId, tenantId, vnfName); + } else { + LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ()); + // Populate the outputs from the existing stack. + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vnfRollback; // Default rollback - no updates performed + } + + // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId): + StackInfo nestedHeatStack = null; + long queryStackStarttime2 = System.currentTimeMillis (); + if (nestedStackId != null) { + try { + LOGGER.debug("Querying for nestedStackId = " + nestedStackId); + nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId); + LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVNF"); + String error = "Update VNF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.AvailabilityError, "Exception trying to query nested stack", me); + LOGGER.debug("ERROR trying to query nested stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) { + String error = "Update VNF: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.AvailabilityError, "Attached heatStack ID DOES NOT EXIST"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + LOGGER.debug(error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested heat stack - copying values to inputs"); + this.sendMapToDebug(inputs); + heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false); + this.sendMapToDebug(inputs); + } + } + + // Ready to deploy the new VNF + + try(CatalogDatabase db = new CatalogDatabase ()) { + // Retrieve the VNF definition + VnfResource vnf; + if (vnfVersion != null && !vnfVersion.isEmpty ()) { + vnf = db.getVnfResource (vnfType, vnfVersion); + } else { + vnf = db.getVnfResource (vnfType); + } + if (vnf == null) { + String error = "Update VNF: Unknown VNF Type: " + vnfType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Unknown VNF Type"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug ("Got VNF definition from Catalog: " + vnf.toString ()); + + // Currently, all VNFs are orchestrated via HEAT + if (!"HEAT".equals (vnf.getOrchestrationMode ())) { + String error = "Update VNF: Configuration error: VNF=" + vnfType; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, " VNF=" + vnfType, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Configuration error"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } + + //1604 - Need to handle an updateVolume request. + VnfComponent vnfComponent = null; + if (requestTypeString != null && !requestTypeString.equals("")) { + LOGGER.debug("About to query for vnfComponent id = " + vnf.getId() + ", type = " + requestTypeString.toUpperCase()); + vnfComponent = db.getVnfComponent(vnf.getId(), requestTypeString.toUpperCase()); + if (vnfComponent == null) { + String error = "Update VNF: Cannot find VNF Component entry for: " + vnfType + ", type = " + requestTypeString.toUpperCase(); + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Cannot find VNF Component entry"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug("FOUND VnfComponent: " + vnfComponent.toString()); + } + + HeatTemplate heatTemplate = db.getHeatTemplate (vnf.getTemplateId ()); + if (heatTemplate == null) { + String error = "Update VNF: undefined Heat Template. VNF=" + vnfType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", String.valueOf(vnf.getTemplateId ()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: undefined Heat Template"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } + + // If this is a component request - get the template associated for volumes + // May change this - for now get both templates - but volume will be 2nd, which makes sense + // for the rest of the code. Same with envt later + if (vnfComponent != null) { + LOGGER.debug("Querying db to find component template " + vnfComponent.getHeatTemplateId()); + heatTemplate = db.getHeatTemplate(vnfComponent + .getHeatTemplateId()); + if (heatTemplate == null) { + String error = "Update VNF: undefined Heat Template for Volume Component. VNF=" + + vnfType; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "Heat Template ID", + String.valueOf(vnfComponent.getHeatTemplateId()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: undefined Heat Template for Volume Component"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } + } + + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ()); + + // Add check for any Environment variable + HeatEnvironment heatEnvironment = null; + String heatEnvironmentString = null; + + if (vnf.getEnvironmentId () != null) { + LOGGER.debug ("about to call getHeatEnvironment with :" + vnf.getEnvironmentId () + ":"); + heatEnvironment = db.getHeatEnvironment (vnf.getEnvironmentId ()); + if (heatEnvironment == null) { + + String error = "Create VNF: undefined Heat Environment. VNF=" + vnfType + + ", Environment ID=" + + vnf.getEnvironmentId (); + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(vnf.getEnvironmentId ()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Create VNF: undefined Heat Environment"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ()); + heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ()); + LOGGER.debug ("After parsing: " + heatEnvironmentString); + } + } else { + LOGGER.debug ("no environment parameter for this VNF " + vnfType); + } + + //1604 - override the VNF environment with the one for the component + if(vnfComponent != null) { + if (vnfComponent.getHeatEnvironmentId () != null) { + LOGGER.debug ("about to call getHeatEnvironment with :" + vnfComponent.getHeatEnvironmentId () + ":"); + heatEnvironment = db.getHeatEnvironment (vnfComponent.getHeatEnvironmentId ()); + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VNF=" + vnfType + + ", Environment ID=" + + vnfComponent.getHeatEnvironmentId (); + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(vnfComponent.getHeatEnvironmentId ()), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: undefined Heat Environment"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ()); + heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ()); + LOGGER.debug ("after parsing: " + heatEnvironmentString); + } + } else { + LOGGER.debug ("no environment parameter for this VNF VOLUME component " + vnfType); + } + } + // End 1604 + + + LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId=" + + heatTemplate.getId ()); + Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getId ()); + Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> (); + if (nestedTemplates != null) { + // for debugging print them out + LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:"); + for (String providerResourceFile : nestedTemplates.keySet ()) { + String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile); + String childTemplateBody = (String) nestedTemplates.get (providerResourceFile); + nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody); + LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody); + } + } else { + LOGGER.debug ("No nested templates found - nothing to do here"); + nestedTemplatesChecked = null; + } + + // Also add the files: for any get_files associated with this vnf_resource_id + // *if* there are any + LOGGER.debug ("In MsoVnfAdapterImpl.updateVnf, about to call db.getHeatFiles avec vnfResourceId=" + + vnf.getId ()); + Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ()); + Map <String, Object> heatFilesObjects = new HashMap <String, Object> (); + if (heatFiles != null) { + // add these to stack - to be done in createStack + // here, we will map them to Map<String, Object> from Map<String, HeatFiles> + // this will match the nested templates format + LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:"); + + for (String heatFileName : heatFiles.keySet ()) { + String heatFileBody = heatFiles.get (heatFileName).getFileBody (); + // Remove the file:/// enforcement for get_file: + //String heatFileNameChecked = this.enforceFilePrefix (heatFileName); + String heatFileNameChecked = heatFileName; + LOGGER.debug (heatFileNameChecked + " -> " + heatFileBody); + heatFilesObjects.put (heatFileNameChecked, heatFileBody); + } + } else { + LOGGER.debug ("No heat files found -nothing to do here"); + heatFilesObjects = null; + } + + // Check that required parameters have been supplied + String missingParams = null; + List <String> paramList = new ArrayList <String> (); + + // New for 1510 - consult the PARAM_ALIAS field to see if we've been + // supplied an alias. Only check if we don't find it initially. + // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there. + // And also new - add parameter to turn off checking all together if we find we're blocking orders we + // shouldn't + boolean haveEnvironmentParameters = false; + boolean checkRequiredParameters = true; + try { + String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER) + .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e); + } + // 1604 - Add enhanced environment & parameter checking + // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep + // Part 2: only submit to openstack the parameters in the envt that are in the heat template + // Note this also removes any comments + MsoHeatEnvironmentEntry mhee = null; + if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) { + LOGGER.debug("Enhanced environment checking enabled - 1604"); + haveEnvironmentParameters = true; + StringBuilder sb = new StringBuilder(heatEnvironmentString); + //LOGGER.debug("About to create MHEE with " + sb); + mhee = new MsoHeatEnvironmentEntry(sb); + StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n"); + for (HeatTemplateParam parm : heatTemplate.getParameters()) { + sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired()); + } + if (!mhee.isValid()) { + sb2.append("Environment says it's not valid! " + mhee.getErrorString()); + } else { + sb2.append("\nEnvironment:"); + sb2.append(mhee.toFullString()); + } + LOGGER.debug(sb2.toString()); + } else { + LOGGER.debug("NO ENVIRONMENT for this entry"); + } + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + LOGGER.debug ("Parameter:'" + parm.getParamName () + + "', isRequired=" + + parm.isRequired () + + ", alias=" + + parm.getParamAlias ()); + if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) { + if (inputs.containsKey (parm.getParamAlias ())) { + // They've submitted using an alias name. Remove that from inputs, and add back using real name. + String realParamName = parm.getParamName (); + String alias = parm.getParamAlias (); + String value = inputs.get (alias); + LOGGER.debug ("*Found an Alias: paramName=" + realParamName + + ",alias=" + + alias + + ",value=" + + value); + inputs.remove (alias); + inputs.put (realParamName, value); + LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName); + } + // enhanced - check if it's in the Environment (note: that method + else if (mhee != null && mhee.containsParameter(parm.getParamName())) { + + LOGGER.debug ("Required parameter " + parm.getParamName () + + " appears to be in environment - do not count as missing"); + } + else { + LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ()); + if (missingParams == null) { + missingParams = parm.getParamName (); + } else { + missingParams += "," + parm.getParamName (); + } + } + } + paramList.add (parm.getParamName ()); + } + if (missingParams != null) { + // Problem - missing one or more required parameters + if (checkRequiredParameters) { + String error = "Update VNF: Missing Required inputs: " + missingParams; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Update VNF: Missing Required inputs"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + + // Here - modify heatEnvironmentString + StringBuilder parsedEnvironmentString = null; + String newEnvironmentString = null; + if (mhee != null) { + LOGGER.debug("Environment before:\n" + heatEnvironmentString); + parsedEnvironmentString = mhee.toFullStringExcludeNonParams(heatTemplate.getParameters()); + LOGGER.debug("Environment after:\n" + parsedEnvironmentString.toString()); + newEnvironmentString = parsedEnvironmentString.toString(); + } + + // Remove any extraneous parameters (don't throw an error) + if (inputs != null) { + List <String> extraParams = new ArrayList <String> (); + extraParams.addAll (inputs.keySet ()); + // This is not a valid parameter for this template + extraParams.removeAll (paramList); + if (!extraParams.isEmpty ()) { + LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "VNF Extra params"); + inputs.keySet ().removeAll (extraParams); + } + } + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + // Have the tenant. Now deploy the stack itself + // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions + // because we already checked for those. + long updateStackStarttime = System.currentTimeMillis (); + try { + heatStack = heatU.updateStack (cloudSiteId, + tenantId, + vnfName, + template, + copyStringInputs (inputs), + true, + heatTemplate.getTimeoutMinutes (), + newEnvironmentString, + //heatEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects); + LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateStack", vnfName); + } catch (MsoException me) { + me.addContext ("UpdateVNF"); + String error = "Update VNF " + vnfType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", vnfName); + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vnfType, cloudSiteId, tenantId, "OpenStack", "updateStack", MsoLogger.ErrorCode.DataError, "Exception - updateStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + } + + // Reach this point if updateStack is successful. + // Populate remaining rollback info and response parameters. + vnfRollback.setVnfId (heatStack.getCanonicalName ()); + vnfRollback.setVnfCreated (true); + + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vnfRollback; + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VNF"); + return; + } + + /** + * This is the "Query VNF" web service implementation. + * It will look up a VNF by name or ID in the specified cloud and tenant. + * + * The method returns an indicator that the VNF exists, its Openstack internal + * ID, its status, and the set of outputs (from when the stack was created). + * + * @param cloudSiteId CLLI code of the cloud site in which to query + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + * @param vnfExists Flag reporting the result of the query + * @param vnfId Holder for output VNF Openstack ID + * @param outputs Holder for Map of VNF outputs from heat (assigned IPs, etc) + */ + @Override + public void queryVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest, + Holder <Boolean> vnfExists, + Holder <String> vnfId, + Holder <VnfStatus> status, + Holder <Map <String, String>> outputs) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("QueryVnf"); + LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + StackInfo heatStack = null; + long subStartTime = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, vnfName); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vnfName); + } catch (MsoException me) { + me.addContext ("QueryVNF"); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + String error = "Query VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vnfName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + // Populate the outputs based on the returned Stack information + // + if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) { + // Not Found + vnfExists.value = Boolean.FALSE; + status.value = VnfStatus.NOTFOUND; + vnfId.value = null; + outputs.value = new HashMap <String, String> (); // Return as an empty map + + LOGGER.debug ("VNF " + vnfName + " not found"); + } else { + vnfExists.value = Boolean.TRUE; + status.value = stackStatusToVnfStatus (heatStack.getStatus ()); + vnfId.value = heatStack.getCanonicalName (); + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + + LOGGER.debug ("VNF " + vnfName + " found, ID = " + vnfId.value); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF"); + return; + } + + /** + * This is the "Delete VNF" web service implementation. + * It will delete a VNF by name or ID in the specified cloud and tenant. + * + * The method has no outputs. + * + * @param cloudSiteId CLLI code of the cloud site in which to delete + * @param tenantId Openstack tenant identifier + * @param vnfName VNF Name or Openstack ID + * @param msoRequest Request tracking information for logs + */ + @Override + public void deleteVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVnf"); + LOGGER.debug ("Deleting VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + // Use the MsoHeatUtils to delete the stack. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + heat.deleteStack (tenantId, cloudSiteId, vnfName, true); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName); + } catch (MsoException me) { + me.addContext ("DeleteVNF"); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + String error = "Delete VNF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteVNF", MsoLogger.ErrorCode.DataError, "Exception - DeleteVNF", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + // On success, nothing is returned. + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VNF"); + return; + } + + /** + * This web service endpoint will rollback a previous Create VNF operation. + * A rollback object is returned to the client in a successful creation + * response. The client can pass that object as-is back to the rollbackVnf + * operation to undo the creation. + */ + @Override + public void rollbackVnf (VnfRollback rollback) throws VnfException { + long startTime = System.currentTimeMillis (); + MsoLogger.setServiceName ("RollbackVnf"); + // rollback may be null (e.g. if stack already existed when Create was called) + if (rollback == null) { + LOGGER.info (MessageEnum.RA_ROLLBACK_NULL, "OpenStack", "rollbackVnf"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null"); + return; + } + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudSiteId (); + String tenantId = rollback.getTenantId (); + String vnfId = rollback.getVnfId (); + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + LOGGER.debug ("Rolling Back VNF " + vnfId + " in " + cloudSiteId + "/" + tenantId); + + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + // Use the MsoHeatUtils to delete the stack. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + heat.deleteStack (tenantId, cloudSiteId, vnfId, true); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null); + } catch (MsoException me) { + // Failed to rollback the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("RollbackVNF"); + String error = "Rollback VNF: " + vnfId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfId, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - DeleteStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VNF"); + return; + } + + private VnfStatus stackStatusToVnfStatus (HeatStatus stackStatus) { + switch (stackStatus) { + case CREATED: + return VnfStatus.ACTIVE; + case UPDATED: + return VnfStatus.ACTIVE; + case FAILED: + return VnfStatus.FAILED; + default: + return VnfStatus.UNKNOWN; + } + } + + private Map <String, String> copyStringOutputs (Map <String, Object> stackOutputs) { + Map <String, String> stringOutputs = new HashMap <String, String> (); + for (String key : stackOutputs.keySet ()) { + if (stackOutputs.get (key) instanceof String) { + stringOutputs.put (key, (String) stackOutputs.get (key)); + } + } + return stringOutputs; + } + + private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) { + return new HashMap <String, Object> (stringInputs); + } + + /* + * a helper method to make sure that any resource_registry entry of the format + * "xx::xx" : yyy.yaml (or yyy.template) + * has the file name prepended with "file:///" + * Return a String of the environment body that's passed in. + * Have to be careful not to mess up the original formatting. + */ + private String parseEnvironment (String environment) { + StringBuilder sb = new StringBuilder (); + try (Scanner scanner = new Scanner (environment)) { + scanner.useDelimiter ("\n"); + String line = null; + Pattern resource = Pattern.compile ("\\s*\"\\w+::\\S+\"\\s*:"); + LOGGER.debug ("regex pattern for finding a resource_registry: \\s*\"\\w+::\\S+\"\\s*:"); + while (scanner.hasNextLine ()) { + line = scanner.nextLine (); + if (line.toLowerCase ().contains ("resource_registry")) { + sb.append (line + "\n"); + boolean done = false; + // basically keep scanning until EOF or parameters: section + while (scanner.hasNextLine () && !done) { + line = scanner.nextLine (); + if ("parameters:".equalsIgnoreCase (line.trim ())) { + sb.append (line + "\n"); + done = true; + break; + } + Matcher m = resource.matcher (line); + if (m.find ()) { + sb.append (m.group ()); + String secondPart = line.substring (m.end ()).trim (); + String output = secondPart; + if (secondPart.endsWith (".yaml") + || secondPart.endsWith (".template") && !secondPart.startsWith ("file:///")) { + output = "file:///" + secondPart; + LOGGER.debug ("changed " + secondPart + " to " + output); + } // don't do anything if it's not .yaml or .template + sb.append (" " + output + "\n"); + } else { + sb.append (line + "\n"); + } + } + } else { + sb.append (line + "\n"); + continue; + } + } + scanner.close (); + } catch (Exception e) { + LOGGER.debug ("Error trying to scan " + environment, e); + return environment; + } + return sb.toString (); + } + + /* + * helper class to add file:/// to the Provider_Resource_File entry in HEAT_NESTED_TEMPLATE + * and the File_Name entry in HEAT_FILES if the file:/// part is missing. + */ + private String enforceFilePrefix (String string) { + if (string.trim ().startsWith ("file:///")) { + // just leave it + return string; + } + if (string.trim ().endsWith (".yaml") || string.trim ().endsWith (".template")) { + // only .yaml or .template are valid anyway - otherwise don't bother + return "file:///" + string.trim (); + } else { + LOGGER.debug (string + " is NOT a .yaml or .template file"); + } + return string; + } + + private void sendMapToDebug(Map<String, String> inputs) { + int i = 0; + StringBuilder sb = new StringBuilder("inputs:"); + if (inputs == null) { + sb.append("\tNULL"); + } + else if (inputs.size() < 1) { + sb.append("\tEMPTY"); + } else { + for (String str : inputs.keySet()) { + sb.append("\titem " + i++ + ": " + str + "=" + inputs.get(str)); + } + } + LOGGER.debug(sb.toString()); + return; + } + + public void createVfModule(String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + String baseVfHeatStackId, + Map <String, String> inputs, + Boolean failIfExists, + Boolean backout, + MsoRequest msoRequest, + Holder <String> vnfId, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException { + String vfModuleName = vnfName; + String vfModuleType = vnfType; + String vfVersion = vnfVersion; + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateVfModule"); + String requestTypeString = ""; + if (requestType != null && !requestType.equals("")) { + requestTypeString = requestType; + } + String nestedStackId = null; + if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) { + if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) { + nestedStackId = volumeGroupHeatStackId; + } + } + String nestedBaseStackId = null; + if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) { + if (!baseVfHeatStackId.equalsIgnoreCase("null")) { + nestedBaseStackId = baseVfHeatStackId; + } + } + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap<String,String>(); + LOGGER.debug("inputs == null - setting to empty"); + } else { + this.sendMapToDebug(inputs); + } + //This method will also handle doing things the "old" way - i.e., just orchestrate a VNF + boolean oldWay = false; + if (requestTypeString.startsWith("X")) { + oldWay = true; + LOGGER.debug("orchestrating a VNF - *NOT* a module!"); + requestTypeString = requestTypeString.substring(1); + } + + // 1607 - let's parse out the request type we're being sent + boolean isBaseRequest = false; + boolean isVolumeRequest = false; + if (requestTypeString.startsWith("VOLUME")) { + isVolumeRequest = true; + } + + LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + VnfRollback vfRollback = new VnfRollback(); + vfRollback.setCloudSiteId(cloudSiteId); + vfRollback.setTenantId(tenantId); + vfRollback.setMsoRequest(msoRequest); + vfRollback.setRequestType(requestTypeString); + vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId); + vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId); + vfRollback.setIsBase(isBaseRequest); + + // First, look up to see if the VF already exists. + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + StackInfo heatStack = null; + long subStartTime1 = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName); + } catch (MsoException me) { + String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - queryStack", me); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + // New with 1607 - more precise handling/messaging if the stack already exists + if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) { + // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED + HeatStatus status = heatStack.getStatus(); + if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING || status == HeatStatus.UPDATING) { + // fail - it's in progress - return meaningful error + 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."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } + if (status == HeatStatus.FAILED) { + // fail - it exists and is in a FAILED state + String error = "Create VF: Stack " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists and is in FAILED state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } + if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) { + // fail - it exists and is in a FAILED state + String error = "Create VF: Stack " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + 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"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } + if (status == HeatStatus.CREATED) { + // fail - it exists + if (failIfExists != null && failIfExists) { + String error = "Create VF: Stack " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Stack " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, heatStack.getCanonicalName ()); + } else { + LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ()); + // Populate the outputs from the existing stack. + vnfId.value = heatStack.getCanonicalName (); + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; // Default rollback - no updates performed + } + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module"); + return; + + } + + // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf + StackInfo nestedHeatStack = null; + long subStartTime2 = System.currentTimeMillis (); + if (nestedStackId != null) { + try { + LOGGER.debug("Querying for nestedStackId = " + nestedStackId); + nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested stack", me); + LOGGER.debug("ERROR trying to query nested stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) { + String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "queryStack", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached heatStack ID DOES NOT EXIST"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + LOGGER.debug(error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested volume heat stack - copying values to inputs"); + this.sendMapToDebug(inputs); + heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false); + this.sendMapToDebug(inputs); + } + } + + // handle a nestedBaseStackId if sent- this is the stack ID of the base. Should be null for VNF requests + StackInfo nestedBaseHeatStack = null; + long subStartTime3 = System.currentTimeMillis (); + if (nestedBaseStackId != null) { + try { + LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId); + nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId); + LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", vfModuleName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (subStartTime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", vfModuleName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.BusinessProcesssError, "MsoException trying to query nested base stack", me); + LOGGER.debug("ERROR trying to query nested base stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) { + String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + 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"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + LOGGER.debug(error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested base heat stack - copying values to inputs"); + this.sendMapToDebug(inputs); + heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); + this.sendMapToDebug(inputs); + } + } + + // Ready to deploy the new VNF + + try (CatalogDatabase db = new CatalogDatabase()) { + // Retrieve the VF + VfModule vf = null; + VnfResource vnfResource = null; + LOGGER.debug("version: " + vfVersion); + if (!oldWay) { + // Need to handle old and new schema methods - for a time. Try the new way first. + if (vfVersion != null && !vfVersion.isEmpty()) { + vf = db.getVfModuleType(vfModuleType, vfVersion); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the TYPE column - will try in MODEL_NAME"); + vf = db.getVfModuleModelName(vfModuleType, vfVersion); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " and version=" + vfVersion + " in the MODEL_NAME field either - ERROR"); + } + } + } else { + vf = db.getVfModuleType(vfModuleType); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME"); + vf = db.getVfModuleModelName(vfModuleType); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR"); + } + } + } + if (vf == null) { + String error = "Create VF Module: Unable to determine specific VF Module Type: " + + vfModuleType; + if (vfVersion != null && !vfVersion.isEmpty()) { + error += " with version = " + vfVersion; + } + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to determine specific VF Module Type"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug("Got VF module definition from Catalog: " + + vf.toString()); + + if (vf.isBase()) { + isBaseRequest = true; + LOGGER.debug("This is a BASE VF request!"); + } else { + LOGGER.debug("This is *not* a BASE VF request!"); + if (!isVolumeRequest && nestedBaseStackId == null) { + LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request"); + } + } + } else { + if (vfVersion != null && !vfVersion.isEmpty()) { + vnfResource = db.getVnfResource(vnfType, vnfVersion); + } else { + vnfResource = db.getVnfResource(vnfType); + } + if (vnfResource == null) { + String error = "Create VNF: Unknown VNF Type: " + vnfType; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", + vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VNF: Unknown VNF Type"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug("Got VNF module definition from Catalog: " + + vnfResource.toString()); + } + // By here - we have either a vf or vnfResource + + //1607 - Add version check + // First - see if it's in the VnfResource record + // if we have a vf Module - then we have to query to get the VnfResource record. + if (!oldWay) { + if (vf.getVnfResourceId() != null) { + int vnfResourceId = vf.getVnfResourceId(); + vnfResource = db.getVnfResourceById(vnfResourceId); + if (vnfResource == null) { + LOGGER.debug("Unable to find vnfResource at " + vnfResourceId + " will not error for now..."); + } + } + } + String minVersionVnf = null; + String maxVersionVnf = null; + if (vnfResource != null) { + try { + minVersionVnf = vnfResource.getAicVersionMin(); + maxVersionVnf = vnfResource.getAicVersionMax(); + } catch (Exception e) { + LOGGER.debug("Unable to pull min/max version for this VNF Resource entry"); + minVersionVnf = null; + maxVersionVnf = null; + } + if (minVersionVnf != null && minVersionVnf.equals("")) { + minVersionVnf = null; + } + if (maxVersionVnf != null && maxVersionVnf.equals("")) { + maxVersionVnf = null; + } + } + if (minVersionVnf != null && maxVersionVnf != null) { + MavenLikeVersioning aicV = new MavenLikeVersioning(); + CloudSite cloudSite = null; + String aicVersion = ""; + if (this.cloudConfig == null) { + this.cloudConfig = this.cloudConfigFactory.getCloudConfig(); + } + // double check + if (this.cloudConfig != null) { + cloudSite = this.cloudConfig.getCloudSite(cloudSiteId); + if (cloudSite != null) { + aicV.setVersion(cloudSite.getAic_version()); + if ((aicV.isMoreRecentThan(minVersionVnf) || aicV.isTheSameVersion(minVersionVnf)) // aic >= min + && (aicV.isTheSameVersion(maxVersionVnf) || !(aicV.isMoreRecentThan(maxVersionVnf)))) { //aic <= max + LOGGER.debug("VNF Resource " + vnfResource.getVnfType() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version()); + } else { + // ERROR + String error = "VNF Resource type: " + vnfResource.getVnfType() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSite.getId() + " with AIC_Version:" + cloudSite.getAic_version(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + } // let this error out downstream to avoid introducing uncertainty at this stage + } else { + LOGGER.debug("cloudConfig is NULL - cannot check cloud site version"); + } + + } else { + LOGGER.debug("AIC Version not set in VNF_Resource - this is expected thru 1607 - do not error here - not checked."); + } + // End Version check 1607 + + // with VF_MODULE - we have both the non-vol and vol template/envs in that object + // with VNF_RESOURCE - we use the old methods. + Integer heatTemplateId = null; + Integer heatEnvtId = null; + + if (!oldWay) { + if (isVolumeRequest) { + heatTemplateId = vf.getVolTemplateId(); + heatEnvtId = vf.getVolEnvironmentId(); + } else { + heatTemplateId = vf.getTemplateId(); + heatEnvtId = vf.getEnvironmentId(); + } + } else { + if (isVolumeRequest) { + VnfComponent vnfComponent = null; + vnfComponent = db.getVnfComponent(vnfResource.getId(), "VOLUME"); + if (vnfComponent == null) { + String error = "Create VNF: Cannot find VNF Component entry for: " + vnfType + ", type = VOLUME"; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VNF Type", vnfType, "OpenStack", "getVnfComponent", MsoLogger.ErrorCode.DataError, "Create VNF: Cannot find VNF Component entry"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + heatTemplateId = vnfComponent.getHeatTemplateId(); + heatEnvtId = vnfComponent.getHeatEnvironmentId(); + } + } else { + heatTemplateId = vnfResource.getTemplateId(); + heatEnvtId = vnfResource.getEnvironmentId(); + } + } + // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null) + HeatTemplate heatTemplate = null; + if (heatTemplateId == null) { + String error = "Create: No Heat Template ID defined in catalog database for " + vnfType + ", reqType=" + requestTypeString; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vnfType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create: No Heat Template ID defined in catalog database"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } else { + heatTemplate = db.getHeatTemplate(heatTemplateId); + } + if (heatTemplate == null) { + String error = "Create VF/VNF: no entry found for heat template ID = " + heatTemplateId; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "Heat Template ID", + String.valueOf(heatTemplateId), "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create VF/VNF: no entry found for heat template ID = " + heatTemplateId); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } + LOGGER.debug("Got HEAT Template from DB"); + + HeatEnvironment heatEnvironment = null; + String heatEnvironmentString = null; + + if (heatEnvtId != null && heatEnvtId != 0) { + LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvtId + ":"); + heatEnvironment = db.getHeatEnvironment (heatEnvtId); + if (heatEnvironment == null) { + String error = "Create VFModule: undefined Heat Environment. VFModule=" + vfModuleType + + ", Environment ID=" + + heatEnvtId; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvtId), "OpenStack", "getHeatEnvironment", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: undefined Heat Environment"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ()); + heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ()); + LOGGER.debug ("after parsing: " + heatEnvironmentString); + } + } else { + LOGGER.debug ("no environment parameter found for this Type " + vfModuleType); + } + + // 1510 - Add the files: for nested templates *if* there are any + LOGGER.debug ("In MsoVnfAdapterImpl, createVfModule about to call db.getNestedTemplates avec templateId=" + + heatTemplate.getId ()); + Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getId ()); + Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> (); + if (nestedTemplates != null) { + // for debugging print them out + LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:"); + for (String providerResourceFile : nestedTemplates.keySet ()) { + String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile); + String childTemplateBody = (String) nestedTemplates.get (providerResourceFile); + LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody); + nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody); + } + } else { + LOGGER.debug ("No nested templates found - nothing to do here"); + nestedTemplatesChecked = null; // just to make sure + } + + // 1510 - Also add the files: for any get_files associated with this vnf_resource_id + // *if* there are any + Map<String, HeatFiles> heatFiles = null; + Map<String, Object> heatFilesObjects = new HashMap<String, Object>(); + + // Add ability to turn on adding get_files with volume requests (by property). + boolean addGetFilesOnVolumeReq = false; + try { + String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null); + if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) { + addGetFilesOnVolumeReq = true; + LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString); + } + } catch (Exception e) { + LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e); + } + + if (!isVolumeRequest || addGetFilesOnVolumeReq) { + if (oldWay) { + LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFiles avec vnfResourceId=" + + vnfResource.getId()); + heatFiles = db.getHeatFiles(vnfResource.getId()); + } else { + // 1607 - now use VF_MODULE_TO_HEAT_FILES table + LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId=" + + vf.getId()); + heatFiles = db + .getHeatFilesForVfModule(vf.getId()); + } + if (heatFiles != null) { + // add these to stack - to be done in createStack + // here, we will map them to Map<String, Object> from + // Map<String, HeatFiles> + // this will match the nested templates format + LOGGER.debug("Contents of heatFiles - to be added to files: on stack:"); + + for (String heatFileName : heatFiles.keySet()) { + if (heatFileName.startsWith("_ERROR|")) { + // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found. + String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1); + String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId; + LOGGER.debug(error); + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "HEAT_FILES entry not found"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } + String heatFileBody = heatFiles.get(heatFileName) + .getFileBody(); + String heatFileNameChecked = heatFileName; + LOGGER.debug(heatFileNameChecked + " -> " + + heatFileBody); + heatFilesObjects.put(heatFileNameChecked, heatFileBody); + } + } else { + LOGGER.debug("No heat files found -nothing to do here"); + heatFilesObjects = null; + } + } else { + LOGGER.debug("Volume request - DO NOT CHECK for HEAT_FILES"); + } + + // Check that required parameters have been supplied + String missingParams = null; + List <String> paramList = new ArrayList <String> (); + + // New for 1510 - consult the PARAM_ALIAS field to see if we've been + // supplied an alias. Only check if we don't find it initially. + // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there. + // And also new - add parameter to turn off checking all together if we find we're blocking orders we + // shouldn't + boolean haveEnvironmentParameters = false; + boolean checkRequiredParameters = true; + try { + String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER) + .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e); + } + // 1604 - Add enhanced environment & parameter checking + // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep + // Part 2: only submit to openstack the parameters in the envt that are in the heat template + // Note this also removes any comments + MsoHeatEnvironmentEntry mhee = null; + if (heatEnvironmentString != null && heatEnvironmentString.contains ("parameters:")) { + //LOGGER.debug ("Have an Environment argument with a parameters: section - will bypass checking for valid params - but will still check for aliases"); + LOGGER.debug("Enhanced environment checking enabled - 1604"); + haveEnvironmentParameters = true; + StringBuilder sb = new StringBuilder(heatEnvironmentString); + //LOGGER.debug("About to create MHEE with " + sb); + mhee = new MsoHeatEnvironmentEntry(sb); + StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n"); + for (HeatTemplateParam parm : heatTemplate.getParameters()) { + sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired()); + } + if (!mhee.isValid()) { + sb2.append("Environment says it's not valid! " + mhee.getErrorString()); + } else { + sb2.append("\nEnvironment:"); + sb2.append(mhee.toFullString()); + } + LOGGER.debug(sb2.toString()); + } else { + LOGGER.debug("NO ENVIRONMENT for this entry"); + } + // This is kind of a mess. inputs is a Map<String, String> -- + // if one of the parameters is json - we need to pass String, JsonNode - + // so we will store off the parameters that are json in its own HashMap + // if there are any json params - then we convert inputs to a Map<String, Object> + // and pass that to createStack + HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>(); + boolean hasJson = false; + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + LOGGER.debug ("Parameter:'" + parm.getParamName () + + "', isRequired=" + + parm.isRequired () + + ", alias=" + + parm.getParamAlias ()); + // New 1607 - support json type + String parameterType = parm.getParamType(); + if (parameterType == null || parameterType.trim().equals("")) { + parameterType = "String"; + } + JsonNode jsonNode = null; + if (parameterType.equalsIgnoreCase("json") && inputs != null) { + if (inputs.containsKey(parm.getParamName()) ) { + hasJson = true; + String jsonString = null; + try { + jsonString = inputs.get(parm.getParamName()); + jsonNode = new ObjectMapper().readTree(jsonString); + } catch (JsonParseException jpe) { + //TODO - what to do here? + //for now - send the error to debug, but just leave it as a String + String errorMessage = jpe.getMessage(); + LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage()); + hasJson = false; + jsonNode = null; + } + if (jsonNode != null) { + jsonParams.put(parm.getParamName(), jsonNode); + } + } else if (inputs.containsKey(parm.getParamAlias())) { + hasJson = true; + String jsonString = null; + try { + jsonString = inputs.get(parm.getParamAlias()); + jsonNode = new ObjectMapper().readTree(jsonString); + } catch (JsonParseException jpe) { + //TODO - what to do here? + //for now - send the error to debug, but just leave it as a String + String errorMessage = jpe.getMessage(); + LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage()); + hasJson = false; + jsonNode = null; + } + if (jsonNode != null) { + // Notice here - we add it to the jsonParams hashMap with the actual name - + // then manipulate the inputs so when we check for aliases below - it will not + // get flagged. + jsonParams.put(parm.getParamName(), jsonNode); + inputs.remove(parm.getParamAlias()); + inputs.put(parm.getParamName(), jsonString); + } + } //TODO add a check for the parameter in the env file + } + if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) { + // Check if they have an alias + LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs..."); + if (inputs.containsKey (parm.getParamAlias ())) { + // They've submitted using an alias name. Remove that from inputs, and add back using real name. + String realParamName = parm.getParamName (); + String alias = parm.getParamAlias (); + String value = inputs.get (alias); + LOGGER.debug ("*Found an Alias: paramName=" + realParamName + + ",alias=" + + alias + + ",value=" + + value); + inputs.remove (alias); + inputs.put (realParamName, value); + LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName); + } + // enhanced - check if it's in the Environment (note: that method + else if (mhee != null && mhee.containsParameter(parm.getParamName())) { + + LOGGER.debug ("Required parameter " + parm.getParamName () + + " appears to be in environment - do not count as missing"); + } else { + LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ()); + if (missingParams == null) { + missingParams = parm.getParamName (); + } else { + missingParams += "," + parm.getParamName (); + } + } + } + paramList.add (parm.getParamName ()); + } + if (missingParams != null) { + if (checkRequiredParameters) { + // Problem - missing one or more required parameters + String error = "Create VFModule: Missing Required inputs: " + missingParams; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VFModule: Missing Required inputs"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + + // Here - modify heatEnvironmentString + StringBuilder parsedEnvironmentString = null; + String newEnvironmentString = null; + if (mhee != null) { + LOGGER.debug("Environment before:\n" + heatEnvironmentString); + parsedEnvironmentString = mhee.toFullStringExcludeNonParams(heatTemplate.getParameters()); + LOGGER.debug("Environment after:\n" + parsedEnvironmentString.toString()); + newEnvironmentString = parsedEnvironmentString.toString(); + } + + // Remove any extraneous parameters (don't throw an error) + if (inputs != null) { + List <String> extraParams = new ArrayList <String> (); + extraParams.addAll (inputs.keySet ()); + extraParams.removeAll (paramList); + if (!extraParams.isEmpty ()) { + LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params"); + inputs.keySet ().removeAll (extraParams); + } + } + // 1607 - when we get here - we have clean inputs. Check if we have + Map<String, Object> inputsTwo = null; + if (hasJson && jsonParams.size() > 0) { + inputsTwo = new HashMap<String, Object>(); + for (String keyParamName : inputs.keySet()) { + if (jsonParams.containsKey(keyParamName)) { + inputsTwo.put(keyParamName, jsonParams.get(keyParamName)); + } else { + inputsTwo.put(keyParamName, inputs.get(keyParamName)); + } + } + } + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + // Have the tenant. Now deploy the stack itself + // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions + // because we already checked for those. + long createStackStarttime = System.currentTimeMillis (); + try { + // heatStack = heat.createStack(cloudSiteId, tenantId, vnfName, template, inputs, true, + // heatTemplate.getTimeoutMinutes()); + if (backout == null) { + backout = true; + } + if (heat != null) { + LOGGER.debug("heat is not null!!"); + } + + if (!hasJson) { + heatStack = heat.createStack (cloudSiteId, + tenantId, + vfModuleName, + template, + inputs, + true, + heatTemplate.getTimeoutMinutes (), + newEnvironmentString, + //heatEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects, + backout.booleanValue()); + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName); + } else { + heatStack = heat.createStack (cloudSiteId, + tenantId, + vfModuleName, + template, + inputsTwo, + true, + heatTemplate.getTimeoutMinutes (), + newEnvironmentString, + //heatEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects, + backout.booleanValue()); + + } + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "CreateStack", vfModuleName); + } catch (MsoException me) { + me.addContext ("CreateVFModule"); + String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "MsoException - createStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } catch (NullPointerException npe) { + String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe; + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "CreateStack", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createStack", npe); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + LOGGER.debug("NULL POINTER EXCEPTION at heat.createStack"); + //npe.addContext ("CreateVNF"); + throw new VnfException ("NullPointerException during heat.createStack"); + } catch (Exception e) { + LOGGER.recordMetricEvent (createStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack", "OpenStack", "CreateStack", vfModuleName); + LOGGER.debug("unhandled exception at heat.createStack"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack"); + throw new VnfException("Exception during heat.createStack! " + e.getMessage()); + } + } catch (Exception e) { + LOGGER.debug("unhandled exception in create VF"); + throw new VnfException("Exception during create VF " + e.getMessage()); + + } + + // Reach this point if createStack is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfId (heatStack.getCanonicalName ()); + vfRollback.setVnfCreated (true); + + vnfId.value = heatStack.getCanonicalName (); + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; + + LOGGER.debug ("VF Module " + vfModuleName + " successfully created"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module"); + return; + + + } + + public void deleteVfModule (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVf"); + LOGGER.debug ("Deleting VF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + // Use the MsoHeatUtils to delete the stack. Set the polling flag to true. + // The possible outcomes of deleteStack are a StackInfo object with status + // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException + // could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + heat.deleteStack (tenantId, cloudSiteId, vnfName, true); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", vnfName); + } catch (MsoException me) { + me.addContext ("DeleteVNF"); + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", vnfName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "DeleteStack", MsoLogger.ErrorCode.DataError, "Exception - deleteStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + // On success, nothing is returned. + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete VF"); + return; + } + + @Override + public void updateVfModule (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + String baseVfHeatStackId, + String vfModuleStackId, + Map <String, String> inputs, + MsoRequest msoRequest, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException { + String vfModuleName = vnfName; + String vfModuleType = vnfType; + String vfVersion = vnfVersion; + String methodName = "updateVfModule"; + MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ()); + String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName; + MsoLogger.setServiceName (serviceName); + + String requestTypeString = ""; + if (requestType != null && !requestType.equals("")) { + requestTypeString = requestType; + } + String nestedStackId = null; + if (volumeGroupHeatStackId != null && !volumeGroupHeatStackId.equals("")) { + if (!volumeGroupHeatStackId.equalsIgnoreCase("null")) { + nestedStackId = volumeGroupHeatStackId; + } + } + String nestedBaseStackId = null; + if (baseVfHeatStackId != null && !baseVfHeatStackId.equals("")) { + if (!baseVfHeatStackId.equalsIgnoreCase("null")) { + nestedBaseStackId = baseVfHeatStackId; + } + } + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap<String,String>(); + LOGGER.debug("inputs == null - setting to empty"); + } else { + this.sendMapToDebug(inputs); + } + boolean isBaseRequest = false; + boolean isVolumeRequest = false; + if (requestTypeString.startsWith("VOLUME")) { + isVolumeRequest = true; + } + if (vfModuleName == null || vfModuleName.trim().equals("")) { + if (vfModuleStackId != null) { + vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId); + } + } + + LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId); + LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedStackId = " + nestedStackId + ", nestedBaseStackId = " + nestedBaseStackId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + VnfRollback vfRollback = new VnfRollback (); + vfRollback.setCloudSiteId (cloudSiteId); + vfRollback.setTenantId (tenantId); + vfRollback.setMsoRequest (msoRequest); + vfRollback.setRequestType(requestTypeString); + vfRollback.setVolumeGroupHeatStackId(volumeGroupHeatStackId); + vfRollback.setBaseGroupHeatStackId(baseVfHeatStackId); + vfRollback.setIsBase(isBaseRequest); + vfRollback.setVfModuleStackId(vfModuleStackId); + + // First, look up to see if the VNF already exists. + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + MsoHeatUtilsWithUpdate heatU = new MsoHeatUtilsWithUpdate (MSO_PROP_VNF_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + StackInfo heatStack = null; + long queryStackStarttime = System.currentTimeMillis (); + LOGGER.debug("UpdateVfModule - querying for " + vfModuleName); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, vfModuleName); + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVFModule"); + String error = "Update VFModule: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + //TODO - do we need to check for the other status possibilities? + if (heatStack == null || heatStack.getStatus () == HeatStatus.NOTFOUND) { + // Not Found + String error = "Update VF: Stack " + vfModuleName + " does not exist in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_NOT_EXIST, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfNotFound (cloudSiteId, tenantId, vfModuleName); + } else { + LOGGER.debug ("Found Existing stack, status=" + heatStack.getStatus ()); + // Populate the outputs from the existing stack. + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; // Default rollback - no updates performed + } + + // 1604 Cinder Volume support - handle a nestedStackId if sent (volumeGroupHeatStackId): + StackInfo nestedHeatStack = null; + long queryStackStarttime2 = System.currentTimeMillis (); + if (nestedStackId != null) { + try { + LOGGER.debug("Querying for nestedStackId = " + nestedStackId); + nestedHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedStackId); + LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVFModule"); + String error = "Update VF: Attached heatStack ID Query " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (queryStackStarttime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me); + LOGGER.debug("ERROR trying to query nested stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedHeatStack == null || nestedHeatStack.getStatus() == HeatStatus.NOTFOUND) { + MsoLogger.setServiceName (serviceName); + String error = "Update VFModule: Attached volume heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error); + LOGGER.debug(error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested heat stack - copying values to inputs"); + this.sendMapToDebug(inputs); + heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false); + this.sendMapToDebug(inputs); + } + } + // handle a nestedBaseStackId if sent - this is the stack ID of the base. + StackInfo nestedBaseHeatStack = null; + if (nestedBaseStackId != null) { + long queryStackStarttime3 = System.currentTimeMillis (); + try { + LOGGER.debug("Querying for nestedBaseStackId = " + nestedBaseStackId); + nestedBaseHeatStack = heat.queryStack(cloudSiteId, tenantId, nestedBaseStackId); + LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("UpdateVfModule"); + String error = "Update VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.recordMetricEvent (queryStackStarttime3, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, "Exception - " + error, me); + LOGGER.debug("ERROR trying to query nested base stack= " + error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + if (nestedBaseHeatStack == null || nestedBaseHeatStack.getStatus() == HeatStatus.NOTFOUND) { + MsoLogger.setServiceName (serviceName); + String error = "Update VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, error, "OpenStack", "QueryStack", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + LOGGER.debug(error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found nested base heat stack - copying values to inputs"); + this.sendMapToDebug(inputs); + heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); + this.sendMapToDebug(inputs); + } + } + + // Ready to deploy the new VNF + + try (CatalogDatabase db = new CatalogDatabase ()) { + // Retrieve the VF definition + //VnfResource vnf; + VfModule vf = null; + if (vfVersion != null && !vfVersion.isEmpty ()) { + vf = db.getVfModuleType(vfModuleType, vfVersion); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " and version = " + vfVersion + " in the TYPE column - will try in MODEL_NAME"); + vf = db.getVfModuleModelName(vfModuleType, vfVersion); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " and version = " + vfVersion + " in the MODEL_NAME field either - ERROR"); + } + } + } else { + vf = db.getVfModuleType(vfModuleType); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " in the TYPE column - will try in MODEL_NAME"); + vf = db.getVfModuleModelName(vfModuleType); + if (vf == null) { + LOGGER.debug("Unable to find " + vfModuleType + " in the MODEL_NAME field either - ERROR"); + } + } + } + if (vf == null) { + String error = "Update VFModule: Unknown VF Module Type: " + vfModuleType; + if (vfVersion != null && !vfVersion.isEmpty()) { + error += " with version = " + vfVersion; + } + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "VF Module Type", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug ("Got VF module definition from Catalog: " + vf.toString ()); + + HeatTemplate heatTemplate = null; + Integer heatTemplateId = null; + Integer heatEnvtId = null; + if (!isVolumeRequest) { + heatTemplateId = vf.getTemplateId(); + heatEnvtId = vf.getEnvironmentId(); + } else { + heatTemplateId = vf.getVolTemplateId(); + heatEnvtId = vf.getVolEnvironmentId(); + } + if (heatTemplateId == null) { + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestTypeString; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } else { + heatTemplate = db.getHeatTemplate(heatTemplateId); + } + + if (heatTemplate == null) { + String error = "Update VNF: undefined Heat Template. VF=" + + vfModuleType + ", heat template id = " + heatTemplateId; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "Heat Template ID", + String.valueOf(heatTemplateId), "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } + + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ()); + + // Add check for any Environment variable + HeatEnvironment heatEnvironment = null; + String heatEnvironmentString = null; + + if (heatEnvtId != null) { + LOGGER.debug ("about to call getHeatEnvironment with :" + heatEnvtId + ":"); + heatEnvironment = db.getHeatEnvironment (heatEnvtId); + if (heatEnvironment == null) { + + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType + + ", Environment ID=" + + heatEnvtId; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", String.valueOf(heatEnvtId), "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } else { + LOGGER.debug ("Got Heat Environment from DB: " + heatEnvironment.toString ()); + heatEnvironmentString = heatEnvironment.getEnvironment (); //this.parseEnvironment (heatEnvironment.getEnvironment ()); + LOGGER.debug ("After parsing: " + heatEnvironmentString); + } + } else { + LOGGER.debug ("no environment parameter for this VFModuleType " + vfModuleType); + } + + + LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId=" + + heatTemplate.getId ()); + Map <String, Object> nestedTemplates = db.getNestedTemplates (heatTemplate.getId ()); + Map <String, Object> nestedTemplatesChecked = new HashMap <String, Object> (); + if (nestedTemplates != null) { + // for debugging print them out + LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:"); + for (String providerResourceFile : nestedTemplates.keySet ()) { + String providerResourceFileChecked = providerResourceFile; //this.enforceFilePrefix (providerResourceFile); + String childTemplateBody = (String) nestedTemplates.get (providerResourceFile); + nestedTemplatesChecked.put (providerResourceFileChecked, childTemplateBody); + LOGGER.debug (providerResourceFileChecked + " -> " + childTemplateBody); + } + } else { + LOGGER.debug ("No nested templates found - nothing to do here"); + nestedTemplatesChecked = null; + } + + // Also add the files: for any get_files associated with this VfModule + // *if* there are any + LOGGER.debug ("In MsoVnfAdapterImpl.updateVfModule, about to call db.getHeatFiles avec vfModuleId=" + + vf.getId ()); + + Map <String, HeatFiles> heatFiles = null; +// Map <String, HeatFiles> heatFiles = db.getHeatFiles (vnf.getId ()); + Map <String, Object> heatFilesObjects = new HashMap <String, Object> (); + + // Add ability to turn on adding get_files with volume requests (by property). + boolean addGetFilesOnVolumeReq = false; + try { + String propertyString = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_VNF_ADAPTER).getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ, null); + if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) { + addGetFilesOnVolumeReq = true; + LOGGER.debug("AddGetFilesOnVolumeReq - setting to true! " + propertyString); + } + } catch (Exception e) { + LOGGER.debug("An error occured trying to get property " + MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ + " - default to false", e); + } + if (!isVolumeRequest || addGetFilesOnVolumeReq) { + heatFiles = db.getHeatFilesForVfModule(vf.getId()); + if (heatFiles != null) { + // add these to stack - to be done in createStack + // here, we will map them to Map<String, Object> from Map<String, HeatFiles> + // this will match the nested templates format + LOGGER.debug ("Contents of heatFiles - to be added to files: on stack:"); + + for (String heatFileName : heatFiles.keySet ()) { + if (heatFileName.startsWith("_ERROR|")) { + // This means there was an invalid entry in VF_MODULE_TO_HEAT_FILES table - the heat file it pointed to could not be found. + String heatFileId = heatFileName.substring(heatFileName.lastIndexOf("|")+1); + String error = "Create: No HEAT_FILES entry in catalog database for " + vfModuleType + " at HEAT_FILES index=" + heatFileId; + LOGGER.debug(error); + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "HEAT_FILES entry not found at " + heatFileId, vfModuleType, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + throw new VnfException (error, MsoExceptionCategory.INTERNAL); + } + String heatFileBody = heatFiles.get (heatFileName).getFileBody (); + LOGGER.debug (heatFileName + " -> " + heatFileBody); + heatFilesObjects.put (heatFileName, heatFileBody); + } + } else { + LOGGER.debug ("No heat files found -nothing to do here"); + heatFilesObjects = null; + } + } + + // Check that required parameters have been supplied + String missingParams = null; + List <String> paramList = new ArrayList <String> (); + + // New for 1510 - consult the PARAM_ALIAS field to see if we've been + // supplied an alias. Only check if we don't find it initially. + // Also new in 1510 - don't flag missing parameters if there's an environment - because they might be there. + // And also new - add parameter to turn off checking all together if we find we're blocking orders we + // shouldn't + boolean haveEnvironmentParameters = false; + boolean checkRequiredParameters = true; + try { + String propertyString = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_VNF_ADAPTER) + .getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS,null); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfAdapterImpl.CHECK_REQD_PARAMS, e); + } + // 1604 - Add enhanced environment & parameter checking + // Part 1: parse envt entries to see if reqd parameter is there (before used a simple grep + // Part 2: only submit to openstack the parameters in the envt that are in the heat template + // Note this also removes any comments + MsoHeatEnvironmentEntry mhee = null; + if (heatEnvironmentString != null && heatEnvironmentString.toLowerCase ().contains ("parameters:")) { + LOGGER.debug("Enhanced environment checking enabled - 1604"); + haveEnvironmentParameters = true; + StringBuilder sb = new StringBuilder(heatEnvironmentString); + //LOGGER.debug("About to create MHEE with " + sb); + mhee = new MsoHeatEnvironmentEntry(sb); + StringBuilder sb2 = new StringBuilder("\nHeat Template Parameters:\n"); + for (HeatTemplateParam parm : heatTemplate.getParameters()) { + sb2.append("\t" + parm.getParamName() + ", required=" + parm.isRequired()); + } + if (!mhee.isValid()) { + sb2.append("Environment says it's not valid! " + mhee.getErrorString()); + } else { + sb2.append("\nEnvironment:"); + sb2.append(mhee.toFullString()); + } + LOGGER.debug(sb2.toString()); + } else { + LOGGER.debug("NO ENVIRONMENT for this entry"); + } + + // New for 1607 - support params of json type + HashMap<String, JsonNode> jsonParams = new HashMap<String, JsonNode>(); + boolean hasJson = false; + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + LOGGER.debug ("Parameter:'" + parm.getParamName () + + "', isRequired=" + + parm.isRequired () + + ", alias=" + + parm.getParamAlias ()); + // handle json + String parameterType = parm.getParamType(); + if (parameterType == null || parameterType.trim().equals("")) { + parameterType = "String"; + } + JsonNode jsonNode = null; + if (parameterType.equalsIgnoreCase("json") && inputs != null) { + if (inputs.containsKey(parm.getParamName()) ) { + hasJson = true; + String jsonString = null; + try { + jsonString = inputs.get(parm.getParamName()); + jsonNode = new ObjectMapper().readTree(jsonString); + } catch (JsonParseException jpe) { + //TODO - what to do here? + //for now - send the error to debug, but just leave it as a String + String errorMessage = jpe.getMessage(); + LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage()); + hasJson = false; + jsonNode = null; + } + if (jsonNode != null) { + jsonParams.put(parm.getParamName(), jsonNode); + } + } else if (inputs.containsKey(parm.getParamAlias())) { + hasJson = true; + String jsonString = null; + try { + jsonString = inputs.get(parm.getParamAlias()); + jsonNode = new ObjectMapper().readTree(jsonString); + } catch (JsonParseException jpe) { + //TODO - what to do here? + //for now - send the error to debug, but just leave it as a String + String errorMessage = jpe.getMessage(); + LOGGER.debug("Json Error Converting " + parm.getParamName() + " - " + errorMessage); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage()); + hasJson = false; + jsonNode = null; + } + if (jsonNode != null) { + // Notice here - we add it to the jsonParams hashMap with the actual name - + // then manipulate the inputs so when we check for aliases below - it will not + // get flagged. + jsonParams.put(parm.getParamName(), jsonNode); + inputs.remove(parm.getParamAlias()); + inputs.put(parm.getParamName(), jsonString); + } + } //TODO add a check for the parameter in the env file + } + + if (parm.isRequired () && (inputs == null || !inputs.containsKey (parm.getParamName ()))) { + if (inputs.containsKey (parm.getParamAlias ())) { + // They've submitted using an alias name. Remove that from inputs, and add back using real name. + String realParamName = parm.getParamName (); + String alias = parm.getParamAlias (); + String value = inputs.get (alias); + LOGGER.debug ("*Found an Alias: paramName=" + realParamName + + ",alias=" + + alias + + ",value=" + + value); + inputs.remove (alias); + inputs.put (realParamName, value); + LOGGER.debug (alias + " entry removed from inputs, added back using " + realParamName); + } + // enhanced - check if it's in the Environment (note: that method + else if (mhee != null && mhee.containsParameter(parm.getParamName())) { + + LOGGER.debug ("Required parameter " + parm.getParamName () + + " appears to be in environment - do not count as missing"); + } + else { + LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ()); + if (missingParams == null) { + missingParams = parm.getParamName (); + } else { + missingParams += "," + parm.getParamName (); + } + } + } + paramList.add (parm.getParamName ()); + } + if (missingParams != null) { + // Problem - missing one or more required parameters + if (checkRequiredParameters) { + String error = "Update VNF: Missing Required inputs: " + missingParams; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, missingParams, "OpenStack", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new VnfException (error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug ("found missing parameters - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + + // Here - modify heatEnvironmentString + StringBuilder parsedEnvironmentString = null; + String newEnvironmentString = null; + if (mhee != null) { + LOGGER.debug("Environment before:\n" + heatEnvironmentString); + parsedEnvironmentString = mhee.toFullStringExcludeNonParams(heatTemplate.getParameters()); + LOGGER.debug("Environment after:\n" + parsedEnvironmentString.toString()); + newEnvironmentString = parsedEnvironmentString.toString(); + } + + // Remove any extraneous parameters (don't throw an error) + if (inputs != null) { + List <String> extraParams = new ArrayList <String> (); + extraParams.addAll (inputs.keySet ()); + // This is not a valid parameter for this template + extraParams.removeAll (paramList); + if (!extraParams.isEmpty ()) { + LOGGER.warn (MessageEnum.RA_VNF_EXTRA_PARAM, vnfType, extraParams.toString(), "OpenStack", "", MsoLogger.ErrorCode.DataError, "Extra params"); + inputs.keySet ().removeAll (extraParams); + } + } + // 1607 - when we get here - we have clean inputs. Create inputsTwo in case we have json + Map<String, Object> inputsTwo = null; + if (hasJson && jsonParams.size() > 0) { + inputsTwo = new HashMap<String, Object>(); + for (String keyParamName : inputs.keySet()) { + if (jsonParams.containsKey(keyParamName)) { + inputsTwo.put(keyParamName, jsonParams.get(keyParamName)); + } else { + inputsTwo.put(keyParamName, inputs.get(keyParamName)); + } + } + } + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + // Have the tenant. Now deploy the stack itself + // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions + // because we already checked for those. + long updateStackStarttime = System.currentTimeMillis (); + try { + if (!hasJson) { + heatStack = heatU.updateStack (cloudSiteId, + tenantId, + vfModuleName, + template, + copyStringInputs (inputs), + true, + heatTemplate.getTimeoutMinutes (), + newEnvironmentString, + //heatEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects); + LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null); + } else { + heatStack = heatU.updateStack (cloudSiteId, + tenantId, + vfModuleName, + template, + inputsTwo, + true, + heatTemplate.getTimeoutMinutes (), + newEnvironmentString, + //heatEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects); + LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully receive response from Open Stack", "OpenStack", "UpdateStack", null); + + } + } catch (MsoException me) { + me.addContext ("UpdateVFModule"); + String error = "Update VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null); + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - " + error, me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + } + + // Reach this point if updateStack is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfId (heatStack.getCanonicalName ()); + vfRollback.setVnfCreated (true); + + outputs.value = copyStringOutputs (heatStack.getOutputs ()); + rollback.value = vfRollback; + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully update VF Module"); + return; + } + + private String getVfModuleNameFromModuleStackId(String vfModuleStackId) { + // expected format of vfModuleStackId is "MSOTEST51-vSAMP3_base_module-0/1fc1f86c-7b35-447f-99a6-c23ec176ae24" + // before the "/" is the vfModuleName and after the "/" is the heat stack id in Openstack + if (vfModuleStackId == null) + return null; + int index = vfModuleStackId.lastIndexOf('/'); + if (index <= 0) + return null; + String vfModuleName = null; + try { + vfModuleName = vfModuleStackId.substring(0, index); + } catch (Exception e) { + vfModuleName = null; + } + return vfModuleName; + } + +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VfRollback.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VfRollback.java new file mode 100644 index 0000000000..90ab01bd8c --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VfRollback.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + + +import org.openecomp.mso.entity.MsoRequest; + +public class VfRollback { + private String vnfId; + private String tenantId; + private String cloudSiteId; + private boolean tenantCreated = false; + private boolean vnfCreated = false; + private MsoRequest msoRequest; + private String volumeGroupName; + private String volumeGroupId; + private String requestType; + private String volumeGroupHeatStackId; + private String baseGroupHeatStackId; + private boolean isBase = false; + private String vfModuleStackId; + + + public String getVnfId() { + return vnfId; + } + public void setVnfId(String vnfId) { + this.vnfId = vnfId; + } + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getCloudSiteId() { + return cloudSiteId; + } + public void setCloudSiteId(String cloudId) { + this.cloudSiteId = cloudId; + } + public boolean getTenantCreated() { + return tenantCreated; + } + public void setTenantCreated(boolean tenantCreated) { + this.tenantCreated = tenantCreated; + } + public boolean getVnfCreated() { + return vnfCreated; + } + public void setVnfCreated(boolean vnfCreated) { + this.vnfCreated = vnfCreated; + } + public MsoRequest getMsoRequest() { + return msoRequest; + } + public void setMsoRequest (MsoRequest msoRequest) { + this.msoRequest = msoRequest; + } + public String getVolumeGroupName() { + return this.volumeGroupName; + } + public void setVolumeGroupName(String volumeGroupName) { + this.volumeGroupName = volumeGroupName; + } + public String getVolumeGroupId() { + return this.volumeGroupId; + } + public void setVolumeGroupId(String volumeGroupId) { + this.volumeGroupId = volumeGroupId; + } + public String getRequestType() { + return this.requestType; + } + public void setRequestType(String requestType) { + this.requestType = requestType; + } + /* + private String volumeGroupHeatStackId; + private String baseGroupHeatStackId; + private boolean isBase = false; + */ + public String getVolumeGroupHeatStackId() { + return this.volumeGroupHeatStackId; + } + public void setVolumeGroupHeatStackId(String volumeGroupHeatStackId) { + this.volumeGroupHeatStackId = volumeGroupHeatStackId; + } + + public String getBaseGroupHeatStackId() { + return this.baseGroupHeatStackId; + } + public void setBaseGroupHeatStackId(String baseGroupHeatStackId) { + this.baseGroupHeatStackId = baseGroupHeatStackId; + } + + public boolean isBase() { + return this.isBase; + } + public void setIsBase(boolean isBase) { + this.isBase = isBase; + } + public String getVfModuleStackId() { + return this.vfModuleStackId; + } + public void setVfModuleStackId(String vfModuleStackId) { + this.vfModuleStackId = vfModuleStackId; + } + + @Override + public String toString() { + return "VfRollback: cloud=" + cloudSiteId + ", tenant=" + tenantId + + ", vnf=" + vnfId + ", tenantCreated=" + tenantCreated + + ", vnfCreated=" + vnfCreated + ", requestType = " + requestType + + ", volumeGroupHeatStackId = " + this.volumeGroupHeatStackId; + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VnfAdapterRest.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VnfAdapterRest.java new file mode 100644 index 0000000000..6906f816a7 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VnfAdapterRest.java @@ -0,0 +1,628 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HEAD; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; + +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.openstack.beans.VnfRollback; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; +import org.openecomp.mso.properties.MsoPropertiesFactory; +import org.openecomp.mso.adapters.vnfrest.*; + +/** + * This class services calls to the REST interface for VF Modules (http://host:port/vnfs/rest/v1/vnfs) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + * For testing, call with cloudSiteId = ___TESTING___ + * To test exceptions, also set tenantId = ___TESTING___ + */ +@Path("/v1/vnfs") +public class VnfAdapterRest { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + private static final String TESTING_KEYWORD = "___TESTING___"; + private final CloudConfigFactory cloudConfigFactory = new CloudConfigFactory(); + private final MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + private final MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory, cloudConfigFactory); + //TODO Logging, SkipAAI, CREATED flags, Integrate with BPEL, Auth, + + @HEAD + @GET + @Path("/healthcheck") + @Produces(MediaType.TEXT_HTML) + public Response healthcheck () { + String CHECK_HTML = "<!DOCTYPE html><html><head><meta charset=\"ISO-8859-1\"><title>Health Check</title></head><body>Application ready</body></html>"; + return Response.ok().entity(CHECK_HTML).build(); + } + + /* + * URL:http://localhost:8080/vnfs/rest/v1/vnfs/<aaivnfid>/vf-modules/<aaimodid> + * REQUEST: + * {"deleteVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleStackId": "4e567676-e266-4594-a3a6-131c8a2baf73", + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @DELETE + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response deleteVfModule ( + @PathParam("aaiVnfId") String aaiVnfId, + @PathParam("aaiVfModuleId") String aaiVfModuleId, + final DeleteVfModuleRequest req) + { + LOGGER.debug("Delete VfModule enter: " + req.toJsonString()); + if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) { + LOGGER.debug("Req rejected - aaiVnfId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vnfid in URL does not match content") + .build(); + } + if (aaiVfModuleId == null || !aaiVfModuleId.equals(req.getVfModuleId())) { + LOGGER.debug("Req rejected - aaiVfModuleId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vfModuleId in URL does not match content") + .build(); + } + DeleteVfModuleTask task = new DeleteVfModuleTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling delete, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "deleteVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in deleteVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteVfModuleTask implements Runnable { + private final DeleteVfModuleRequest req; + private DeleteVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public DeleteVfModuleTask(DeleteVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<DeleteVfModuleResponse>(response) {} + : new GenericEntity<VfModuleExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + + @Override + public void run() { + try { + String cloudsite = req.getCloudSiteId(); + if (cloudsite != null && !cloudsite.equals(TESTING_KEYWORD)) { + //vnfAdapter.deleteVnf (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest()); + vnfAdapter.deleteVfModule (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest()); + } + response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE, req.getMessageId()); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - Delete VNF Module", e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Delete vfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + /* + * URL:http://localhost:8080/vnfs/rest/v1/vnfs/<aaiVnfId>/vf-modules/<aaiVfModuleId>?cloudSiteId=DAN&tenantId=vfModule?&skipAAI=TRUE&msoRequest.requestId=ra1&msoRequest.serviceInstanceId=si1&vfModuleName=T2N2S1 + * RESP: + * {"queryVfModuleResponse": { + "vfModuleId": "AvfmodId", + "vfModuleOutputs": {"entry": { + "key": "server_private_ip_1", + "value": "10.100.1.25" + }}, + "vfModuleStackId": "RaaVnf1/abfa8a6d-feb1-40af-aea3-109403b1cf6b", + "vnfId": "AvnfID", + "vnfStatus": "ACTIVE" + }} + */ + @GET + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response queryVfModule( + @PathParam("aaiVnfId") String aaiVnfId, + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @QueryParam("cloudSiteId") String cloudSiteId, + @QueryParam("tenantId") String tenantId, + @QueryParam("vfModuleName") String vfModuleName, //RAA? Id in doc + @QueryParam("skipAAI") Boolean skipAAI, + @QueryParam("msoRequest.requestId") String requestId, + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId) + { + //This request responds synchronously only + LOGGER.debug ("Query vfModule enter:" + vfModuleName); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryVfModuleResponse qryResp = new QueryVfModuleResponse(aaiVnfId, aaiVfModuleId, null, null, null); + Holder<Boolean> vnfExists = new Holder<Boolean>(); + Holder<String> vfModuleId = new Holder<String>(); + Holder<VnfStatus> status = new Holder<VnfStatus>(); + Holder<Map<String, String>> outputs = new Holder <Map <String, String>> (); + vnfAdapter.queryVnf (cloudSiteId, tenantId, vfModuleName, msoRequest, vnfExists, vfModuleId, status, outputs); + if (!vnfExists.value) { + LOGGER.debug ("vfModule not found"); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("vfModule found" + vfModuleId.value + ", status=" + status.value); + qryResp.setVfModuleId(vfModuleId.value); + qryResp.setVnfStatus(status.value); + qryResp.setVfModuleOutputs(outputs.value); + } + LOGGER.debug ("Query vfModule exit"); + return Response + .status(respStatus) + .entity(new GenericEntity<QueryVfModuleResponse>(qryResp) {}) + .build(); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, "", "queryVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - queryVfModule", e); + VfModuleExceptionResponse excResp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity<VfModuleExceptionResponse>(excResp) {}) + .build(); + } + } + + /*URL: http://localhost:8080/vnfs/rest/v1/vnfs/<aaivnfid>/vf-modules + *REQUEST: + * {"createVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleName": "RaaVnf1", + "vnfType": "ApacheVnf", + "vfModuleParams": {"entry": [ + {"key": "network_id", + "value": "59ed7b41-2983-413f-ba93-e7d437433916"}, + {"key": "subnet_id", + "value": "086c9298-5c57-49b7-bb2b-6fd5730c5d92"}, + {"key": "server_name_0", + "value": "RaaVnf1"} + ]}, + "failIfExists": true, + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @POST + @Path("{aaiVnfId}/vf-modules") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response createVfModule( + @PathParam("aaiVnfId") String aaiVnfId, + final CreateVfModuleRequest req) + { + LOGGER.debug("Create VfModule enter inside VnfAdapterRest: " + req.toJsonString()); + if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) { + LOGGER.debug("Req rejected - aaiVnfId not provided or doesn't match URL"); + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("vnfid in URL does not match content") + .build(); + } + CreateVfModuleTask task = new CreateVfModuleTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, "", "createVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - createVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createVfModule exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateVfModuleTask implements Runnable { + private final CreateVfModuleRequest req; + private CreateVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public CreateVfModuleTask(CreateVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<CreateVfModuleResponse>(response) {} + : new GenericEntity<VfModuleExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + + @Override + public void run() { + LOGGER.debug ("CreateVfModuleTask start"); + try { + // Synchronous Web Service Outputs + Holder <String> vfModuleStackId = new Holder <String> (); + Holder <Map <String, String>> outputs = new Holder <Map <String, String>> (); + Holder <VnfRollback> vnfRollback = new Holder <VnfRollback> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("completeVnfVfModuleType=" + completeVnfVfModuleType); + String cloudsite = req.getCloudSiteId(); + if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + vnfRollback.value = new VnfRollback(req.getVnfId(), tenant, cloudsite, + true, false, new MsoRequest("reqid", "svcid"), + req.getVolumeGroupId(), req.getVolumeGroupId(), req.getRequestType()); + vfModuleStackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + outputs.value = VolumeAdapterRest.testMap(); + } else { +// vnfAdapter.createVnf (createReq.getCloudSiteId(), +// createReq.getTenantId(), +// createReq.getVnfType(), +// createReq.getVnfVersion(), +// createReq.getVfModuleName(), +// createReq.getRequestType(), +// createReq.getVolumeGroupStackId(), +// createReq.getVfModuleParams(), +// createReq.getFailIfExists(), +// createReq.getBackout(), +// createReq.getMsoRequest(), +// vfModuleStackId, +// outputs, +// vnfRollback); + vnfAdapter.createVfModule(req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleStackId(), + req.getVfModuleParams(), + req.getFailIfExists(), + req.getBackout(), + req.getMsoRequest(), + vfModuleStackId, + outputs, + vnfRollback); + } + VfModuleRollback modRollback = new VfModuleRollback(vnfRollback.value, req.getVfModuleId(), vfModuleStackId.value, req.getMessageId()); + response = new CreateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), + vfModuleStackId.value, Boolean.TRUE, outputs.value, modRollback, req.getMessageId()); + } catch (VnfException e) { + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateVfModuleTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @PUT + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response updateVfModule( + @PathParam("aaiVnfId") String aaiVnfId, + @PathParam("aaiVfModuleId") String aaiVfModuleId, + final UpdateVfModuleRequest req) + { + LOGGER.debug("Update VfModule enter: " + req.toJsonString()); + UpdateVfModulesTask task = new UpdateVfModulesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, "", "updateVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - updateVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateVfModules exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateVfModulesTask implements Runnable { + private final UpdateVfModuleRequest req; + private UpdateVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public UpdateVfModulesTask(UpdateVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<UpdateVfModuleResponse>(response) {} + : new GenericEntity<VfModuleExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + try { + //MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl (msoPropertiesFactory, cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <String> vfModuleStackId = new Holder <String> (); + Holder <Map <String, String>> outputs = new Holder <Map <String, String>> (); + Holder <VnfRollback> vnfRollback = new Holder <VnfRollback> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVf - completeVnfVfModuleType=" + completeVnfVfModuleType); + + /* + vnfAdapter.updateVnf (updateReq.getCloudSiteId(), + updateReq.getTenantId(), + updateReq.getVnfType(), + updateReq.getVnfVersion(), + updateReq.getVfModuleName(), + updateReq.getRequestType(), + updateReq.getVolumeGroupStackId(), + updateReq.getVfModuleParams(), + updateReq.getMsoRequest(), + outputs, + vnfRollback); + */ + vnfAdapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleId(), + req.getVfModuleStackId(), + req.getVfModuleParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + + response = new UpdateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), + vfModuleStackId.value, outputs.value, req.getMessageId()); + } catch (VnfException e) { + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient (); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Update VfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + /* + * URL:http://localhost:8080/vnfs/rest/v1/vnfs/<aaivnfid>/vf-modules/<aaimodid>/rollback + * REQUEST: + * {"deleteVfModuleRequest": + {"cloudSiteId": "DAN", + "tenantId": "214b428a1f554c02935e66330f6a5409", + "vnfId": "somevnfid", + "vfModuleId": "somemodid", + "vfModuleStackId": "4e567676-e266-4594-a3a6-131c8a2baf73", + "messageId": "ra.1", + "notificationUrl": "http://localhost:8089/vnfmock", + "skipAAI": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + } + */ + @DELETE + @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response rollbackVfModule ( + @PathParam("aaiVnfId") String aaiVnfId, + @PathParam("aaiVfModuleId") String aaiVfModuleId, + //@QueryParam("rollback") String rollback, + final RollbackVfModuleRequest req) + { + LOGGER.debug("Rollback VfModule enter: " + req.toJsonString()); + RollbackVfModulesTask task = new RollbackVfModulesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVfModule", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVfModule", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("rollbackVfModule exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackVfModulesTask implements Runnable { + private final RollbackVfModuleRequest req; + private RollbackVfModuleResponse response = null; + private VfModuleExceptionResponse eresp = null; + private boolean sendxml; + + public RollbackVfModulesTask(RollbackVfModuleRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<RollbackVfModuleResponse>(response) {} + : new GenericEntity<VfModuleExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + try { + VfModuleRollback vmr = req.getVfModuleRollback(); + VnfRollback vrb = new VnfRollback( + vmr.getVfModuleStackId(), vmr.getTenantId(), vmr.getCloudSiteId(), true, true, + vmr.getMsoRequest(), null, null, null); + vnfAdapter.rollbackVnf (vrb); + response = new RollbackVfModuleResponse(Boolean.TRUE, req.getMessageId()); + } catch (VnfException e) { + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVfModule", e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, false, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient (); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("RollbackVfModulesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VolumeAdapterRest.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VolumeAdapterRest.java new file mode 100644 index 0000000000..8fa1552bb0 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/VolumeAdapterRest.java @@ -0,0 +1,576 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf; + + +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; + +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; +import org.openecomp.mso.adapters.vnfrest.CreateVolumeGroupRequest; +import org.openecomp.mso.adapters.vnfrest.CreateVolumeGroupResponse; +import org.openecomp.mso.adapters.vnfrest.DeleteVolumeGroupRequest; +import org.openecomp.mso.adapters.vnfrest.DeleteVolumeGroupResponse; +import org.openecomp.mso.adapters.vnfrest.QueryVolumeGroupResponse; +import org.openecomp.mso.adapters.vnfrest.RollbackVolumeGroupRequest; +import org.openecomp.mso.adapters.vnfrest.RollbackVolumeGroupResponse; +import org.openecomp.mso.adapters.vnfrest.UpdateVolumeGroupRequest; +import org.openecomp.mso.adapters.vnfrest.UpdateVolumeGroupResponse; +import org.openecomp.mso.adapters.vnfrest.VolumeGroupExceptionResponse; +import org.openecomp.mso.adapters.vnfrest.VolumeGroupRollback; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.VnfRollback; +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; +import org.openecomp.mso.properties.MsoPropertiesFactory; + +/** + * This class services calls to the REST interface for VNF Volumes (http://host:port/vnfs/rest/v1/volume-groups) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + * For testing, call with cloudSiteId = ___TESTING___ + * To test exceptions, also set tenantId = ___TESTING___ + */ +@Path("/v1/volume-groups") +public class VolumeAdapterRest { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA); + private static final String TESTING_KEYWORD = "___TESTING___"; + private final CloudConfigFactory cloudConfigFactory = new CloudConfigFactory(); + private final MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + private final MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl(msoPropertiesFactory, cloudConfigFactory); + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response createVNFVolumes(final CreateVolumeGroupRequest req) { + LOGGER.debug("createVNFVolumes enter: " + req.toJsonString()); + CreateVNFVolumesTask task = new CreateVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, "", "createVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - createVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateVNFVolumesTask implements Runnable { + private final CreateVolumeGroupRequest req; + private CreateVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public CreateVNFVolumesTask(CreateVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<CreateVolumeGroupResponse>(response) {} + : new GenericEntity<VolumeGroupExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug ("CreateVFModule VolumesTask start"); + try { + // Synchronous Web Service Outputs + Holder<String> stackId = new Holder<String>(); + Holder<Map<String, String>> outputs = new Holder<Map<String, String>>(); + Holder<VnfRollback> vnfRollback = new Holder<VnfRollback>(); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in createVfModuleVolumes - completeVnfVfModuleType=" + completeVnfVfModuleType); + + String cloudsite = req.getCloudSiteId(); + if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + stackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + outputs.value = testMap(); + } else { +// vnfAdapter.createVnf( +// req.getCloudSiteId(), +// req.getTenantId(), +// req.getVnfType(), +// req.getVnfVersion(), +// req.getVolumeGroupName(), +// "VOLUME", // request type is VOLUME +// null, // not sure about this +// req.getVolumeGroupParams(), +// req.getFailIfExists(), +// req.getSuppressBackout(), +// req.getMsoRequest(), +// stackId, +// outputs, +// vnfRollback); + vnfAdapter.createVfModule( + req.getCloudSiteId(), //cloudSiteId, + req.getTenantId(), //tenantId, + //req.getVnfType(), //vnfType, + completeVnfVfModuleType, + req.getVnfVersion(), //vnfVersion, + req.getVolumeGroupName(), //vnfName, + "VOLUME", //requestType, + null, //volumeGroupHeatStackId, + null, //baseVfHeatStackId, + req.getVolumeGroupParams(), //inputs, + req.getFailIfExists(), //failIfExists, + req.getSuppressBackout(), //backout, + req.getMsoRequest(), // msoRequest, + stackId, + outputs, + vnfRollback); + } + VolumeGroupRollback rb = new VolumeGroupRollback( + req.getVolumeGroupId(), + stackId.value, + true, // TODO boolean volumeGroupCreated, when would it be false? + req.getTenantId(), + req.getCloudSiteId(), + req.getMsoRequest(), + req.getMessageId()); + response = new CreateVolumeGroupResponse( + req.getVolumeGroupId(), + stackId.value, + true, // TODO boolean volumeGroupCreated, when would it be false? + outputs.value, + rb, + req.getMessageId()); + } catch (VnfException e) { + eresp = new VolumeGroupExceptionResponse( + e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateVFModule VolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiVolumeGroupId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response deleteVNFVolumes( + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + final DeleteVolumeGroupRequest req + ) + { + LOGGER.debug("deleteVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || !aaiVolumeGroupId.equals(req.getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + DeleteVNFVolumesTask task = new DeleteVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, "", "deleteVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - deleteVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteVNFVolumesTask implements Runnable { + private final DeleteVolumeGroupRequest req; + private DeleteVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public DeleteVNFVolumesTask(DeleteVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<DeleteVolumeGroupResponse>(response) {} + : new GenericEntity<VolumeGroupExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("DeleteVNFVolumesTask start"); + try { + if (!req.getCloudSiteId().equals(TESTING_KEYWORD)) { + vnfAdapter.deleteVnf(req.getCloudSiteId(), req.getTenantId(), req.getVolumeGroupStackId(), req.getMsoRequest()); + } + response = new DeleteVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiVolumeGroupId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response rollbackVNFVolumes( + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + final RollbackVolumeGroupRequest req + ) + { + LOGGER.debug("rollbackVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || req.getVolumeGroupRollback() == null || !aaiVolumeGroupId.equals(req.getVolumeGroupRollback().getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + RollbackVNFVolumesTask task = new RollbackVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_ROLLBACK_VNF_ERR, "", "rollbackVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - rollbackVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug("rollbackVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackVNFVolumesTask implements Runnable { + private final RollbackVolumeGroupRequest req; + private RollbackVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public RollbackVNFVolumesTask(RollbackVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<RollbackVolumeGroupResponse>(response) {} + : new GenericEntity<VolumeGroupExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("DeleteVNFVolumesTask start"); + try { + VolumeGroupRollback vgr = req.getVolumeGroupRollback(); + VnfRollback vrb = new VnfRollback( + vgr.getVolumeGroupStackId(), vgr.getTenantId(), vgr.getCloudSiteId(), true, true, + vgr.getMsoRequest(), null, null, null); + vnfAdapter.rollbackVnf(vrb); + response = new RollbackVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @PUT + @Path("{aaiVolumeGroupId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response updateVNFVolumes( + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + final UpdateVolumeGroupRequest req + ) + { + LOGGER.debug("updateVNFVolumes enter: " + req.toJsonString()); + if (aaiVolumeGroupId == null || !aaiVolumeGroupId.equals(req.getVolumeGroupId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("VolumeGroupId in URL does not match content") + .build(); + } + UpdateVNFVolumesTask task = new UpdateVNFVolumesTask(req); + if (req.isSynchronous()) { + // This is a synchronous request + task.run(); + return Response + .status(task.getStatusCode()) + .entity(task.getGenericEntityResponse()) + .build(); + } else { + // This is an asynchronous request + try { + Thread t1 = new Thread(task); + t1.start(); + } catch (Exception e) { + // problem handling create, send generic failure as sync resp to caller + LOGGER.error (MessageEnum.RA_UPDATE_VNF_ERR, "", "updateVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - updateVNFVolumes", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateVNFVolumes exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateVNFVolumesTask implements Runnable { + private final UpdateVolumeGroupRequest req; + private UpdateVolumeGroupResponse response = null; + private VolumeGroupExceptionResponse eresp = null; + private boolean sendxml; + + public UpdateVNFVolumesTask(UpdateVolumeGroupRequest req) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + } + public int getStatusCode() { + return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; + } + public Object getGenericEntityResponse() { + return (response != null) + ? new GenericEntity<UpdateVolumeGroupResponse>(response) {} + : new GenericEntity<VolumeGroupExceptionResponse>(eresp) {}; + } + private String getResponse() { + if (response != null) { + return sendxml ? response.toXmlString() : response.toJsonString(); + } else { + return sendxml ? eresp.toXmlString() : eresp.toJsonString(); + } + } + @Override + public void run() { + LOGGER.debug("UpdateVNFVolumesTask start"); + try { + @SuppressWarnings("unused") + Holder<String> stackId = new Holder<String> (); + Holder<Map<String, String>> outputs = new Holder<Map <String, String>> (); + Holder<VnfRollback> vnfRollback = new Holder<VnfRollback> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVfModuleVolume - completeVnfVfModuleType=" + completeVnfVfModuleType); + + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + outputs.value = testMap(); + } else { + //vnfAdapter.updateVnf( + // req.getCloudSiteId(), + // req.getTenantId(), + // req.getVnfType(), + // req.getVnfVersion(), + // req.getVfModuleType(), + // "VOLUME", // request type is VOLUME + // req.getVolumeGroupStackId(), + // req.getVolumeGroupParams(), + // req.getMsoRequest(), + // outputs, + // vnfRollback); + vnfAdapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVolumeGroupStackId(), + "VOLUME", + null, + null, + req.getVolumeGroupStackId(), + req.getVolumeGroupParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + } + response = new UpdateVolumeGroupResponse( + req.getVolumeGroupId(), req.getVolumeGroupStackId(), + outputs.value, req.getMessageId()); + } catch (VnfException e) { + eresp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiVolumeGroupId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response queryVNFVolumes( + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @QueryParam("cloudSiteId") String cloudSiteId, + @QueryParam("tenantId") String tenantId, + @QueryParam("volumeGroupStackId") String volumeGroupStackId, + @QueryParam("skipAAI") Boolean skipAAI, + @QueryParam("msoRequest.requestId") String requestId, + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId + ) + { + //This request responds synchronously only + LOGGER.debug ("queryVNFVolumes enter:" + aaiVolumeGroupId + " " + volumeGroupStackId); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryVolumeGroupResponse qryResp = new QueryVolumeGroupResponse(aaiVolumeGroupId, volumeGroupStackId, null, null); + Holder<Boolean> vnfExists = new Holder<Boolean>(); + Holder<String> vfModuleId = new Holder<String>(); + Holder<VnfStatus> status = new Holder<VnfStatus>(); + Holder<Map<String, String>> outputs = new Holder<Map<String, String>>(); + if (cloudSiteId != null && cloudSiteId.equals(TESTING_KEYWORD)) { + if (tenantId != null && tenantId.equals(TESTING_KEYWORD)) { + throw new VnfException("testing."); + } + vnfExists.value = true; + vfModuleId.value = TESTING_KEYWORD; + status.value = VnfStatus.ACTIVE; + outputs.value = testMap(); + } else { + vnfAdapter.queryVnf(cloudSiteId, tenantId, volumeGroupStackId, msoRequest, vnfExists, vfModuleId, status, outputs); + } + if (!vnfExists.value) { + LOGGER.debug ("VNFVolumes not found"); + qryResp.setVolumeGroupStatus(status.value); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("VNFVolumes found " + vfModuleId.value + ", status=" + status.value); + qryResp.setVolumeGroupStatus(status.value); + qryResp.setVolumeGroupOutputs(outputs.value); + } + LOGGER.debug("Query queryVNFVolumes exit"); + return Response + .status(respStatus) + .entity(new GenericEntity<QueryVolumeGroupResponse>(qryResp) {}) + .build(); + } catch (VnfException e) { + LOGGER.error(MessageEnum.RA_QUERY_VNF_ERR, aaiVolumeGroupId, "", "queryVNFVolumes", MsoLogger.ErrorCode.BusinessProcesssError, "VnfException - queryVNFVolumes", e); + VolumeGroupExceptionResponse excResp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); + LOGGER.debug("Query queryVNFVolumes exit"); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity<VolumeGroupExceptionResponse>(excResp) {}) + .build(); + } + } + public static Map<String, String> testMap() { + Map<String, String> m = new HashMap<String, String>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfAlreadyExists.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfAlreadyExists.java new file mode 100644 index 0000000000..7cec0cd99e --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfAlreadyExists.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.exceptions; + + + +import javax.xml.ws.WebFault; + +/** + * This class reports an exception when trying to create a VNF when another + * VNF of the same name already exists in the target cloud/tenant. Note that + * the createVnf method suppresses this exception by default. + * + * + */ +@WebFault (name="VnfAlreadyExists", faultBean="org.openecomp.mso.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://com.att.mso/vnf") +public class VnfAlreadyExists extends VnfException { + + private static final long serialVersionUID = 1L; + + public VnfAlreadyExists (String name, String cloudId, String tenantId, String vnfId) { + super("VNF " + name + " already exists in cloud/tenant " + cloudId + "/" + tenantId + " with ID " + vnfId); + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfException.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfException.java new file mode 100644 index 0000000000..ceef76b468 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfException.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.openecomp.mso.openstack.exceptions.MsoException; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; + +/** + * This class simply extends Exception (without addition additional functionality) + * to provide an identifier for VNF related exceptions on create, delete, query. + * + * + */ +@WebFault (name="VnfException", faultBean="org.openecomp.mso.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://com.att.mso/vnf") +public class VnfException extends Exception { + + private static final long serialVersionUID = 1L; + + private VnfExceptionBean faultInfo; + + public VnfException (String msg) { + super(msg); + faultInfo = new VnfExceptionBean (msg); + } + + public VnfException (Throwable e) { + super(e); + faultInfo = new VnfExceptionBean (e.getMessage()); + } + + public VnfException (String msg, Throwable e) { + super (msg, e); + faultInfo = new VnfExceptionBean (msg); + } + + public VnfException (String msg, MsoExceptionCategory category) { + super(msg); + faultInfo = new VnfExceptionBean (msg, category); + } + + public VnfException (String msg, MsoExceptionCategory category, Throwable e) { + super (msg, e); + faultInfo = new VnfExceptionBean (msg, category); + } + + public VnfException (MsoException e) { + super (e); + faultInfo = new VnfExceptionBean (e.getContextMessage(), e.getCategory()); + } + + public VnfExceptionBean getFaultInfo() { + return faultInfo; + } + + public void setFaultInfo(VnfExceptionBean faultInfo) { + this.faultInfo = faultInfo; + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfExceptionBean.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfExceptionBean.java new file mode 100644 index 0000000000..15918eabb8 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfExceptionBean.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.exceptions; + + +import java.io.Serializable; + +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; + +/** + * Jax-WS Fault Bean for Vnf Exception + */ +public class VnfExceptionBean implements Serializable { + + private static final long serialVersionUID = -5699310749783790095L; + + private String message; + private MsoExceptionCategory category; + private Boolean rolledBack; + + public VnfExceptionBean () {} + + public VnfExceptionBean (String message) { + this.message = message; + } + + public VnfExceptionBean (String message, MsoExceptionCategory category) { + this.message = message; + this.category = category; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public MsoExceptionCategory getCategory () { + return category; + } + + public void setCategory (MsoExceptionCategory category) { + this.category = category; + } + + public Boolean isRolledBack() { + return rolledBack; + } + + public void setRolledBack(Boolean rolledBack) { + this.rolledBack = rolledBack; + } +} diff --git a/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfNotFound.java b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfNotFound.java new file mode 100644 index 0000000000..3c27d03daa --- /dev/null +++ b/adapters/mso-vnf-adapter/src/main/java/org/openecomp/mso/adapters/vnf/exceptions/VnfNotFound.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.exceptions; + + +import javax.xml.ws.WebFault; + +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; + +/** + * This class reports an exception when trying to update a Network that does + * not exist in the target cloud/tenant. Note that deleteNetwork suppresses + * this exception (deletion of non-existent network is considered a success). + * + * + */ +@WebFault (name="VnfNotFound", faultBean="org.openecomp.mso.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://com.att.mso/vnf") +public class VnfNotFound extends VnfException { + + private static final long serialVersionUID = 1L; + + public VnfNotFound (String cloudId, String tenantId, String vnfName) { + super("VNF " + vnfName + " not found in cloud/tenant " + cloudId + "/" + tenantId); + } +} diff --git a/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/QueryTest.java b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/QueryTest.java new file mode 100644 index 0000000000..96e50d0959 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/QueryTest.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.test; + + +import java.util.Map; + +import javax.xml.ws.Holder; + +import org.openecomp.mso.adapters.vnf.MsoVnfAdapter; +import org.openecomp.mso.adapters.vnf.MsoVnfAdapterImpl; +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; + +public class QueryTest { + public final static void main (String args[]) + { + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl(); + log ("Got a VnfAdapter"); + + String cloudId = "MT"; + String tenantId = "MSO_Test"; + String vnfName = "VNF_TEST1"; + Holder<Boolean> vnfExists = new Holder<Boolean>(); + Holder<String> vnfId = new Holder<String>(); + Holder<VnfStatus> status = new Holder<VnfStatus>(); + Holder<Map<String,String>> outputs = new Holder<Map<String,String>>(); + + try { + vnfAdapter.queryVnf(cloudId, tenantId, vnfName, null, + vnfExists, vnfId, status, outputs); + } catch (VnfException e) { + log ("Got an Exception: " + e); + } + + if (! vnfExists.value){ + log ("VNF Not Found"); + } else { + log ("Found VNF, ID = " + vnfId.value + ", status=" + status.value); + } + } + + private static void log (String msg) { + System.out.println (msg); + } +} diff --git a/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfCreateTest.java b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfCreateTest.java new file mode 100644 index 0000000000..02691726d8 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfCreateTest.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.test; + + +import java.util.HashMap; +import java.util.Map; + +import javax.xml.ws.Holder; + +import org.openecomp.mso.adapters.vnf.MsoVnfAdapter; +import org.openecomp.mso.adapters.vnf.MsoVnfAdapterImpl; +import org.openecomp.mso.openstack.beans.VnfRollback; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; + +public class VnfCreateTest { + public final static void main (String args[]) + { + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl(); + log ("Got a VnfAdapter"); + + // Web Service Inputs + String cloudId = "MT"; + String tenantName = "John_Test"; + String vnfType = "ApacheDemo"; + String vnfName = "AdapterTest"; + Map<String,String> inputs = new HashMap<String,String>(); + inputs.put("vnf_id", "abc"); + inputs.put("extra", "whocares"); + inputs.put("private_subnet_gateway", "10.4.1.1"); + inputs.put("private_subnet_cidr", "10.4.1.0/29"); + + // Web Service Outputs + Holder<String> vnfId = new Holder<String>(); + Holder<Map<String,String>> outputs = new Holder<Map<String,String>>(); + Holder<VnfRollback> vnfRollback = new Holder<VnfRollback>(); + + try { + vnfAdapter.createVnf(cloudId, tenantName, vnfType,null, vnfName, null, null, inputs, false, true, null, + vnfId, outputs, vnfRollback); + } catch (VnfException e) { + log ("Got a Create Exception: " + e); + System.exit(1); + } + + log ("Created VNF, ID = " + vnfId.value); + for (String key : outputs.value.keySet()) { + log (" " + key + " = " + outputs.value.get(key)); + } + if (vnfRollback.value != null) + log (vnfRollback.value.toString()); + + try { + Thread.sleep(5000); + } catch (InterruptedException e) {} + + log ("Rolling Back VNF"); + try { + vnfAdapter.rollbackVnf(vnfRollback.value); + } catch (VnfException e) { + log ("Got a Rollback Exception: " + e); + } + log ("VNF Rolled Back"); + } + + private static void log (String msg) { + System.out.println (msg); + } +} diff --git a/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfDeleteTest.java b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfDeleteTest.java new file mode 100644 index 0000000000..0c35da7f64 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfDeleteTest.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.test; + + + +import org.openecomp.mso.adapters.vnf.MsoVnfAdapter; +import org.openecomp.mso.adapters.vnf.MsoVnfAdapterImpl; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; + +public class VnfDeleteTest { + public final static void main (String args[]) + { + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl(); + log ("Got a VnfAdapter"); + + // Web Service Inputs + String cloudId = "MT"; + String tenantName = "MSO_Test"; + String vnfName = "AdapterTest"; + + try { + vnfAdapter.deleteVnf(cloudId, tenantName, vnfName, null); + } catch (VnfException e) { + log ("Got an Exception: " + e); + } + + log ("Deleted VNF"); + } + + private static void log (String msg) { + System.out.println (msg); + } +} diff --git a/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfQueryTest.java b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfQueryTest.java new file mode 100644 index 0000000000..923c222f60 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/test/java/org/openecomp/mso/adapters/vnf/test/VnfQueryTest.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.vnf.test; + + +import java.util.Map; + +import javax.xml.ws.Holder; + +import org.openecomp.mso.adapters.vnf.MsoVnfAdapter; +import org.openecomp.mso.adapters.vnf.MsoVnfAdapterImpl; +import org.openecomp.mso.openstack.beans.VnfStatus; +import org.openecomp.mso.adapters.vnf.exceptions.VnfException; + +public class VnfQueryTest { + public final static void main (String args[]) + { + MsoVnfAdapter vnfAdapter = new MsoVnfAdapterImpl(); + log ("Got a VnfAdapter"); + + String cloudId = "MT"; + String tenantId = "MSO_Test"; + String vnfName = "VNF_TEST1"; + Holder<Boolean> vnfExists = new Holder<Boolean>(); + Holder<String> vnfId = new Holder<String>(); + Holder<VnfStatus> status = new Holder<VnfStatus>(); + Holder<Map<String,String>> outputs = new Holder<Map<String,String>>(); + + try { + vnfAdapter.queryVnf(cloudId, tenantId, vnfName, null, + vnfExists, vnfId, status, outputs); + } catch (VnfException e) { + log ("Got an Exception: " + e); + } + + if (! vnfExists.value){ + log ("VNF Not Found"); + } else { + log ("Found VNF, ID = " + vnfId.value + ", status=" + status.value); + } + } + + private static void log (String msg) { + System.out.println (msg); + } +} diff --git a/adapters/mso-vnf-adapter/src/test/resources/META-INF/services/com.woorea.openstack.base.client.OpenStackClientConnector b/adapters/mso-vnf-adapter/src/test/resources/META-INF/services/com.woorea.openstack.base.client.OpenStackClientConnector new file mode 100644 index 0000000000..1281d32948 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/test/resources/META-INF/services/com.woorea.openstack.base.client.OpenStackClientConnector @@ -0,0 +1 @@ +com.woorea.openstack.connector.HttpClientConnector
\ No newline at end of file diff --git a/adapters/mso-vnf-adapter/src/test/resources/logback-test.xml b/adapters/mso-vnf-adapter/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..238980e0c4 --- /dev/null +++ b/adapters/mso-vnf-adapter/src/test/resources/logback-test.xml @@ -0,0 +1,48 @@ +<!-- + ============LICENSE_START======================================================= + ECOMP MSO + ================================================================================ + Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<configuration > + + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{MM/dd-HH:mm:ss.SSS}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}||%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}||%X{Timer}|%msg%n</pattern> + </encoder> + </appender> + + + <logger name="com.att.eelf.audit" level="info" additivity="false"> + <appender-ref ref="STDOUT" /> + </logger> + + <logger name="com.att.eelf.metrics" level="info" additivity="false"> + <appender-ref ref="STDOUT" /> + </logger> + + <logger name="com.att.eelf.error" level="trace" additivity="false"> + <appender-ref ref="STDOUT" /> + </logger> + + <root level="info"> + <appender-ref ref="STDOUT" /> + </root> + + +</configuration> |