diff options
author | Benjamin, Max (mb388a) <mb388a@us.att.com> | 2018-07-30 15:56:09 -0400 |
---|---|---|
committer | Benjamin, Max (mb388a) <mb388a@us.att.com> | 2018-07-31 11:09:25 -0400 |
commit | 5a6a6de6f1a26a1897e4917a0df613e25a24eb70 (patch) | |
tree | 59a968f27b4b603aacc9d5e7b51fb598aeec5321 /adapters/mso-openstack-adapters/src/main/java | |
parent | b6dc38501f3b746426b42d9de4cc883d894149e8 (diff) |
Containerization feature of SO
Change-Id: I95381232eeefcd247a66a5cec370a8ce1c288e18
Issue-ID: SO-670
Signed-off-by: Benjamin, Max (mb388a) <mb388a@us.att.com>
Diffstat (limited to 'adapters/mso-openstack-adapters/src/main/java')
92 files changed, 23060 insertions, 0 deletions
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/BpelRestClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/BpelRestClient.java new file mode 100644 index 0000000000..cf11ab94c1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/BpelRestClient.java @@ -0,0 +1,298 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.network; + + +import java.security.GeneralSecurityException; +import java.util.Set; +import java.util.TreeSet; + +import javax.annotation.PostConstruct; +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.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * 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.onap.so.adapters.vnf.bpelauth encrypted authorization string to send to BEPL engine + * org.onap.so.adapters.vnf.sockettimeout socket timeout value + * org.onap.so.adapters.vnf.connecttimeout connect timeout value + * org.onap.so.adapters.vnf.retrycount number of times to retry failed connections + * org.onap.so.adapters.vnf.retryinterval interval (in seconds) between retries + * org.onap.so.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code + * 900 means "connection was not established") + */ +@Component("NetworkBpel") +@Scope("prototype") +public class BpelRestClient { + public static final String MSO_PROP_NETWORK_ADAPTER = "MSO_PROP_NETWORK_ADAPTER"; + private static final String PROPERTY_DOMAIN = "org.onap.so.adapters.network"; + 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, BpelRestClient.class); + + @Autowired + private Environment env; + /** 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_NETWORK_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 = ""; + + } + + @PostConstruct + protected void init() { + + socketTimeout = env.getProperty(SOCKET_TIMEOUT_PROPERTY, Integer.class, DEFAULT_SOCKET_TIMEOUT); + connectTimeout = env.getProperty(CONN_TIMEOUT_PROPERTY, Integer.class, DEFAULT_CONNECT_TIMEOUT); + retryCount = env.getProperty(RETRY_COUNT_PROPERTY, Integer.class, DEFAULT_RETRY_COUNT); + retryInterval = env.getProperty(RETRY_INTERVAL_PROPERTY, Integer.class, DEFAULT_RETRY_INTERVAL); + setRetryList(env.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST)); + credentials = getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY); + } + + 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) { + int retCnt = 0; + if (retryCount < 0) + retCnt = DEFAULT_RETRY_COUNT; + this.retryCount = retCnt; + } + + 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.isEmpty()) + return ""; + String t = retryList.toString(); + return t.substring(1, t.length()-1); + } + + public void setRetryList(String retryList) { + Set<Integer> s = new TreeSet<>(); + for (String t : retryList.split("[, ]")) { + try { + s.add(Integer.parseInt(t)); + } catch (NumberFormatException x) { + LOGGER.debug("Exception while parsing", x); + } + } + 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.DataError, "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) { + LOGGER.debug("Exception while Thread sleep", e); + Thread.currentThread().interrupt(); + } + } + } + private void debug(String m) { + LOGGER.debug(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.AvailabilityError, "Exception sending Bpel notification", e); + lastResponseCode = 900; + lastResponse = ""; + } + LOGGER.debug("Response code from BPEL server: "+lastResponseCode); + LOGGER.debug("Response body is: "+lastResponse); + } + + private String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + if (env.getProperty(key) != null) { + try { + return CryptoUtils.decrypt(env.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + env.getProperty(key), e); + } + } + return defaultValue; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRef.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRef.java new file mode 100644 index 0000000000..46fb651afe --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRef.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ContrailPolicyRef { + private static final MsoLogger logger = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, ContrailPolicyRef.class); + + @JsonProperty("network_policy_refs_data_sequence") + private ContrailPolicyRefSeq seq; + + public JsonNode toJsonNode() + { + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(this, JsonNode.class); + } + catch (Exception e) + { + logger.error (MessageEnum.RA_MARSHING_ERROR, "Error creating JsonString for Contrail Policy Ref", "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Policy Ref", e); + } + + return node; + } + + public String toJsonString() + { + String jsonString = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + jsonString = mapper.writeValueAsString(this); + } + catch (Exception e) + { + logger.error (MessageEnum.RA_MARSHING_ERROR, "Error creating JsonString for Contrail Policy Ref", "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Policy Ref", e); + } + + return jsonString; + } + + public void populate(String major, String minor) + { + seq = new ContrailPolicyRefSeq(major, minor); + return; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRefSeq.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRefSeq.java new file mode 100644 index 0000000000..17d4a743dc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailPolicyRefSeq.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ContrailPolicyRefSeq { + + @JsonProperty("network_policy_refs_data_sequence_major") + private String major; + + @JsonProperty("network_policy_refs_data_sequence_minor") + private String minor; + + public ContrailPolicyRefSeq() { + /* To be done */ + } + + public ContrailPolicyRefSeq(String major, String minor) { + super(); + this.major = major; + this.minor = minor; + } + + public String getMajor() { + return major; + } + + public void setMajor(String major) { + this.major = major; + } + + public String getMinor() { + return minor; + } + + public void setMinor(String minor) { + this.minor = minor; + } + + @Override + public String toString() { + return "ContrailPolicyRefSeq [major=" + major + ", minor=" + minor + + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnet.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnet.java new file mode 100644 index 0000000000..019963b242 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnet.java @@ -0,0 +1,214 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.HostRoute; +import org.onap.so.openstack.beans.Pool; +import org.onap.so.openstack.beans.Subnet; +import org.onap.so.openstack.utils.MsoCommonUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ContrailSubnet { + private static final MsoLogger logger = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, ContrailSubnet.class); + @Autowired + private MsoCommonUtils msoCommonUtils; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet") + private ContrailSubnetIp subnet = new ContrailSubnetIp(); + + @JsonProperty("network_ipam_refs_data_ipam_subnets_default_gateway") + private String defaultGateway; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_name") + private String subnetName; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_enable_dhcp") + private Boolean enableDhcp; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_addr_from_start") + private Boolean addrFromStart = true; + /** future - leave this commented + private String subnet_uuid; + private String dns_server_address; + private List<String> dns_nameservers; + private String dhcp_option_list; + **/ + + @JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools") + private List<ContrailSubnetPool> allocationPools = new ArrayList <> (); + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes") + private final ContrailSubnetHostRoutes host_routes = new ContrailSubnetHostRoutes(); + + public ContrailSubnet() { + super(); + } + + public String getDefaultGateway() { + return defaultGateway; + } + + public void setDefaultGateway(String defaultGateway) { + this.defaultGateway = defaultGateway; + } + + public ContrailSubnetIp getSubnet() { + return subnet; + } + + public void setSubnet(ContrailSubnetIp subnet) { + this.subnet = subnet; + } + + public Boolean isEnableDhcp() { + return enableDhcp; + } + + public void setEnableDhcp(Boolean enableDhcp) { + this.enableDhcp = enableDhcp; + } + + public String getSubnetName() { + return subnetName; + } + + public void setSubnetName(String subnetName) { + this.subnetName = subnetName; + } + + public List<ContrailSubnetPool> getAllocationPools() { + return allocationPools; + } + + public void setPools(List<ContrailSubnetPool> allocationPools) { + this.allocationPools = allocationPools; + } + + public Boolean isAddrFromStart() { + return addrFromStart; + } + + public void setAddrFromStart(Boolean addrFromStart) { + this.addrFromStart = addrFromStart; + } + + public JsonNode toJsonNode() + { + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(this, JsonNode.class); + } + catch (Exception e) + { + String error = "Error creating JsonNode for Contrail Subnet:" + subnetName; + logger.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonNode for Contrail Subnet", e); + } + + return node; + } + + public String toJsonString() + { + String jsonString = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + jsonString = mapper.writeValueAsString(this); + } + catch (Exception e) + { + String error = "Error creating JsonString for Contrail Subnet:" + subnetName; + logger.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Subnet", e); + } + + return jsonString; + } + //poulate contrail subnet with input(from bopel) subnet + public void populateWith(Subnet inputSubnet) + { + if (inputSubnet != null) + { + if (!msoCommonUtils.isNullOrEmpty(inputSubnet.getSubnetName())) + subnetName = inputSubnet.getSubnetName(); + else + subnetName = inputSubnet.getSubnetId(); + enableDhcp = inputSubnet.getEnableDHCP(); + defaultGateway = inputSubnet.getGatewayIp(); + if (!msoCommonUtils.isNullOrEmpty(inputSubnet.getCidr()) ) + { + int idx = inputSubnet.getCidr().indexOf("/"); + if (idx != -1) + { + subnet.setIpPrefix(inputSubnet.getCidr().substring(0, idx)); + subnet.setIpPrefixLen(inputSubnet.getCidr().substring(idx+1)); + } + } + if (inputSubnet.getAllocationPools() != null) + { + for (Pool pool : inputSubnet.getAllocationPools()) + { + if ( !msoCommonUtils.isNullOrEmpty(pool.getStart()) && !msoCommonUtils.isNullOrEmpty(pool.getEnd()) ) + { + ContrailSubnetPool csp = new ContrailSubnetPool(); + csp.populateWith(pool); + allocationPools.add (csp); + } + } + } + if (inputSubnet.getHostRoutes() != null) + { + List<ContrailSubnetHostRoute> hrList = host_routes.getHost_routes(); + for (HostRoute hr : inputSubnet.getHostRoutes()) + { + if ( !msoCommonUtils.isNullOrEmpty(hr.getPrefix()) || !msoCommonUtils.isNullOrEmpty(hr.getNextHop()) ) + { + ContrailSubnetHostRoute cshr = new ContrailSubnetHostRoute(); + cshr.populateWith(hr); + hrList.add (cshr); + } + } + } + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder (); + for (ContrailSubnetPool pool : allocationPools) + { + buf.append(pool.toString()); + } + return "ContrailSubnet [subnet=" + subnet.toString() + " default_gateway=" + defaultGateway + + " enable_dhcp=" + enableDhcp + " addr_from_start=" + addrFromStart + " subnet_name=" + subnetName + " allocation_pools=" + buf + " ]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoute.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoute.java new file mode 100644 index 0000000000..d938306c48 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoute.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import org.onap.so.openstack.beans.HostRoute; +import com.fasterxml.jackson.annotation.JsonProperty; +public class ContrailSubnetHostRoute { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes_route_prefix") + private String prefix; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes_route_next_hop") + private String nextHop; + + public ContrailSubnetHostRoute() { + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getNextHop() { + return nextHop; + } + + public void setNextHop(String nextHop) { + this.nextHop = nextHop; + } + + public void populateWith(HostRoute hostRoute) + { + if (hostRoute != null) + { + prefix = hostRoute.getPrefix(); + nextHop = hostRoute.getNextHop(); + } + } + + @Override + public String toString() { + return "ContrailSubnetHostRoute [prefix=" + prefix + ", nextHop=" + nextHop + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoutes.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoutes.java new file mode 100644 index 0000000000..9b07e20267 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetHostRoutes.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import org.onap.so.openstack.beans.HostRoute; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +public class ContrailSubnetHostRoutes { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_host_routes_route") + private List<ContrailSubnetHostRoute> host_routes = new ArrayList <ContrailSubnetHostRoute> (); + + public ContrailSubnetHostRoutes() { + } + + public List<ContrailSubnetHostRoute> getHost_routes() { + return host_routes; + } + + public void setHost_routes(List<ContrailSubnetHostRoute> host_routes) { + this.host_routes = host_routes; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder (); + if (host_routes != null) + { + for (ContrailSubnetHostRoute hr : host_routes) + { + buf.append(hr.toString()); + } + } + return "ContrailSubnetHostRoutes [" + buf.toString() + "]"; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetIp.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetIp.java new file mode 100644 index 0000000000..91d089eb33 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetIp.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ContrailSubnetIp { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix") + private String ipPrefix; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix_len") + private String ipPrefixLen; + + public ContrailSubnetIp() { + /* Empty constructor */ + } + + public String getIpPrefix() { + return ipPrefix; + } + + public void setIpPrefix(String ipPrefix) { + this.ipPrefix = ipPrefix; + } + + public String getIpPrefixLen() { + return ipPrefixLen; + } + + public void setIpPrefixLen(String ipPrefixLen) { + this.ipPrefixLen = ipPrefixLen; + } + + @Override + public String toString() { + return "ContrailSubnetIp [ip_prefix=" + ipPrefix + ", ip_prefix_len=" + ipPrefixLen + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetPool.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetPool.java new file mode 100644 index 0000000000..710d0cc8fd --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/ContrailSubnetPool.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import org.onap.so.openstack.beans.Pool; +import com.fasterxml.jackson.annotation.JsonProperty; +public class ContrailSubnetPool { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools_start") + private String start; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools_end") + private String end; + + public ContrailSubnetPool() { + /* Empty constructor */ + } + + public String getStart() { + return start; + } + + public void setStart(String start) { + this.start = start; + } + + public String getEnd() { + return end; + } + + public void setEnd(String end) { + this.end = end; + } + + public void populateWith(Pool pool) + { + if (pool != null) + { + start = pool.getStart(); + end = pool.getEnd(); + } + } + + @Override + public String toString() { + return "ContrailSubnetPool [start=" + start + ", end=" + end + "]"; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapter.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapter.java new file mode 100644 index 0000000000..27829a6156 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapter.java @@ -0,0 +1,222 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import java.util.List; +import java.util.Map; + +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.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.RouteTarget; +import org.onap.so.openstack.beans.Subnet; + +@WebService (name="NetworkAdapter", targetNamespace="http://org.onap.so/network") +public interface MsoNetworkAdapter +{ + // TODO: Rename all of these to include Vlan in the service name? At least for the + // create and update calls, since they are specific to VLAN-based provider networks. + + /** + * This is the "Create Network" Web Service Endpoint definition. + */ + @WebMethod + public void createNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") String physicalNetworkName, + @WebParam(name="vlans") List<Integer> vlans, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="subnets") List<Subnet> subnets, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback ) + throws NetworkException; + + @WebMethod + public void createNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="routeTargets") List<RouteTarget> routeTargets, + @WebParam(name="shared") String shared, + @WebParam(name="external") String external, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="subnets") List<Subnet> subnets, + @WebParam(name="policyFqdns") List<String> policyFqdns, + @WebParam(name="routeTableFqdns") List<String> routeTableFqdns, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId, + @WebParam(name="networkFqdn", mode=Mode.OUT) Holder<String> networkFqdn, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback ) + throws NetworkException; + + /** + * This is the "Update VLANs" Web Service Endpoint definition. + * This webservice replaces the set of VLANs on a network. + */ + @WebMethod + public void updateNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlans") @XmlElement(required=true) List<Integer> vlans, + @WebParam(name="subnets") List<Subnet> subnets, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback ) + throws NetworkException; + + @WebMethod + public void updateNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="routeTargets") List<RouteTarget> routeTargets, + @WebParam(name="shared") String shared, + @WebParam(name="external") String external, + @WebParam(name="subnets") List<Subnet> subnets, + @WebParam(name="policyFqdns") List<String> policyFqdns, + @WebParam(name="routeTableFqdns") List<String> routeTableFqdns, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap, + @WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback ) + throws NetworkException; + + /** + * TODO: + * This is the "Add VLAN" Web Service Endpoint definition. + * This webservice adds a VLAN to a network. + * This service assumes that PO supports querying the current vlans in real time. + * Otherwise, the caller must have the complete list and should use updateVlans instead. + @WebMethod + public void addVlan (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlan") @XmlElement(required=true) Integer vlan, + @WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback ) + throws NetworkException; + */ + + /** + * TODO: + * This is the "Remove VLAN" Web Service Endpoint definition. + * This webservice removes a VLAN from a network. + * This service assumes that PO supports querying the current vlans in real time. + * Otherwise, the caller must have the complete list and should use updateVlans instead. + * + * This service returns an indicator (noMoreVLans) if the VLAN that was removed was + * the last one on the network. + * + * It is not clear that Rollback will work for delete. The network can be + * recreated from the NetworkRollback object, but the network ID (and stack ID + * for Heat-based orchestration) will be different. The caller will need to know + * to update these identifiers in the inventory DB (A&AI). + @WebMethod + public void removeVlan (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlan") @XmlElement(required=true) Integer vlan, + @WebParam(name="noMoreVlans", mode=Mode.OUT) Holder<Boolean> noMoreVlans, + @WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback ) + throws NetworkException; + */ + + /** + * This is the "Query Network" Web Service Endpoint definition. + * TODO: Should this just return the NetworkInfo complete structure? + */ + @WebMethod + public void queryNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkExists", mode=Mode.OUT) Holder<Boolean> networkExists, + @WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId, + @WebParam(name="status", mode=Mode.OUT) Holder<NetworkStatus> status, + @WebParam(name="vlans", mode=Mode.OUT) Holder<List<Integer>> vlans, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap) + throws NetworkException; + + @WebMethod + public void queryNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkExists", mode=Mode.OUT) Holder<Boolean> networkExists, + @WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId, + @WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId, + @WebParam(name="status", mode=Mode.OUT) Holder<NetworkStatus> status, + @WebParam(name="routeTargets", mode=Mode.OUT) Holder<List<RouteTarget>> routeTargets, + @WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap) + throws NetworkException; + + /** + * This is the "Delete Network" Web Service endpoint definition. + */ + @WebMethod + public void deleteNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="networkDeleted", mode=Mode.OUT) Holder<Boolean> networkDeleted) + throws NetworkException; + + /** + * This is the "Rollback Network" Web Service endpoint definition. + */ + @WebMethod + public void rollbackNetwork (@WebParam(name="rollback") @XmlElement(required=true) NetworkRollback rollback) + throws NetworkException; + + @WebMethod + public void healthCheck (); +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsync.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsync.java new file mode 100644 index 0000000000..99f590b773 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsync.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network; + + +import java.util.List; + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; + +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.Subnet; +/** + * This webservice defines the Asynchronous versions of NETWORK adapter calls. + * The notification messages for final responses are documented elsewhere + * (by the client service WSDL). + * + */ +@WebService (name="NetworkAdapterAsync", targetNamespace="http://org.onap.so/networkA") +public interface MsoNetworkAdapterAsync +{ + /** + * This is the "Create NETWORK" Web Service Endpoint definition. + */ + @WebMethod + @Oneway + public void createNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") String physicalNetworkName, + @WebParam(name="vlans") List<Integer> vlans, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="subnets") List<Subnet> subnets, + @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 updateNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName, + @WebParam(name="vlans") @XmlElement(required=true) List<Integer> vlans, + @WebParam(name="subnets") List<Subnet> subnets, + @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 queryNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId, + @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 deleteNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="networkType") @XmlElement(required=true) String networkType, + @WebParam(name="modelCustomizationUuid") String modelCustomizationUuid, + @WebParam(name="networkId") @XmlElement(required=true) String networkId, + @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 rollbackNetworkA (@WebParam(name="rollback") @XmlElement(required=true) NetworkRollback 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-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsyncImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsyncImpl.java new file mode 100644 index 0000000000..b483d40b8a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterAsyncImpl.java @@ -0,0 +1,698 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.network; + + +import java.net.MalformedURLException; +import java.net.URL; +import java.security.GeneralSecurityException; +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.onap.so.adapters.network.async.client.CreateNetworkNotification; +import org.onap.so.adapters.network.async.client.MsoExceptionCategory; +import org.onap.so.adapters.network.async.client.NetworkAdapterNotify; +import org.onap.so.adapters.network.async.client.NetworkAdapterNotify_Service; +import org.onap.so.adapters.network.async.client.QueryNetworkNotification; +import org.onap.so.adapters.network.async.client.UpdateNetworkNotification; +import org.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.Subnet; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@Component +@WebService(serviceName = "NetworkAdapterAsync", endpointInterface = "org.onap.so.adapters.network.MsoNetworkAdapterAsync", targetNamespace = "http://org.onap.so/networkA") +public class MsoNetworkAdapterAsyncImpl implements MsoNetworkAdapterAsync { + + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoNetworkAdapterAsyncImpl.class); + private static final MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String BPEL_AUTH_PROP = "org.onap.so.adapters.network.bpelauth"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + + @Autowired + private Environment environment; + + @Autowired + private MsoNetworkAdapter networkAdapter; + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheckA () { + LOGGER.debug ("Health check call in Network Adapter"); + } + + /** + * This is the "Create Network" web service implementation. + * It will create a new Network of the requested type in the specified cloud + * and tenant. The tenant must exist at the time this service is called. + * + * If a network with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs) + * + * Initially, all provider networks must be "vlan" type, and multiple segments in + * a multi-provider network must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network creation/update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan(s). + * + * The method returns the network ID and a NetworkRollback object. This latter + * object can be passed as-is to the rollbackNetwork operation to undo everything + * that was created. This is useful if a network is successfully created but + * the orchestration fails on a subsequent operation. + */ + @Override + public void createNetworkA (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + Boolean failIfExists, + Boolean backout, + List <Subnet> subnets, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateNetworkA"); + LOGGER.debug ("Async Create Network: " + networkName + + " of type " + + networkType + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder <String> networkId = new Holder <> (); + Holder <String> neutronNetworkId = new Holder <> (); + Holder <NetworkRollback> networkRollback = new Holder <> (); + Holder <Map <String, String>> subnetIdMap = new Holder <> (); + + try { + networkAdapter.createNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + failIfExists, + backout, + subnets, + msoRequest, + networkId, + neutronNetworkId, + subnetIdMap, + networkRollback); + } catch (NetworkException e) { + LOGGER.debug ("Got a NetworkException on createNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createNetworkNotification (messageId, false, exCat, eMsg, null, null, null, null); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Create Network:Name " + networkName + " physicalNetworkName:" + physicalNetworkName); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.createNetworkNotification (messageId, + true, + null, + null, + networkId.value, + neutronNetworkId.value, + copyCreateSubnetIdMap (subnetIdMap), + copyNrb (networkRollback)); + } catch (Exception e) { + error = "Error sending createNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + /** + * This is the "Update Network" web service implementation. + * It will update an existing Network of the requested type in the specified cloud + * and tenant. The typical use will be to replace the VLANs with the supplied + * list (to add or remove a VLAN), but other properties may be updated as well. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs). + * + * Initially, all provider networks must currently be "vlan" type, and multi-provider + * networks must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan, segments. + * + * The method returns a NetworkRollback object. This object can be passed + * as-is to the rollbackNetwork operation to undo everything that was updated. + * This is useful if a network is successfully updated but orchestration + * fails on a subsequent operation. + */ + @Override + public void updateNetworkA (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <Subnet> subnets, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + + String serviceName = "UpdateNetworkA"; + MsoLogger.setServiceName (serviceName); + MsoLogger.setLogContext (msoRequest); + LOGGER.debug ("Async Update Network: " + networkId + + " of type " + + networkType + + "in " + + cloudSiteId + + "/" + + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder <NetworkRollback> networkRollback = new Holder <> (); + Holder <Map <String, String>> subnetIdMap = new Holder <> (); + + try { + networkAdapter.updateNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkId, + networkName, + physicalNetworkName, + vlans, + subnets, + msoRequest, + subnetIdMap, + networkRollback); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on updateNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateNetworkNotification (messageId, false, exCat, eMsg, null, copyNrb (networkRollback)); + } catch (Exception e1) { + error = "Error sending updateNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending updateNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Update Network:Name " + networkName + " NetworkId:" + networkId); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.updateNetworkNotification (messageId, + true, + null, + null, + copyUpdateSubnetIdMap (subnetIdMap), + copyNrb (networkRollback)); + } catch (Exception e) { + error = "Error sending updateNotification request" + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending updateNotification request", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + /** + * This is the queryNetwork method. It returns the existence and status of + * the specified network, along with its Neutron UUID and list of VLANs. + * This method attempts to find the network using both Heat and Neutron. + * Heat stacks are first searched based on the provided network name/id. + * If none is found, the Neutron is directly queried. + */ + @Override + public void queryNetworkA (String cloudSiteId, + String tenantId, + String networkNameOrId, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + + MsoLogger.setLogContext (msoRequest); + String serviceName = "QueryNetworkA"; + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Async Query Network " + networkNameOrId + " in " + cloudSiteId + "/" + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder <Boolean> networkExists = new Holder <> (); + Holder <String> networkId = new Holder <> (); + Holder <String> neutronNetworkId = new Holder <> (); + Holder <NetworkStatus> status = new Holder <> (); + Holder <List <Integer>> vlans = new Holder <> (); + Holder <Map <String, String>> subnetIdMap = new Holder <> (); + + try { + networkAdapter.queryNetwork (cloudSiteId, + tenantId, + networkNameOrId, + msoRequest, + networkExists, + networkId, + neutronNetworkId, + status, + vlans, + subnetIdMap); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on createNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.queryNetworkNotification (messageId, false, exCat, eMsg, null, null, null, null, null, null); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Query Network:NameOrId " + networkNameOrId + " tenantId:" + tenantId); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + org.onap.so.adapters.network.async.client.NetworkStatus networkS = org.onap.so.adapters.network.async.client.NetworkStatus.fromValue (status.value.name ()); + notifyPort.queryNetworkNotification (messageId, + true, + null, + null, + networkExists.value, + networkId.value, + neutronNetworkId.value, + networkS, + vlans.value, + copyQuerySubnetIdMap (subnetIdMap)); + } catch (Exception e) { + error = "Error sending createNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + /** + * This is the "Delete Network" web service implementation. + * It will delete a Network in the specified cloud and tenant. + * + * If the network is not found, it is treated as a success. + * + * This service supports two modes of Network creation/update/delete: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. + * + * For Heat-based orchestration, the networkId should be the stack ID. + * For Neutron-based orchestration, the networkId should be the Neutron network UUID. + * + * The method returns nothing on success. Rollback is not possible for delete + * commands, so any failure on delete will require manual fallout in the client. + */ + @Override + public void deleteNetworkA (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + MsoLogger.setLogContext (msoRequest); + String serviceName = "DeleteNetworkA"; + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Async Delete Network " + networkId + " in " + cloudSiteId + "/" + tenantId); + + // Use the synchronous method to perform the actual Create + + + // Synchronous Web Service Outputs + Holder <Boolean> networkDeleted = new Holder <> (); + + try { + networkAdapter.deleteNetwork (cloudSiteId, tenantId, networkType, modelCustomizationUuid, networkId, msoRequest, networkDeleted); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on createNetwork: ", e); + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteNetworkNotification (messageId, false, exCat, eMsg, null); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Delete NetworkId: " + networkId + " tenantId:" + tenantId); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.deleteNetworkNotification (messageId, true, null, null, networkDeleted.value); + } catch (Exception e) { + error = "Error sending deleteNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending deleteNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + 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 rollbackNetwork + * operation to undo the creation. + * + * The rollback includes removing the VNF and deleting the tenant if the + * tenant did not exist prior to the VNF creation. + */ + @Override + public void rollbackNetworkA (NetworkRollback rollback, String messageId, String notificationUrl) { + String error; + String serviceName = "RollbackNetworkA"; + MsoLogger.setServiceName (serviceName); + // rollback may be null (e.g. if network already existed when Create was called) + if (rollback == null) { + LOGGER.warn (MessageEnum.RA_ROLLBACK_NULL, "", "", MsoLogger.ErrorCode.SchemaError, "Rollback is null"); + return; + } + + MsoLogger.setLogContext (rollback.getMsoRequest ()); + LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK, rollback.getNetworkStackId (), "", ""); + // Use the synchronous method to perform the actual Create + + + try { + networkAdapter.rollbackNetwork (rollback); + MsoLogger.setServiceName (serviceName); + } catch (NetworkException e) { + MsoLogger.setServiceName (serviceName); + LOGGER.debug ("Got a NetworkException on rollbackNetwork: ", e); + // Build and send Asynchronous error response + MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ()); + } catch (Exception e1) { + LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in get fault info", e1); + } + // Build and send Asynchronous error response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackNetworkNotification (rollback.getMsoRequest ().getRequestId (), false, exCat, eMsg); + } catch (Exception e1) { + error = "Error sending createNetwork notification " + e1.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in sending createNetwork notification ", e1); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + LOGGER.debug ("Async Rollback NetworkId: " + rollback.getNetworkStackId () + " tenantId:" + rollback.getTenantId ()); + // Build and send Asynchronous response + try { + NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl); + notifyPort.rollbackNetworkNotification (rollback.getMsoRequest ().getRequestId (), true, null, null); + } catch (Exception e) { + error = "Error sending rollbackNetwork notification " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in sending rollbackNetwork notification", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error); + } + return; + } + + private org.onap.so.adapters.network.async.client.NetworkRollback copyNrb (Holder <NetworkRollback> hNrb) { + org.onap.so.adapters.network.async.client.NetworkRollback cnrb = new org.onap.so.adapters.network.async.client.NetworkRollback (); + + if (hNrb != null && hNrb.value != null) { + org.onap.so.adapters.network.async.client.MsoRequest cmr = new org.onap.so.adapters.network.async.client.MsoRequest (); + + cnrb.setCloudId (hNrb.value.getCloudId ()); + cmr.setRequestId (hNrb.value.getMsoRequest ().getRequestId ()); + cmr.setServiceInstanceId (hNrb.value.getMsoRequest ().getServiceInstanceId ()); + cnrb.setMsoRequest (cmr); + cnrb.setNetworkId (hNrb.value.getNetworkId ()); + cnrb.setNetworkStackId (hNrb.value.getNetworkStackId ()); + cnrb.setNeutronNetworkId (hNrb.value.getNeutronNetworkId ()); + cnrb.setTenantId (hNrb.value.getTenantId ()); + cnrb.setNetworkType (hNrb.value.getNetworkType ()); + cnrb.setNetworkCreated (hNrb.value.getNetworkCreated ()); + cnrb.setNetworkName (hNrb.value.getNetworkName ()); + cnrb.setPhysicalNetwork (hNrb.value.getPhysicalNetwork ()); + List <Integer> vlansc = cnrb.getVlans (); + List <Integer> vlansh = hNrb.value.getVlans (); + if (vlansh != null) { + vlansc.addAll (vlansh); + } + } + return cnrb; + } + + private NetworkAdapterNotify getNotifyEP (String notificationUrl) { + + URL warWsdlLoc = null; + try { + warWsdlLoc = Thread.currentThread ().getContextClassLoader ().getResource ("NetworkAdapterNotify.wsdl"); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.DataError, "Exception - WSDL not found", e); + } + if (warWsdlLoc == null) { + LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.DataError, "WSDL not found"); + } else { + try { + LOGGER.debug ("NetworkAdpaterNotify.wsdl location:" + warWsdlLoc.toURI ().toString ()); + } catch (Exception e) { + LOGGER.error (MessageEnum.RA_WSDL_URL_CONVENTION_EXC, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.SchemaError, "Exception - WSDL URL convention", e); + } + } + + NetworkAdapterNotify_Service notifySvc = new NetworkAdapterNotify_Service (warWsdlLoc, + new QName ("http://org.onap.so/networkNotify", + "networkAdapterNotify")); + + NetworkAdapterNotify notifyPort = notifySvc.getMsoNetworkAdapterAsyncImplPort (); + + BindingProvider bp = (BindingProvider) notifyPort; + + URL epUrl = null; + try { + epUrl = new URL (notificationUrl); + } catch (MalformedURLException e1) { + LOGGER.error (MessageEnum.RA_INIT_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - init notification", e1); + } + + if(null != epUrl) { + LOGGER.debug ("Notification Endpoint URL: " + epUrl.toExternalForm ()); + bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY, epUrl.toExternalForm ()); + } + else { + LOGGER.debug ("Notification Endpoint URL is NULL: "); + } + + // authentication + try { + Map <String, Object> reqCtx = bp.getRequestContext (); + Map <String, List <String>> headers = new HashMap <> (); + + String userCredentials = this.getEncryptedProperty (BPEL_AUTH_PROP, "", ENCRYPTION_KEY); + + String basicAuth = "Basic " + DatatypeConverter.printBase64Binary (userCredentials.getBytes ()); + reqCtx.put (MessageContext.HTTP_REQUEST_HEADERS, headers); + headers.put ("Authorization", Collections.singletonList (basicAuth)); + } catch (Exception e) { + String error1 = "Unable to set authorization in callback request" + e.getMessage (); + LOGGER.error (MessageEnum.RA_SET_CALLBACK_AUTH_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - Unable to set authorization in callback request", e); + alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error1); + } + + return notifyPort; + } + + public String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + try { + return CryptoUtils.decrypt(this.environment.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + this.environment.getProperty(key), e); + } + return defaultValue; + + } + + private CreateNetworkNotification.SubnetIdMap copyCreateSubnetIdMap (Holder <Map <String, String>> hMap) { + + CreateNetworkNotification.SubnetIdMap subnetIdMap = new CreateNetworkNotification.SubnetIdMap (); + + if (hMap != null && hMap.value != null) { + Map <String, String> sMap = new HashMap <> (); + sMap = hMap.value; + CreateNetworkNotification.SubnetIdMap.Entry entry = new CreateNetworkNotification.SubnetIdMap.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + subnetIdMap.getEntry ().add (entry); + } + } + return subnetIdMap; + } + + private UpdateNetworkNotification.SubnetIdMap copyUpdateSubnetIdMap (Holder <Map <String, String>> hMap) { + + UpdateNetworkNotification.SubnetIdMap subnetIdMap = new UpdateNetworkNotification.SubnetIdMap (); + + if (hMap != null && hMap.value != null) { + Map <String, String> sMap = new HashMap <> (); + sMap = hMap.value; + UpdateNetworkNotification.SubnetIdMap.Entry entry = new UpdateNetworkNotification.SubnetIdMap.Entry (); + + for (Map.Entry<String,String> mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + subnetIdMap.getEntry ().add (entry); + } + } + return subnetIdMap; + } + + private QueryNetworkNotification.SubnetIdMap copyQuerySubnetIdMap (Holder <Map <String, String>> hMap) { + + QueryNetworkNotification.SubnetIdMap subnetIdMap = new QueryNetworkNotification.SubnetIdMap (); + + if (hMap != null && hMap.value != null) { + Map <String, String> sMap = new HashMap <> (); + sMap = hMap.value; + QueryNetworkNotification.SubnetIdMap.Entry entry = new QueryNetworkNotification.SubnetIdMap.Entry (); + + for (Map.Entry<String,String> mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + subnetIdMap.getEntry ().add (entry); + } + } + return subnetIdMap; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java new file mode 100644 index 0000000000..f5a05b7333 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java @@ -0,0 +1,2125 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.network; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.network.beans.ContrailPolicyRef; +import org.onap.so.adapters.network.beans.ContrailPolicyRefSeq; +import org.onap.so.adapters.network.beans.ContrailSubnet; +import org.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.adapters.network.mappers.ContrailSubnetMapper; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.NetworkResource; +import org.onap.so.db.catalog.beans.NetworkResourceCustomization; +import org.onap.so.db.catalog.data.repository.NetworkResourceCustomizationRepository; +import org.onap.so.db.catalog.data.repository.NetworkResourceRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.HeatStatus; +import org.onap.so.openstack.beans.NetworkInfo; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.Pool; +import org.onap.so.openstack.beans.RouteTarget; +import org.onap.so.openstack.beans.StackInfo; +import org.onap.so.openstack.beans.Subnet; +import org.onap.so.openstack.exceptions.MsoAdapterException; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.utils.MsoCommonUtils; +import org.onap.so.openstack.utils.MsoHeatUtils; +import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate; +import org.onap.so.openstack.utils.MsoNeutronUtils; +import org.onap.so.openstack.utils.MsoNeutronUtils.NetworkType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +@Transactional +@WebService(serviceName = "NetworkAdapter", endpointInterface = "org.onap.so.adapters.network.MsoNetworkAdapter", targetNamespace = "http://org.onap.so/network") +public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { + + private static final String AIC3_NW_PROPERTY= "org.onap.so.adapters.network.aic3nw"; + private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork"; + private static final String VLANS = "vlans"; + private static final String PHYSICAL_NETWORK = "physical_network"; + private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork"; + private static final String NETWORK_ID = "network_id"; + private static final String NETWORK_FQDN = "network_fqdn"; + private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork"; + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static final String NEUTRON_MODE = "NEUTRON"; + + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoNetworkAdapterImpl.class); + private static final MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + @Autowired + private CloudConfig cloudConfig; + @Autowired + private Environment environment; + @Autowired + private MsoNeutronUtils neutron; + @Autowired + private MsoHeatUtils heat; + @Autowired + private MsoHeatUtilsWithUpdate heatWithUpdate; + @Autowired + private MsoCommonUtils commonUtils; + + @Autowired + private NetworkResourceCustomizationRepository networkCustomRepo; + + @Autowired + private NetworkResourceRepository networkResourceRepo; + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheck () { + LOGGER.debug ("Health check call in Network Adapter"); + } + + /** + * Do not use this constructor or the msoPropertiesFactory will be NULL. + * + * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory) + */ + public MsoNetworkAdapterImpl() { + } + + @Override + public void createNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + Boolean failIfExists, + Boolean backout, + List <Subnet> subnets, + MsoRequest msoRequest, + Holder <String> networkId, + Holder <String> neutronNetworkId, + Holder <Map <String, String>> subnetIdMap, + Holder <NetworkRollback> rollback) throws NetworkException { + Holder <String> networkFqdn = new Holder <> (); + createNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + null, + null, + null, + failIfExists, + backout, + subnets, + null, + null, + msoRequest, + networkId, + neutronNetworkId, + networkFqdn, + subnetIdMap, + rollback); + } + + @Override + public void createNetworkContrail (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + List <RouteTarget> routeTargets, + String shared, + String external, + Boolean failIfExists, + Boolean backout, + List <Subnet> subnets, + List <String> policyFqdns, + List<String> routeTableFqdns, + MsoRequest msoRequest, + Holder <String> networkId, + Holder <String> neutronNetworkId, + Holder <String> networkFqdn, + Holder <Map <String, String>> subnetIdMap, + Holder <NetworkRollback> rollback) throws NetworkException { + createNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkName, + null, + null, + routeTargets, + shared, + external, + failIfExists, + backout, + subnets, + policyFqdns, + routeTableFqdns, + msoRequest, + networkId, + neutronNetworkId, + networkFqdn, + subnetIdMap, + rollback); + } + + /** + * This is the "Create Network" web service implementation. + * It will create a new Network of the requested type in the specified cloud + * and tenant. The tenant must exist at the time this service is called. + * + * If a network with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs) + * + * Initially, all provider networks must be "vlan" type, and multiple segments in + * a multi-provider network must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network creation/update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan(s). + * + * The method returns the network ID and a NetworkRollback object. This latter + * object can be passed as-is to the rollbackNetwork operation to undo everything + * that was created. This is useful if a network is successfully created but + * the orchestration fails on a subsequent operation. + */ + + private void createNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <RouteTarget> routeTargets, + String shared, + String external, + Boolean failIfExists, + Boolean backout, + List <Subnet> subnets, + List <String> policyFqdns, + List <String> routeTableFqdns, + MsoRequest msoRequest, + Holder <String> networkId, + Holder <String> neutronNetworkId, + Holder <String> networkFqdn, + Holder <Map <String, String>> subnetIdMap, + Holder <NetworkRollback> rollback) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateNetwork"); + + LOGGER.debug ("*** CREATE Network: " + networkName + + " of type " + + networkType + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + NetworkRollback networkRollback = new NetworkRollback (); + networkRollback.setCloudId (cloudSiteId); + networkRollback.setTenantId (tenantId); + networkRollback.setMsoRequest (msoRequest); + networkRollback.setModelCustomizationUuid(modelCustomizationUuid); + + // tenant query is not required here. + // If the tenant doesn't exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token). + // So this is just catching that error in a bit more obvious way up front. + + Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId); + if (!cloudSiteOpt.isPresent()) + { + String error = "Configuration Error. Stack " + networkName + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + " CloudSite does not exist in MSO Configuration"; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Set the detailed error as the Exception 'message' + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + + NetworkResource networkResource = networkCheck (startTime, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + routeTargets, + cloudSiteId, + cloudSiteOpt.get()); + String mode = networkResource.getOrchestrationMode (); + NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ()); + + if (NEUTRON_MODE.equals (mode)) { + + // Use an MsoNeutronUtils for all neutron commands + + // See if the Network already exists (by name) + NetworkInfo netInfo = null; + long queryNetworkStarttime = System.currentTimeMillis (); + try { + netInfo = neutron.queryNetwork (networkName, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "QueryNetwork", null); + } catch (MsoException me) { + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack", "OpenStack", "QueryNetwork", null); + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack", me); + me.addContext (CREATE_NETWORK_CONTEXT); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack"); + throw new NetworkException (me); + } + + if (netInfo != null) { + // Exists. If that's OK, return success with the network ID. + // Otherwise, return an exception. + if (failIfExists != null && failIfExists) { + String error = "Create Nework: Network " + networkName + + " already exists in " + + cloudSiteId + + "/" + + tenantId + + " with ID " + netInfo.getId(); + LOGGER.error (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } else { + // Populate the outputs from the existing network. + networkId.value = netInfo.getId (); + neutronNetworkId.value = netInfo.getId (); + rollback.value = networkRollback; // Default rollback - no updates performed + String msg = "Found Existing network, status=" + netInfo.getStatus () + " for Neutron mode"; + LOGGER.warn (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, msg); + } + return; + } + + long createNetworkStarttime = System.currentTimeMillis (); + try { + netInfo = neutron.createNetwork (cloudSiteId, + tenantId, + neutronNetworkType, + networkName, + physicalNetworkName, + vlans); + LOGGER.recordMetricEvent (createNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "CreateNetwork", null); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + LOGGER.recordMetricEvent (createNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack", "OpenStack", "CreateNetwork", null); + String error = "Create Network: type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + throw new NetworkException (me); + } + + // Note: ignoring MsoNetworkAlreadyExists because we already checked. + + // If reach this point, network creation is successful. + // Since directly created via Neutron, networkId tracked by MSO is the same + // as the neutron network ID. + networkId.value = netInfo.getId (); + neutronNetworkId.value = netInfo.getId (); + + networkRollback.setNetworkCreated (true); + networkRollback.setNetworkId (netInfo.getId ()); + networkRollback.setNeutronNetworkId (netInfo.getId ()); + networkRollback.setNetworkType (networkType); + + LOGGER.debug ("Network " + networkName + " created, id = " + netInfo.getId ()); + } else if ("HEAT".equals (mode)) { + + HeatTemplate heatTemplate = networkResource.getHeatTemplate(); + if (heatTemplate == null) { + String error = "Network error - undefined Heat Template. Network Type = " + networkType; + LOGGER.error (MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType, "Openstack", "", MsoLogger.ErrorCode.DataError, "Network error - undefined Heat Template. Network Type = " + networkType); + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this + // error, + // configuration + // must be fixed + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new NetworkException (error, MsoExceptionCategory.INTERNAL); + } + + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString()); + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + boolean aic3template=false; + String aic3nw = AIC3_NW; + + aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW); + + if (template.contains(aic3nw)) + aic3template = true; + + // First, look up to see if the Network already exists (by name). + // For HEAT orchestration of networks, the stack name will always match the network name + StackInfo heatStack = null; + long queryNetworkStarttime = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, networkName); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "QueryNetwork", null); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack", "OpenStack", "QueryNetwork", null); + String error = "Create Network (heat): query network " + networkName + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + + if (heatStack != null && (heatStack.getStatus () != HeatStatus.NOTFOUND)) { + // Stack exists. Return success or error depending on input directive + if (failIfExists != null && failIfExists) { + String error = "CreateNetwork: Stack " + networkName + + " already exists in " + + cloudSiteId + + "/" + + tenantId + + " as " + heatStack.getCanonicalName(); + LOGGER.error (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "", MsoLogger.ErrorCode.DataError, "Network already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } else { + // Populate the outputs from the existing stack. + networkId.value = heatStack.getCanonicalName (); + neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID); + rollback.value = networkRollback; // Default rollback - no updates performed + if (aic3template) + { + networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN); + } + Map <String, Object> outputs = heatStack.getOutputs (); + Map <String, String> sMap = new HashMap <> (); + if (outputs != null) { + for (String key : outputs.keySet ()) { + if (key != null && key.startsWith ("subnet")) { + if (aic3template) //one subnet_id output + { + Map <String, String> map = getSubnetUUId(key, outputs, subnets); + sMap.putAll(map); + } + else //multiples subnet_%aaid% outputs + { + String subnetUUId = (String) outputs.get(key); + sMap.put (key.substring("subnet_id_".length()), subnetUUId); + } + } + } + } + subnetIdMap.value = sMap; + LOGGER.warn (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", MsoLogger.ErrorCode.DataError, "Found Existing network stack, status=" + heatStack.getStatus ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Found Existing network stack"); + } + return; + } + + // Ready to deploy the new Network + // Build the common set of HEAT template parameters + Map <String, Object> stackParams = populateNetworkParams (neutronNetworkType, + networkName, + physicalNetworkName, + vlans, + routeTargets, + shared, + external, + aic3template); + + // Validate (and update) the input parameters against the DB definition + // Shouldn't happen unless DB config is wrong, since all networks use same inputs + // and inputs were already validated. + try { + stackParams = heat.validateStackParams (stackParams, heatTemplate); + } catch (IllegalArgumentException e) { + String error = "Create Network: Configuration Error: " + e.getMessage (); + LOGGER.error (MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e); + alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this + // error, + // configuration + // must be fixed + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Input parameters were not valid + throw new NetworkException (error, MsoExceptionCategory.INTERNAL); + } + + if (subnets != null) { + try { + if (aic3template) + { + template = mergeSubnetsAIC3 (template, subnets, stackParams); + } + else + { + template = mergeSubnets (template, subnets); + } + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat): type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging subnets", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException (me); + } + } + + if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) { + try { + mergePolicyRefs (policyFqdns, stackParams); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging policyRefs", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException (me); + } + } + + if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) { + try { + mergeRouteTableRefs (routeTableFqdns, stackParams); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging routeTableRefs", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException (me); + } + } + + // Deploy the network stack + // Ignore MsoStackAlreadyExists exception because we already checked. + try { + if (backout == null) + backout = true; + heatStack = heat.createStack (cloudSiteId, + tenantId, + networkName, + template, + stackParams, + true, + heatTemplate.getTimeoutMinutes (), + null, + null, + null, + backout.booleanValue()); + } catch (MsoException me) { + me.addContext (CREATE_NETWORK_CONTEXT); + String error = "Create Network (heat): type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception creating network", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + + // Reach this point if createStack is successful. + + // For Heat-based orchestration, the MSO-tracked network ID is the heat stack, + // and the neutronNetworkId is the network UUID returned in stack outputs. + networkId.value = heatStack.getCanonicalName (); + neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID); + if (aic3template) + { + networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN); + } + Map <String, Object> outputs = heatStack.getOutputs (); + Map <String, String> sMap = new HashMap <> (); + if (outputs != null) { + for (String key : outputs.keySet ()) { + if (key != null && key.startsWith ("subnet")) { + if (aic3template) //one subnet output expected + { + Map <String, String> map = getSubnetUUId(key, outputs, subnets); + sMap.putAll(map); + } + else //multiples subnet_%aaid% outputs allowed + { + String subnetUUId = (String) outputs.get(key); + sMap.put (key.substring("subnet_id_".length()), subnetUUId); + } + } + } + } + subnetIdMap.value = sMap; + + rollback.value = networkRollback; + // Populate remaining rollback info and response parameters. + networkRollback.setNetworkStackId (heatStack.getCanonicalName ()); + networkRollback.setNeutronNetworkId ((String) heatStack.getOutputs ().get (NETWORK_ID)); + networkRollback.setNetworkCreated (true); + networkRollback.setNetworkType (networkType); + + LOGGER.debug ("Network " + networkName + " successfully created via HEAT"); + } + + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network"); + return; + } + + @Override + public void updateNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <Subnet> subnets, + MsoRequest msoRequest, + Holder <Map <String, String>> subnetIdMap, + Holder <NetworkRollback> rollback) throws NetworkException { + updateNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkId, + networkName, + physicalNetworkName, + vlans, + null, + null, + null, + subnets, + null, + null, + msoRequest, + subnetIdMap, + rollback); + + } + + @Override + public void updateNetworkContrail (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + List <RouteTarget> routeTargets, + String shared, + String external, + List <Subnet> subnets, + List <String> policyFqdns, + List<String> routeTableFqdns, + MsoRequest msoRequest, + Holder <Map <String, String>> subnetIdMap, + Holder <NetworkRollback> rollback) throws NetworkException { + updateNetwork (cloudSiteId, + tenantId, + networkType, + modelCustomizationUuid, + networkId, + networkName, + null, + null, + routeTargets, + shared, + external, + subnets, + policyFqdns, + routeTableFqdns, + msoRequest, + subnetIdMap, + rollback); + } + + /** + * This is the "Update Network" web service implementation. + * It will update an existing Network of the requested type in the specified cloud + * and tenant. The typical use will be to replace the VLANs with the supplied + * list (to add or remove a VLAN), but other properties may be updated as well. + * + * There will be a pre-defined set of network types defined in the MSO Catalog. + * All such networks will have a similar configuration, based on the allowable + * Openstack networking definitions. This includes basic networks, provider + * networks (with a single VLAN), and multi-provider networks (one or more VLANs). + * + * Initially, all provider networks must currently be "vlan" type, and multi-provider + * networks must be multiple VLANs on the same physical network. + * + * This service supports two modes of Network update: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. All Heat-based templates must support some subset of + * the same input parameters: network_name, physical_network, vlan, segments. + * + * The method returns a NetworkRollback object. This object can be passed + * as-is to the rollbackNetwork operation to undo everything that was updated. + * This is useful if a network is successfully updated but orchestration + * fails on a subsequent operation. + */ + private void updateNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <RouteTarget> routeTargets, + String shared, + String external, + List <Subnet> subnets, + List <String> policyFqdns, + List<String> routeTableFqdns, + MsoRequest msoRequest, + Holder <Map <String, String>> subnetIdMap, + Holder <NetworkRollback> rollback) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("UpdateNetwork"); + LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName + + " of type " + + networkType + + " in " + + cloudSiteId + + "/" + + tenantId); + + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Build a default rollback object (no actions performed) + NetworkRollback networkRollback = new NetworkRollback (); + networkRollback.setCloudId (cloudSiteId); + networkRollback.setTenantId (tenantId); + networkRollback.setMsoRequest (msoRequest); + + Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId); + if (!cloudSiteOpt.isPresent()) { + String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + " CloudSite does not exist in MSO Configuration"; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Set the detailed error as the Exception 'message' + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + + + + NetworkResource networkResource = networkCheck( + startTime, + networkType, + modelCustomizationUuid, + networkName, + physicalNetworkName, + vlans, + routeTargets, + cloudSiteId, + cloudSiteOpt.get()); + String mode = networkResource.getOrchestrationMode(); + NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType()); + + // Use an MsoNeutronUtils for all Neutron commands + + if (NEUTRON_MODE.equals(mode)) { + + // Verify that the Network exists + // For Neutron-based orchestration, the networkId is the Neutron Network UUID. + NetworkInfo netInfo = null; + long queryNetworkStarttime = System.currentTimeMillis(); + try { + netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network (neutron): query " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null); + LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "QueryNetwork", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - queryNetwork", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + if (netInfo == null) { + String error = "Update Nework: Network " + networkId + + " does not exist in " + + cloudSiteId + + "/" + + tenantId; + LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Network not found"); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + // Does not exist. Throw an exception (can't update a non-existent network) + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + long updateNetworkStarttime = System.currentTimeMillis(); + try { + netInfo = neutron.updateNetwork(cloudSiteId, + tenantId, + networkId, + neutronNetworkType, + physicalNetworkName, + vlans); + LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateNetwork", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network (neutron): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "Openstack", "updateNetwork", MsoLogger.ErrorCode.DataError, "Exception - updateNetwork", me); + LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateNetwork", null); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + // Add the network ID and previously queried vlans to the rollback object + networkRollback.setNetworkId(netInfo.getId()); + networkRollback.setNeutronNetworkId(netInfo.getId()); + networkRollback.setNetworkType(networkType); + // Save previous parameters + networkRollback.setNetworkName(netInfo.getName()); + networkRollback.setPhysicalNetwork(netInfo.getProvider()); + networkRollback.setVlans(netInfo.getVlans()); + + LOGGER.debug("Network " + networkId + " updated, id = " + netInfo.getId()); + } else if ("HEAT".equals(mode)) { + + // First, look up to see that the Network already exists. + // For Heat-based orchestration, the networkId is the network Stack ID. + StackInfo heatStack = null; + long queryStackStarttime = System.currentTimeMillis(); + try { + heatStack = heat.queryStack(cloudSiteId, tenantId, networkName); + LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "UpdateNetwork (heat): query " + networkName + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null); + LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) { + String error = "UpdateNetwork: Stack " + networkName + + " does not exist in " + + cloudSiteId + + "/" + + tenantId; + LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Network not found"); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + // Network stack does not exist. Return an error + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + + // Get the previous parameters for rollback + Map<String, Object> heatParams = heatStack.getParameters(); + + String previousNetworkName = (String) heatParams.get("network_name"); + String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK); + + List<Integer> previousVlans = new ArrayList<>(); + String vlansParam = (String) heatParams.get(VLANS); + if (vlansParam != null) { + for (String vlan : vlansParam.split(",")) { + try { + previousVlans.add(Integer.parseInt(vlan)); + } catch (NumberFormatException e) { + LOGGER.warn(MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e); + } + } + } + LOGGER.debug("Update Stack: Previous VLANS: " + previousVlans); + + // Ready to deploy the updated Network via Heat + + + HeatTemplate heatTemplate = networkResource.getHeatTemplate(); + if (heatTemplate == null) { + String error = "Network error - undefined Heat Template. Network Type=" + networkType; + LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType, "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError, "Network error - undefined Heat Template. Network Type=" + networkType); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException(error, MsoExceptionCategory.INTERNAL); + } + + LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString()); + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate(); + template = template.replaceAll("\r\n", "\n"); + + boolean aic3template = false; + String aic3nw = AIC3_NW; + + aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW); + + if (template.contains(aic3nw)) + aic3template = true; + + // Build the common set of HEAT template parameters + Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType, + networkName, + physicalNetworkName, + vlans, + routeTargets, + shared, + external, + aic3template); + + // Validate (and update) the input parameters against the DB definition + // Shouldn't happen unless DB config is wrong, since all networks use same inputs + try { + stackParams = heat.validateStackParams(stackParams, heatTemplate); + } catch (IllegalArgumentException e) { + String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType; + LOGGER.error(MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error"); + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError, error); + throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e); + } + + if (subnets != null) { + try { + if (aic3template) { + template = mergeSubnetsAIC3(template, subnets, stackParams); + } else { + template = mergeSubnets(template, subnets); + } + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network (heat): type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergeSubnets ", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException(me); + } + } + + if (policyFqdns != null && aic3template) { + try { + mergePolicyRefs(policyFqdns, stackParams); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergePolicyRefs", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException(me); + } + } + + if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) { + try { + mergeRouteTableRefs(routeTableFqdns, stackParams); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergeRouteTableRefs", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + throw new NetworkException(me); + } + } + + // Update the network stack + // Ignore MsoStackNotFound exception because we already checked. + long updateStackStarttime = System.currentTimeMillis(); + try { + heatStack = heatWithUpdate.updateStack(cloudSiteId, + tenantId, + networkId, + template, + stackParams, + true, + heatTemplate.getTimeoutMinutes()); + LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateStack", null); + } catch (MsoException me) { + me.addContext(UPDATE_NETWORK_CONTEXT); + String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null); + LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - update network", me); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException(me); + } + + Map<String, Object> outputs = heatStack.getOutputs(); + Map<String, String> sMap = new HashMap<>(); + if (outputs != null) { + for (String key : outputs.keySet()) { + if (key != null && key.startsWith("subnet")) { + if (aic3template) //one subnet output expected + { + Map<String, String> map = getSubnetUUId(key, outputs, subnets); + sMap.putAll(map); + } else //multiples subnet_%aaid% outputs allowed + { + String subnetUUId = (String) outputs.get(key); + sMap.put(key.substring("subnet_id_".length()), subnetUUId); + } + } + } + } + subnetIdMap.value = sMap; + + // Reach this point if createStack is successful. + // Populate remaining rollback info and response parameters. + networkRollback.setNetworkStackId(heatStack.getCanonicalName()); + if(null != outputs) { + networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID)); + } + else { + LOGGER.debug("outputs is NULL"); + } + networkRollback.setNetworkType(networkType); + // Save previous parameters + networkRollback.setNetworkName(previousNetworkName); + networkRollback.setPhysicalNetwork(previousPhysicalNetwork); + networkRollback.setVlans(previousVlans); + + rollback.value = networkRollback; + + LOGGER.debug("Network " + networkId + " successfully updated via HEAT"); + } + + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network"); + return; + } + + private NetworkResource networkCheck (long startTime, + String networkType, + String modelCustomizationUuid, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <RouteTarget> routeTargets, + String cloudSiteId, + CloudSite cloudSite) throws NetworkException { + // Retrieve the Network Resource definition + NetworkResource networkResource = null; + NetworkResourceCustomization networkCust = null; + if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { + if (!commonUtils.isNullOrEmpty(networkType)) { + networkResource = networkResourceRepo.findOneByModelName(networkType); + } + } else { + networkCust = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid); + } + if(networkCust != null){ + LOGGER.debug("Got Network Customization definition from Catalog: " + + networkCust.toString()); + + networkResource = networkCust.getNetworkResource(); + } + if (networkResource == null) { + String error = "Create/UpdateNetwork: Unable to get network resource with NetworkType:" + + networkType + + " or ModelCustomizationUUID:" + + modelCustomizationUuid; + LOGGER.error(MessageEnum.RA_UNKOWN_PARAM, + "NetworkType/ModelCustomizationUUID", networkType + "/" + + modelCustomizationUuid, "OpenStack", "", + MsoLogger.ErrorCode.DataError, + "Create/UpdateNetwork: Unknown NetworkType/ModelCustomizationUUID"); + + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug("Got Network definition from Catalog: " + + networkResource.toString()); + + String mode = networkResource.getOrchestrationMode(); + NetworkType neutronNetworkType = NetworkType + .valueOf(networkResource.getNeutronNetworkType()); + + // All Networks are orchestrated via HEAT or Neutron + if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) { + String error = "CreateNetwork: Configuration Error: Network Type = " + + networkType; + LOGGER.error(MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT, + mode, "OpenStack", "", MsoLogger.ErrorCode.DataError, + "CreateNetwork: Configuration Error"); + // Alarm on this error, configuration must be fixed + alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, + MsoAlarmLogger.CRITICAL, error); + + throw new NetworkException(error, MsoExceptionCategory.INTERNAL); + } + + MavenLikeVersioning aicV = new MavenLikeVersioning(); + aicV.setVersion(cloudSite.getAicVersion()); + if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV + .isTheSameVersion(networkResource.getAicVersionMin())) // aic + // >= + // min + && (aicV.isTheSameVersion(networkResource + .getAicVersionMax()) || !(aicV + .isMoreRecentThan(networkResource + .getAicVersionMax())))) // aic <= max + { + LOGGER.debug("Network Type:" + networkType + " VersionMin:" + + networkResource.getAicVersionMin() + " VersionMax:" + + networkResource.getAicVersionMax() + + " supported on Cloud:" + cloudSiteId + + " with AIC_Version:" + cloudSite.getAicVersion()); + } else { + String error = "Network Type:" + networkType + " Version_Min:" + + networkResource.getAicVersionMin() + " Version_Max:" + + networkResource.getAicVersionMax() + + " not supported on Cloud:" + cloudSiteId + + " with AIC_Version:" + cloudSite.getAicVersion(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", + MsoLogger.ErrorCode.DataError, + "Network Type not supported on Cloud"); + LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, + MsoLogger.ResponseCode.DataError, error); + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + + // Validate the Network parameters. + String missing = validateNetworkParams(neutronNetworkType, + networkName, physicalNetworkName, vlans, routeTargets); + if (!missing.isEmpty()) { + String error = "Create Network: Missing parameters: " + missing; + LOGGER.error(MessageEnum.RA_MISSING_PARAM, missing, + "OpenStack", "", MsoLogger.ErrorCode.DataError, + "Create Network: Missing parameters"); + + throw new NetworkException(error, MsoExceptionCategory.USERDATA); + } + + return networkResource; + } + + @Override + public void queryNetwork (String cloudSiteId, + String tenantId, + String networkNameOrId, + MsoRequest msoRequest, + Holder <Boolean> networkExists, + Holder <String> networkId, + Holder <String> neutronNetworkId, + Holder <NetworkStatus> status, + Holder <List <Integer>> vlans, + Holder <Map <String, String>> subnetIdMap) throws NetworkException { + queryNetwork (cloudSiteId, + tenantId, + networkNameOrId, + msoRequest, + networkExists, + networkId, + neutronNetworkId, + status, + vlans, + null, + subnetIdMap); + } + + @Override + public void queryNetworkContrail (String cloudSiteId, + String tenantId, + String networkNameOrId, + MsoRequest msoRequest, + Holder <Boolean> networkExists, + Holder <String> networkId, + Holder <String> neutronNetworkId, + Holder <NetworkStatus> status, + Holder <List <RouteTarget>> routeTargets, + Holder <Map <String, String>> subnetIdMap) throws NetworkException { + queryNetwork (cloudSiteId, + tenantId, + networkNameOrId, + msoRequest, + networkExists, + networkId, + neutronNetworkId, + status, + null, + routeTargets, + subnetIdMap); + } + + /** + * This is the queryNetwork method. It returns the existence and status of + * the specified network, along with its Neutron UUID and list of VLANs. + * This method attempts to find the network using both Heat and Neutron. + * Heat stacks are first searched based on the provided network name/id. + * If none is found, the Neutron is directly queried. + */ + private void queryNetwork (String cloudSiteId, + String tenantId, + String networkNameOrId, + MsoRequest msoRequest, + Holder <Boolean> networkExists, + Holder <String> networkId, + Holder <String> neutronNetworkId, + Holder <NetworkStatus> status, + Holder <List <Integer>> vlans, + Holder <List <RouteTarget>> routeTargets, + Holder <Map <String, String>> subnetIdMap) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("QueryNetwork"); + LOGGER.debug ("*** QUERY Network with Network: " + networkNameOrId + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + if (commonUtils.isNullOrEmpty (cloudSiteId) + || commonUtils.isNullOrEmpty(tenantId) + || commonUtils.isNullOrEmpty(networkNameOrId)) { + + String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkNameOrId", "OpenStack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId); + if (!cloudSiteOpt.isPresent()) + { + String error = "Configuration Error. Stack " + networkNameOrId + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + " CloudSite does not exist in MSO Configuration"; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Configuration Error"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + // Set the detailed error as the Exception 'message' + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + // Use MsoNeutronUtils for all NEUTRON commands + + String mode; + String neutronId; + // Try Heat first, since networks may be named the same as the Heat stack + StackInfo heatStack = null; + long queryStackStarttime = System.currentTimeMillis (); + try { + heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId); + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null); + } catch (MsoException me) { + me.addContext ("QueryNetwork"); + String error = "Query Network (heat): " + networkNameOrId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null); + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + + // Populate the outputs based on the returned Stack information + if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) { + // Found it. Get the neutronNetworkId for further query + Map <String, Object> outputs = heatStack.getOutputs (); + neutronId = (String) outputs.get (NETWORK_ID); + mode = "HEAT"; + + Map <String, String> sMap = new HashMap <> (); + if (outputs != null) { + for (String key : outputs.keySet ()) { + if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs + { + String subnetUUId = (String) outputs.get(key); + sMap.put (key.substring("subnet_id_".length()), subnetUUId); + } + else if (key != null && key.startsWith ("subnet")) //one subnet output expected + { + Map <String, String> map = getSubnetUUId(key, outputs, null); + sMap.putAll(map); + } + + } + } + subnetIdMap.value = sMap; + } else { + // Input ID was not a Heat stack ID. Try it directly in Neutron + neutronId = networkNameOrId; + mode = NEUTRON_MODE; + } + + // Query directly against the Neutron Network for the details + // no RouteTargets available for ContrailV2 in neutron net-show + // networkId is heatStackId + long queryNetworkStarttime = System.currentTimeMillis (); + try { + NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null); + if (netInfo != null) { + // Found. Populate the output elements + networkExists.value = Boolean.TRUE; + if ("HEAT".equals (mode)) { + networkId.value = heatStack.getCanonicalName (); + } else { + networkId.value = netInfo.getId (); + } + neutronNetworkId.value = netInfo.getId (); + status.value = netInfo.getStatus (); + if (vlans != null) + vlans.value = netInfo.getVlans (); + + LOGGER.debug ("Network " + networkNameOrId + + " found (" + + mode + + "), ID = " + + networkId.value + + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : "")); + } else { + // Not found. Populate the status fields, leave the rest null + networkExists.value = Boolean.FALSE; + status.value = NetworkStatus.NOTFOUND; + neutronNetworkId.value = null; + if (vlans != null) + vlans.value = new ArrayList<>(); + + LOGGER.debug ("Network " + networkNameOrId + " not found"); + } + } catch (MsoException me) { + me.addContext ("QueryNetwork"); + String error = "Query Network (neutron): " + networkNameOrId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null); + LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network"); + return; + } + + /** + * This is the "Delete Network" web service implementation. + * It will delete a Network in the specified cloud and tenant. + * + * If the network is not found, it is treated as a success. + * + * This service supports two modes of Network creation/update/delete: + * - via Heat Templates + * - via Neutron API + * The network orchestration mode for each network type is declared in its + * catalog definition. + * + * For Heat-based orchestration, the networkId should be the stack ID. + * For Neutron-based orchestration, the networkId should be the Neutron network UUID. + * + * The method returns nothing on success. Rollback is not possible for delete + * commands, so any failure on delete will require manual fallout in the client. + */ + @Override + public void deleteNetwork (String cloudSiteId, + String tenantId, + String networkType, + String modelCustomizationUuid, + String networkId, + MsoRequest msoRequest, + Holder <Boolean> networkDeleted) throws NetworkException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteNetwork"); + LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + + if (commonUtils.isNullOrEmpty (cloudSiteId) + || commonUtils.isNullOrEmpty(tenantId) + || commonUtils.isNullOrEmpty(networkId)) { + String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + + // Retrieve the Network Resource definition + NetworkResource networkResource = null; + + if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { + if (!commonUtils.isNullOrEmpty(networkType)) { + networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType); + } + } else { + NetworkResourceCustomization nrc = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid); + if (nrc != null) { + networkResource = nrc.getNetworkResource(); + } + } + + String mode = ""; + if (networkResource != null) { + LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ()); + + mode = networkResource.getOrchestrationMode (); + } + + if (NEUTRON_MODE.equals (mode)) { + + // Use MsoNeutronUtils for all NEUTRON commands + long deleteNetworkStarttime = System.currentTimeMillis (); + try { + // The deleteNetwork function in MsoNeutronUtils returns success if the network + // was not found. So don't bother to query first. + boolean deleted = neutron.deleteNetwork (networkId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteNetwork", null); + networkDeleted.value = deleted; + } catch (MsoException me) { + me.addContext ("DeleteNetwork"); + String error = "Delete Network (neutron): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } else { // DEFAULT to ("HEAT".equals (mode)) + long deleteStackStarttime = System.currentTimeMillis (); + + try { + // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted. + // So query first to report back if stack WAS deleted or just NOTOFUND + StackInfo heatStack = null; + heatStack = heat.queryStack(cloudSiteId, tenantId, networkId); + if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) + { + heat.deleteStack (tenantId, cloudSiteId, networkId, true); + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null); + networkDeleted.value = true; + } + else + { + networkDeleted.value = false; + } + } catch (MsoException me) { + me.addContext ("DeleteNetwork"); + String error = "Delete Network (heat): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } + + + // On success, nothing is returned. + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network"); + 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. + * + * The rollback includes removing the VNF and deleting the tenant if the + * tenant did not exist prior to the VNF creation. + */ + @Override + public void rollbackNetwork (NetworkRollback rollback) throws NetworkException { + MsoLogger.setServiceName ("RollbackNetwork"); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + if (rollback == null) { + LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform"); + return; + } + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudId (); + String tenantId = rollback.getTenantId (); + String networkId = rollback.getNetworkStackId (); + String networkType = rollback.getNetworkType (); + String modelCustomizationUuid = rollback.getModelCustomizationUuid(); + + LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId); + + + + // Retrieve the Network Resource definition + NetworkResource networkResource = null; + if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { + networkResource = networkCustomRepo.findOneByNetworkType(networkType).getNetworkResource(); + } else { + networkResource = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid).getNetworkResource(); + } + String mode = ""; + if (networkResource != null) { + + LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ()); + + mode = networkResource.getOrchestrationMode (); + } + + if (rollback.getNetworkCreated ()) { + // Rolling back a newly created network, so delete it. + if (NEUTRON_MODE.equals (mode)) { + // Use MsoNeutronUtils for all NEUTRON commands + long deleteNetworkStarttime = System.currentTimeMillis (); + try { + // The deleteNetwork function in MsoNeutronUtils returns success if the network + // was not found. So don't bother to query first. + neutron.deleteNetwork (networkId, tenantId, cloudSiteId); + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteNetwork", null); + } catch (MsoException me) { + me.addContext ("RollbackNetwork"); + String error = "Rollback Network (neutron): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } else { // DEFAULT to if ("HEAT".equals (mode)) + long deleteStackStarttime = System.currentTimeMillis (); + try { + // The deleteStack function in MsoHeatUtils returns success if the stack + // was not found. So don't bother to query first. + heat.deleteStack (tenantId, cloudSiteId, networkId, true); + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null); + } catch (MsoException me) { + me.addContext ("RollbackNetwork"); + String error = "Rollback Network (heat): " + networkId + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null); + LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new NetworkException (me); + } + } + } + + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network"); + return; + } + + private String validateNetworkParams (NetworkType neutronNetworkType, + String networkName, + String physicalNetwork, + List <Integer> vlans, + List <RouteTarget> routeTargets) { + String sep = ""; + StringBuilder missing = new StringBuilder (); + if (commonUtils.isNullOrEmpty(networkName)) { + missing.append ("networkName"); + sep = ","; + } + + if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) { + if (commonUtils.isNullOrEmpty(physicalNetwork)) { + missing.append (sep).append ("physicalNetworkName"); + sep = ","; + } + if (vlans == null || vlans.isEmpty ()) { + missing.append (sep).append (VLANS); + } + } + + return missing.toString (); + } + + private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType, + String networkName, + String physicalNetwork, + List <Integer> vlans, + List <RouteTarget> routeTargets, + String shared, + String external, + boolean aic3template) { + // Build the common set of HEAT template parameters + Map <String, Object> stackParams = new HashMap <> (); + stackParams.put ("network_name", networkName); + + if (neutronNetworkType == NetworkType.PROVIDER) { + // For Provider type + stackParams.put (PHYSICAL_NETWORK, physicalNetwork); + stackParams.put ("vlan", vlans.get (0).toString ()); + } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) { + // For Multi-provider, PO supports a custom resource extension of ProviderNet. + // It supports all ProviderNet properties except segmentation_id, and adds a + // comma-separated-list of VLANs as a "segments" property. + // Note that this does not match the Neutron definition of Multi-Provider network, + // which contains a list of 'segments', each having physical_network, network_type, + // and segmentation_id. + StringBuilder buf = new StringBuilder (); + String sep = ""; + for (Integer vlan : vlans) { + buf.append (sep).append (vlan.toString ()); + sep = ","; + } + String csl = buf.toString (); + + stackParams.put (PHYSICAL_NETWORK, physicalNetwork); + stackParams.put (VLANS, csl); + } + if (routeTargets != null) { + + String rtGlobal = ""; + String rtImport = ""; + String rtExport = ""; + String sep = ""; + for (RouteTarget rt : routeTargets) { + boolean rtIsNull = false; + if (rt != null) + { + String routeTarget = rt.getRouteTarget(); + String routeTargetRole = rt.getRouteTargetRole(); + LOGGER.debug("Checking for an actually null route target: " + rt.toString()); + if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null")) + rtIsNull = true; + if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null")) + rtIsNull = true; + } else { + rtIsNull = true; + } + if (!rtIsNull) { + LOGGER.debug("Input RT:" + rt.toString()); + String role = rt.getRouteTargetRole(); + String rtValue = rt.getRouteTarget(); + + if ("IMPORT".equalsIgnoreCase(role)) + { + sep = rtImport.isEmpty() ? "" : ","; + rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ; + } + else if ("EXPORT".equalsIgnoreCase(role)) + { + sep = rtExport.isEmpty() ? "" : ","; + rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ; + } + else // covers BOTH, empty etc + { + sep = rtGlobal.isEmpty() ? "" : ","; + rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ; + } + + } + } + + if (!rtImport.isEmpty()) + { + stackParams.put ("route_targets_import", rtImport); + } + if (!rtExport.isEmpty()) + { + stackParams.put ("route_targets_export", rtExport); + } + if (!rtGlobal.isEmpty()) + { + stackParams.put ("route_targets", rtGlobal); + } + } + if (commonUtils.isNullOrEmpty(shared)) { + stackParams.put ("shared", "False"); + } else { + stackParams.put ("shared", shared); + } + if (commonUtils.isNullOrEmpty(external)) { + stackParams.put ("external", "False"); + } else { + stackParams.put ("external", external); + } + return stackParams; + } + + + + /** policyRef_list structure in stackParams + [ + { + "network_policy_refs_data_sequence": { + "network_policy_refs_data_sequence_major": "1", + "network_policy_refs_data_sequence_minor": "0" + } + }, + { + "network_policy_refs_data_sequence": { + "network_policy_refs_data_sequence_major": "2", + "network_policy_refs_data_sequence_minor": "0" + } + } + ] + **/ + private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException { + //Resource Property + List<ContrailPolicyRef> prlist = new ArrayList <> (); + int index = 1; + for (String pf : pFqdns) { + if (!commonUtils.isNullOrEmpty(pf)) + { + ContrailPolicyRef pr = new ContrailPolicyRef(); + ContrailPolicyRefSeq refSeq = new ContrailPolicyRefSeq(String.valueOf(index), "0"); + pr.setSeq(refSeq); + index++; + LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString()); + prlist.add(pr); + } + } + + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(prlist, JsonNode.class); + String jsonString = mapper.writeValueAsString(prlist); + LOGGER.debug("Json PolicyRefs Data:" + jsonString); + } + catch (Exception e) + { + String error = "Error creating JsonNode for policyRefs Data"; + LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e); + throw new MsoAdapterException (error); + } + //update parameters + if (pFqdns != null && node != null) + { + StringBuilder buf = new StringBuilder (); + String sep = ""; + for (String pf : pFqdns) { + if (!commonUtils.isNullOrEmpty(pf)) + { + buf.append (sep).append (pf); + sep = ","; + } + } + String csl = buf.toString (); + stackParams.put ("policy_refs", csl); + stackParams.put ("policy_refsdata", node); + } + + LOGGER.debug ("StackParams updated with policy refs"); + return; + } + + private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException { + + //update parameters + if (rtFqdns != null) + { + StringBuilder buf = new StringBuilder (); + String sep = ""; + for (String rtf : rtFqdns) { + if (!commonUtils.isNullOrEmpty(rtf)) + { + buf.append (sep).append (rtf); + sep = ","; + } + } + String csl = buf.toString (); + stackParams.put ("route_table_refs", csl); + } + + LOGGER.debug ("StackParams updated with route_table refs"); + return; + } + + + /*** Subnet Output structure from Juniper + { + "ipam_subnets": [ + { + "subnet": { + "ip_prefix": "10.100.1.0", + "ip_prefix_len": 28 + }, + "addr_from_start": null, + "enable_dhcp": false, + "default_gateway": "10.100.1.1", + "dns_nameservers": [], + "dhcp_option_list": null, + "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf", + "allocation_pools": [ + { + "start": "10.100.1.3", + "end": "10.100.1.5" + }, + { + "start": "10.100.1.6", + "end": "10.100.1.9" + } + ], + "host_routes": null, + "dns_server_address": "10.100.1.13", + "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0" + }, + { + "subnet": { + "ip_prefix": "10.100.2.16", + "ip_prefix_len": 28 + }, + "addr_from_start": null, + "enable_dhcp": true, + "default_gateway": "10.100.2.17", + "dns_nameservers": [], + "dhcp_option_list": null, + "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6", + "allocation_pools": [ + { + "start": "10.100.2.18", + "end": "10.100.2.20" + } + ], + "host_routes": null, + "dns_server_address": "10.100.2.29", + "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1" + } + ], + "host_routes": null + } + ***/ + private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException { + + //Resource Property + List<ContrailSubnet> cslist = new ArrayList <> (); + for (Subnet subnet : subnets) { + LOGGER.debug("Input Subnet:" + subnet.toString()); + ContrailSubnet cs = new ContrailSubnetMapper(subnet).map(); + LOGGER.debug("Contrail Subnet:" + cs.toString()); + cslist.add(cs); + } + + JsonNode node = null; + try + { + ObjectMapper mapper = new ObjectMapper(); + node = mapper.convertValue(cslist, JsonNode.class); + String jsonString = mapper.writeValueAsString(cslist); + LOGGER.debug("Json Subnet List:" + jsonString); + } + catch (Exception e) + { + String error = "Error creating JsonNode from input subnets"; + LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e); + throw new MsoAdapterException (error); + } + //update parameters + if (node != null) + { + stackParams.put ("subnet_list", node); + } + //Outputs - All subnets are in one ipam_subnets structure + String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n" + + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n"; + + // append outputs in heatTemplate + int outputsIdx = heatTemplate.indexOf ("outputs:"); + heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8); + LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate); + return heatTemplate; + } + + + private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException { + + String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n" + + " properties:\n" + + " name: %name%\n" + + " network_id: { get_resource: network }\n" + + " cidr: %cidr%\n"; + + /* make these optional + + " ip_version: %ipversion%\n" + + " enable_dhcp: %enabledhcp%\n" + + " gateway_ip: %gatewayip%\n" + + " allocation_pools:\n" + + " - start: %poolstart%\n" + + " end: %poolend%\n"; + + */ + + String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n" + + " value: {get_resource: subnet_%subnetId%}\n"; + + String curR; + String curO; + StringBuilder resourcesBuf = new StringBuilder (); + StringBuilder outputsBuf = new StringBuilder (); + for (Subnet subnet : subnets) { + + // build template for each subnet + curR = resourceTempl; + if (subnet.getSubnetId () != null) { + curR = curR.replace ("%subnetId%", subnet.getSubnetId ()); + } else { + String error = "Missing Required AAI SubnetId for subnet in HEAT Template"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID for subnet in HEAT Template"); + throw new MsoAdapterException (error); + } + + if (subnet.getSubnetName () != null) { + curR = curR.replace ("%name%", subnet.getSubnetName ()); + } else { + curR = curR.replace ("%name%", subnet.getSubnetId ()); + } + + if (subnet.getCidr () != null) { + curR = curR.replace ("%cidr%", subnet.getCidr ()); + } else { + String error = "Missing Required cidr for subnet in HEAT Template"; + LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template"); + throw new MsoAdapterException (error); + } + + if (subnet.getIpVersion () != null) { + curR = curR + " ip_version: " + subnet.getIpVersion () + "\n"; + } + if (subnet.getEnableDHCP () != null) { + curR = curR + " enable_dhcp: " + Boolean.toString (subnet.getEnableDHCP ()) + "\n"; + } + if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) { + curR = curR + " gateway_ip: " + subnet.getGatewayIp () + "\n"; + } + + if (subnet.getAllocationPools() != null) { + curR = curR + " allocation_pools:\n"; + for (Pool pool : subnet.getAllocationPools()) + { + if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd())) + { + curR = curR + " - start: " + pool.getStart () + "\n"; + curR = curR + " end: " + pool.getEnd () + "\n"; + } + } + } + + resourcesBuf.append (curR); + + curO = outputTempl; + curO = curO.replace ("%subnetId%", subnet.getSubnetId ()); + + outputsBuf.append (curO); + + } + // append resources and outputs in heatTemplate + LOGGER.debug ("Tempate initial:" + heatTemplate); + int outputsIdx = heatTemplate.indexOf ("outputs:"); + heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8); + int resourcesIdx = heatTemplate.indexOf ("resources:"); + heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10); + + LOGGER.debug ("Template updated with all subnets:" + heatTemplate); + return heatTemplate; + } + + private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) { + + Map <String, String> sMap = new HashMap <> (); + + try{ + Object obj = outputs.get(key); + ObjectMapper mapper = new ObjectMapper(); + String jStr = mapper.writeValueAsString(obj); + LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr); + + JsonNode rootNode = mapper.readTree(jStr); + for (JsonNode sNode : rootNode.path("ipam_subnets")) + { + LOGGER.debug("Output Subnet Node" + sNode.toString()); + String name = sNode.path("subnet_name").textValue(); + String uuid = sNode.path("subnet_uuid").textValue(); + String aaiId = name; // default + // try to find aaiId for name in input subnetList + if (subnets != null) + { + for (Subnet subnet : subnets) + { + if ( subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName())) + { + if (subnet.getSubnetName().equals(name)) + { + aaiId = subnet.getSubnetId(); + break; + } + } + } + } + sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map + } + } + catch (Exception e) + { + LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e); + } + + LOGGER.debug ("Return sMap" + sMap.toString()); + return sMap; + } + + private static String insertStr (String template, String snippet, int index) { + + String updatedTemplate; + + LOGGER.debug ("Index:" + index + " Snippet:" + snippet); + + String templateBeg = template.substring (0, index); + String templateEnd = template.substring (index); + + updatedTemplate = templateBeg + "\n" + snippet + templateEnd; + + LOGGER.debug ("Template updated with a subnet:" + updatedTemplate); + return updatedTemplate; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java new file mode 100644 index 0000000000..465fb6d866 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java @@ -0,0 +1,671 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.network; + + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Provider; +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.onap.so.adapters.network.exceptions.NetworkException; +import org.onap.so.adapters.nwrest.ContrailNetwork; +import org.onap.so.adapters.nwrest.CreateNetworkError; +import org.onap.so.adapters.nwrest.CreateNetworkRequest; +import org.onap.so.adapters.nwrest.CreateNetworkResponse; +import org.onap.so.adapters.nwrest.DeleteNetworkError; +import org.onap.so.adapters.nwrest.DeleteNetworkRequest; +import org.onap.so.adapters.nwrest.DeleteNetworkResponse; +import org.onap.so.adapters.nwrest.ProviderVlanNetwork; +import org.onap.so.adapters.nwrest.QueryNetworkError; +import org.onap.so.adapters.nwrest.QueryNetworkResponse; +import org.onap.so.adapters.nwrest.RollbackNetworkError; +import org.onap.so.adapters.nwrest.RollbackNetworkRequest; +import org.onap.so.adapters.nwrest.RollbackNetworkResponse; +import org.onap.so.adapters.nwrest.UpdateNetworkError; +import org.onap.so.adapters.nwrest.UpdateNetworkRequest; +import org.onap.so.adapters.nwrest.UpdateNetworkResponse; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.NetworkRollback; +import org.onap.so.openstack.beans.NetworkStatus; +import org.onap.so.openstack.beans.RouteTarget; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +@Path("/v1/networks") +@Api(value = "/v1/networks", description = "root of network adapters restful web service") +@Component +@Transactional +public class NetworkAdapterRest { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,NetworkAdapterRest.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + + + @Autowired + private MsoNetworkAdapterImpl adapter; + @Autowired + @Qualifier("NetworkBpel") + private Provider<BpelRestClient> bpelRestClientProvider; + + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateNetwork", + response = Response.class, + notes = "Creates a new network, CreateNetworkRquest JSON is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "network has been successfully created"), + @ApiResponse(code = 202, message = "create network request has been accepted (async only)"), + @ApiResponse(code = 500, message = "create network failed, examine entity object for details") }) + public Response createNetwork( + @ApiParam(value = "details of network being created", required = true) + CreateNetworkRequest req) { + LOGGER.debug("createNetwork enter: " + req.toJsonString()); + CreateNetworkTask task = new CreateNetworkTask(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_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while create network", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("createNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class CreateNetworkTask implements Runnable { + private final CreateNetworkRequest req; + private CreateNetworkResponse response = null; + private CreateNetworkError eresp = null; + private boolean sendxml; + + public CreateNetworkTask(CreateNetworkRequest 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<CreateNetworkResponse>(response) {} + : new GenericEntity<CreateNetworkError>(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 ("CreateNetworkTask start"); + try { + // Synchronous Web Service Outputs + Holder<String> networkId = new Holder<>(); + Holder<String> neutronNetworkId = new Holder<>(); + Holder<String> networkFqdn = new Holder<>(); + Holder<Map<String, String>> subnetIdMap = new Holder<>(); + Holder<NetworkRollback> rollback = new Holder<>(); + + String cloudsite = req.getCloudSiteId(); + if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) { + String tenant = req.getTenantId(); + if (tenant != null && tenant.equals(TESTING_KEYWORD)) { + throw new NetworkException("testing."); + } + networkId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + neutronNetworkId.value = "55e55884-28fa-11e6-8971-0017f20fe1b8"; + networkFqdn.value = "086f70b6-28fb-11e6-8260-0017f20fe1b8"; + subnetIdMap.value = testMap(); + rollback.value = new NetworkRollback(); + } else if (req.isContrailRequest()) { + ContrailNetwork ctn = req.getContrailNetwork(); + if (ctn == null) { + ctn = new ContrailNetwork(); + req.setContrailNetwork(ctn); + } + adapter.createNetworkContrail( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkName(), + req.getContrailNetwork().getRouteTargets(), + req.getContrailNetwork().getShared(), + req.getContrailNetwork().getExternal(), + req.getFailIfExists(), + req.getBackout(), + req.getSubnets(), + req.getContrailNetwork().getPolicyFqdns(), + req.getContrailNetwork().getRouteTableFqdns(), + req.getMsoRequest(), + networkId, + neutronNetworkId, + networkFqdn, + subnetIdMap, + rollback); + } else { + ProviderVlanNetwork pvn = req.getProviderVlanNetwork(); + if (pvn == null) { + pvn = new ProviderVlanNetwork(); + req.setProviderVlanNetwork(pvn); + } + adapter.createNetwork( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkName(), + req.getProviderVlanNetwork().getPhysicalNetworkName(), + req.getProviderVlanNetwork().getVlans(), + req.getFailIfExists(), + req.getBackout(), + req.getSubnets(), + req.getMsoRequest(), + networkId, + neutronNetworkId, + subnetIdMap, + rollback); + } + response = new CreateNetworkResponse( + req.getNetworkId(), + neutronNetworkId.value, + rollback.value.getNetworkStackId(), + networkFqdn.value, + rollback.value.getNetworkCreated(), + subnetIdMap.value, + rollback.value, + req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new CreateNetworkError( + e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiNetworkId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteNetwork", + response = Response.class, + notes = "Deletes an existing network, aaiNetworkId and DeleteNetworkRequest JSON are required") + @ApiResponses({ + @ApiResponse(code = 200, message = "network has been successfully deleted"), + @ApiResponse(code = 202, message = "request to delete network has been accepted (async only)"), + @ApiResponse(code = 500, message = "delete network failed, examine entity object for details") }) + public Response deleteNetwork( + @ApiParam(value = "aaiNetworkId to be deleted ", required = true) + @PathParam("aaiNetworkId") String aaiNetworkId, + @ApiParam(value = "details of network being deleted", required = true) + DeleteNetworkRequest req) + { + LOGGER.debug("deleteNetwork enter: " + req.toJsonString()); + if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")") + .build(); + } + DeleteNetworkTask task = new DeleteNetworkTask(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_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while delete network", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("deleteNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class DeleteNetworkTask implements Runnable { + private final DeleteNetworkRequest req; + private DeleteNetworkResponse response = null; + private DeleteNetworkError eresp = null; + private boolean sendxml; + + public DeleteNetworkTask(DeleteNetworkRequest 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<DeleteNetworkResponse>(response) {} + : new GenericEntity<DeleteNetworkError>(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("DeleteNetworkTask start"); + try { + Holder<Boolean> networkDeleted = new Holder<>(); + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + networkDeleted.value = true; + } else { + adapter.deleteNetwork( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkStackId(), + req.getMsoRequest(), + networkDeleted); + } + response = new DeleteNetworkResponse(req.getNetworkId(), networkDeleted.value, req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new DeleteNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiNetworkId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryNetwork", + response = Response.class, + notes = "Queries an existing network") + @ApiResponses({ + @ApiResponse(code = 200, message = "Query network successful"), + @ApiResponse(code = 500, message = "Query network failed, examine entity object for details") }) + public Response queryNetwork( + @ApiParam(value = "cloudSiteId", required = false) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = false) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "networkStackId", required = false) + @QueryParam("networkStackId") String networkStackId, + @ApiParam(value = "skipAAI", required = false) + @QueryParam("skipAAI") String skipAAI, + @ApiParam(value = "msoRequest.requestId", required = false) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = false) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, + @ApiParam(value = "aaiNetworkId", required = false) + @PathParam("aaiNetworkId") String aaiNetworkId) + { + //This request responds synchronously only + LOGGER.debug ("Query network enter:" + aaiNetworkId); + MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); + + try { + int respStatus = HttpStatus.SC_OK; + QueryNetworkResponse resp = new QueryNetworkResponse(networkStackId, null, networkStackId, null, null); + Holder<Boolean> networkExists = new Holder<>(); + Holder<String> networkId = new Holder<>(); + Holder<String> neutronNetworkId = new Holder<>(); + Holder<NetworkStatus> status = new Holder<>(); + Holder<List<RouteTarget>> routeTargets = new Holder<>(); + Holder<Map<String, String>> subnetIdMap = new Holder<>(); + + adapter.queryNetworkContrail(cloudSiteId, tenantId, aaiNetworkId, msoRequest, + networkExists, networkId, neutronNetworkId, status, routeTargets, subnetIdMap); + + if (!networkExists.value) { + LOGGER.debug ("network not found"); + respStatus = HttpStatus.SC_NOT_FOUND; + } else { + LOGGER.debug ("network found" + networkId.value + ", status=" + status.value); + resp.setNetworkExists(networkExists.value); + resp.setNetworkId(networkId.value); + resp.setNeutronNetworkId(neutronNetworkId.value); + resp.setNetworkStatus(status.value); + resp.setRouteTargets(routeTargets.value); + resp.setSubnetIdMap(subnetIdMap.value); + } + LOGGER.debug ("Query network exit"); + return Response + .status(respStatus) + .entity(new GenericEntity<QueryNetworkResponse>(resp) {}) + .build(); + } catch (NetworkException e) { + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, aaiNetworkId, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception when query VNF", e); + QueryNetworkError err = new QueryNetworkError(); + err.setMessage(e.getMessage()); + err.setCategory(MsoExceptionCategory.INTERNAL); + return Response + .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) + .entity(new GenericEntity<QueryNetworkError>(err) {}) + .build(); + } + } + + @DELETE + @Path("{aaiNetworkId}/rollback") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackNetwork", + response = Response.class, + notes = "Rollback an existing network") + @ApiResponses({ + @ApiResponse(code = 200, message = "Rollback network successful"), + @ApiResponse(code = 202, message = "Rollback network request has been accepted (async only)"), + @ApiResponse(code = 500, message = "Rollback network failed, examine entity object for details") }) + public Response rollbackNetwork( + @ApiParam(value = "RollbackNetworkRequest in JSON format", required = true) + RollbackNetworkRequest req) + { + LOGGER.debug("rollbackNetwork enter: " + req.toJsonString()); + RollbackNetworkTask task = new RollbackNetworkTask(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_NULL, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in rollbackNetwork", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug("rollbackNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class RollbackNetworkTask implements Runnable { + private final RollbackNetworkRequest req; + private RollbackNetworkResponse response = null; + private RollbackNetworkError eresp = null; + private boolean sendxml; + + public RollbackNetworkTask(RollbackNetworkRequest 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<RollbackNetworkResponse>(response) {} + : new GenericEntity<RollbackNetworkError>(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("RollbackNetworkTask start"); + try { + NetworkRollback nwr = req.getNetworkRollback(); + adapter.rollbackNetwork(nwr); + response = new RollbackNetworkResponse(true, req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new RollbackNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("RollbackNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @PUT + @Path("{aaiNetworkId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "UpdateNetwork", + response = Response.class, + notes = "Update an existing network") + @ApiResponses({ + @ApiResponse(code = 200, message = "Update network successful"), + @ApiResponse(code = 202, message = "Update network request has been accepted (async only)"), + @ApiResponse(code = 500, message = "Update network failed, examine entity object for details") }) + public Response updateNetwork( + @ApiParam(value = "aaiNetworkId", required = true) + @PathParam("aaiNetworkId") String aaiNetworkId, + @ApiParam(value = "UpdateNetworkRequest in JSON format", required = true) + UpdateNetworkRequest req) + { + LOGGER.debug("updateNetwork enter: " + req.toJsonString()); + if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) { + return Response + .status(HttpStatus.SC_BAD_REQUEST) + .type(MediaType.TEXT_PLAIN) + .entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")") + .build(); + } + UpdateNetworkTask task = new UpdateNetworkTask(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_NETWORK_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in updateNetwork", e); + return Response.serverError().build(); + } + // send sync response (ACK) to caller + LOGGER.debug ("updateNetwork exit"); + return Response.status(HttpStatus.SC_ACCEPTED).build(); + } + } + + public class UpdateNetworkTask implements Runnable { + private final UpdateNetworkRequest req; + private UpdateNetworkResponse response = null; + private UpdateNetworkError eresp = null; + private boolean sendxml; + + public UpdateNetworkTask(UpdateNetworkRequest 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<UpdateNetworkResponse>(response) {} + : new GenericEntity<UpdateNetworkError>(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("UpdateNetworkTask start"); + try { + Holder<Map<String, String>> subnetIdMap = new Holder<>(); + Holder<NetworkRollback> rollback = new Holder<> (); + + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + subnetIdMap.value = testMap(); + NetworkRollback rb = new NetworkRollback (); + rb.setCloudId(req.getCloudSiteId()); + rb.setTenantId(req.getTenantId()); + rb.setMsoRequest(req.getMsoRequest()); + rollback.value = rb; + } else if (req.isContrailRequest()) { + ContrailNetwork ctn = req.getContrailNetwork(); + if (ctn == null) { + ctn = new ContrailNetwork(); + req.setContrailNetwork(ctn); + } + adapter.updateNetworkContrail( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkStackId(), + req.getNetworkName(), + req.getContrailNetwork().getRouteTargets(), + req.getContrailNetwork().getShared(), + req.getContrailNetwork().getExternal(), + req.getSubnets(), + req.getContrailNetwork().getPolicyFqdns(), + req.getContrailNetwork().getRouteTableFqdns(), + req.getMsoRequest(), + subnetIdMap, + rollback); + } else { + ProviderVlanNetwork pvn = req.getProviderVlanNetwork(); + if (pvn == null) { + pvn = new ProviderVlanNetwork(); + req.setProviderVlanNetwork(pvn); + } + adapter.updateNetwork( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getModelCustomizationUuid(), + req.getNetworkStackId(), + req.getNetworkName(), + req.getProviderVlanNetwork().getPhysicalNetworkName(), + req.getProviderVlanNetwork().getVlans(), + req.getSubnets(), + req.getMsoRequest(), + subnetIdMap, + rollback); + } + response = new UpdateNetworkResponse( + req.getNetworkId(), + null, // NeutronNetworkId is not available from an update + subnetIdMap.value, + req.getMessageId()); + } catch (NetworkException e) { + LOGGER.debug ("Exception:", e); + eresp = new UpdateNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + public static Map<String, String> testMap() { + Map<String, String> m = new HashMap<>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotification.java new file mode 100644 index 0000000000..8135088d7c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotification.java @@ -0,0 +1,437 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for createNetworkNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="createNetworkNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="networkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="neutronNetworkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="subnetIdMap" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <element name="rollback" type="{http://org.onap.so/networkNotify}networkRollback" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "createNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "networkId", + "neutronNetworkId", + "subnetIdMap", + "rollback" +}) +public class CreateNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected String networkId; + protected String neutronNetworkId; + protected CreateNetworkNotification.SubnetIdMap subnetIdMap; + protected NetworkRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the networkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkId() { + return networkId; + } + + /** + * Sets the value of the networkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkId(String value) { + this.networkId = value; + } + + /** + * Gets the value of the neutronNetworkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNeutronNetworkId() { + return neutronNetworkId; + } + + /** + * Sets the value of the neutronNetworkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNeutronNetworkId(String value) { + this.neutronNetworkId = value; + } + + /** + * Gets the value of the subnetIdMap property. + * + * @return + * possible object is + * {@link CreateNetworkNotification.SubnetIdMap } + * + */ + public CreateNetworkNotification.SubnetIdMap getSubnetIdMap() { + return subnetIdMap; + } + + /** + * Sets the value of the subnetIdMap property. + * + * @param value + * allowed object is + * {@link CreateNetworkNotification.SubnetIdMap } + * + */ + public void setSubnetIdMap(CreateNetworkNotification.SubnetIdMap value) { + this.subnetIdMap = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link NetworkRollback } + * + */ + public NetworkRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link NetworkRollback } + * + */ + public void setRollback(NetworkRollback value) { + this.rollback = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class SubnetIdMap { + + protected List<CreateNetworkNotification.SubnetIdMap.Entry> entry; + + /** + * Gets the value of the entry property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the entry property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getEntry().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link CreateNetworkNotification.SubnetIdMap.Entry } + * + * + */ + public List<CreateNetworkNotification.SubnetIdMap.Entry> getEntry() { + if (entry == null) { + entry = new ArrayList<CreateNetworkNotification.SubnetIdMap.Entry>(); + } + return this.entry; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotificationResponse.java new file mode 100644 index 0000000000..a0e40c0e6a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/CreateNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for createNetworkNotificationResponse complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="createNetworkNotificationResponse"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "createNetworkNotificationResponse") +public class CreateNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotification.java new file mode 100644 index 0000000000..d4f992a9b4 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotification.java @@ -0,0 +1,181 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for deleteNetworkNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="deleteNetworkNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="networkDeleted" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "deleteNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "networkDeleted" +}) +public class DeleteNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected Boolean networkDeleted; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the networkDeleted property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isNetworkDeleted() { + return networkDeleted; + } + + /** + * Sets the value of the networkDeleted property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setNetworkDeleted(Boolean value) { + this.networkDeleted = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotificationResponse.java new file mode 100644 index 0000000000..76eb8115d5 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/DeleteNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for deleteNetworkNotificationResponse complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="deleteNetworkNotificationResponse"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "deleteNetworkNotificationResponse") +public class DeleteNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoExceptionCategory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoExceptionCategory.java new file mode 100644 index 0000000000..8c18a59e68 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoExceptionCategory.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for msoExceptionCategory. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * <p> + * <pre> + * <simpleType name="msoExceptionCategory"> + * <restriction base="{http://www.w3.org/2001/XMLSchema}string"> + * <enumeration value="OPENSTACK"/> + * <enumeration value="IO"/> + * <enumeration value="INTERNAL"/> + * <enumeration value="USERDATA"/> + * </restriction> + * </simpleType> + * </pre> + * + */ +@XmlType(name = "msoExceptionCategory") +@XmlEnum +public enum MsoExceptionCategory { + + OPENSTACK, + IO, + INTERNAL, + USERDATA; + + public String value() { + return name(); + } + + public static MsoExceptionCategory fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoRequest.java new file mode 100644 index 0000000000..aa6f34f2e0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/MsoRequest.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for msoRequest complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="msoRequest"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="requestId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="serviceInstanceId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "msoRequest", propOrder = { + "requestId", + "serviceInstanceId" +}) +public class MsoRequest { + + protected String requestId; + protected String serviceInstanceId; + + /** + * Gets the value of the requestId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRequestId() { + return requestId; + } + + /** + * Sets the value of the requestId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRequestId(String value) { + this.requestId = value; + } + + /** + * Gets the value of the serviceInstanceId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getServiceInstanceId() { + return serviceInstanceId; + } + + /** + * Sets the value of the serviceInstanceId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setServiceInstanceId(String value) { + this.serviceInstanceId = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify.java new file mode 100644 index 0000000000..0433aab0cc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify.java @@ -0,0 +1,191 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import java.util.List; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.Action; +import javax.xml.ws.RequestWrapper; +import javax.xml.ws.ResponseWrapper; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebService(name = "networkAdapterNotify", targetNamespace = "http://org.onap.so/networkNotify") +@XmlSeeAlso({ + ObjectFactory.class +}) +public interface NetworkAdapterNotify { + + + /** + * + * @param exception + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @RequestWrapper(localName = "rollbackNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.RollbackNetworkNotification") + @ResponseWrapper(localName = "rollbackNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.RollbackNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/rollbackNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/rollbackNetworkNotificationResponse") + public void rollbackNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage); + + /** + * + * @param exception + * @param vlans + * @param networkExists + * @param errorMessage + * @param messageId + * @param networkId + * @param completed + * @param neutronNetworkId + * @param status + * @param subnetIdMap + */ + @WebMethod + @RequestWrapper(localName = "queryNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.QueryNetworkNotification") + @ResponseWrapper(localName = "queryNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.QueryNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/queryNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/queryNetworkNotificationResponse") + public void queryNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "networkExists", targetNamespace = "") + Boolean networkExists, + @WebParam(name = "networkId", targetNamespace = "") + String networkId, + @WebParam(name = "neutronNetworkId", targetNamespace = "") + String neutronNetworkId, + @WebParam(name = "status", targetNamespace = "") + NetworkStatus status, + @WebParam(name = "vlans", targetNamespace = "") + List<Integer> vlans, + @WebParam(name = "subnetIdMap", targetNamespace = "") + org.onap.so.adapters.network.async.client.QueryNetworkNotification.SubnetIdMap subnetIdMap); + + /** + * + * @param exception + * @param rollback + * @param errorMessage + * @param messageId + * @param networkId + * @param completed + * @param neutronNetworkId + * @param subnetIdMap + */ + @WebMethod + @RequestWrapper(localName = "createNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.CreateNetworkNotification") + @ResponseWrapper(localName = "createNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.CreateNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/createNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/createNetworkNotificationResponse") + public void createNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "networkId", targetNamespace = "") + String networkId, + @WebParam(name = "neutronNetworkId", targetNamespace = "") + String neutronNetworkId, + @WebParam(name = "subnetIdMap", targetNamespace = "") + org.onap.so.adapters.network.async.client.CreateNetworkNotification.SubnetIdMap subnetIdMap, + @WebParam(name = "rollback", targetNamespace = "") + NetworkRollback rollback); + + /** + * + * @param exception + * @param networkDeleted + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @RequestWrapper(localName = "deleteNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.DeleteNetworkNotification") + @ResponseWrapper(localName = "deleteNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.DeleteNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/deleteNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/deleteNetworkNotificationResponse") + public void deleteNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "networkDeleted", targetNamespace = "") + Boolean networkDeleted); + + /** + * + * @param exception + * @param rollback + * @param errorMessage + * @param messageId + * @param completed + * @param subnetIdMap + */ + @WebMethod + @RequestWrapper(localName = "updateNetworkNotification", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.UpdateNetworkNotification") + @ResponseWrapper(localName = "updateNetworkNotificationResponse", targetNamespace = "http://org.onap.so/networkNotify", className = "org.onap.so.adapters.network.async.client.UpdateNetworkNotificationResponse") + @Action(input = "http://org.onap.so/notify/adapterNotify/updateNetworkNotificationRequest", output = "http://org.onap.so/notify/adapterNotify/updateNetworkNotificationResponse") + public void updateNetworkNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "subnetIdMap", targetNamespace = "") + org.onap.so.adapters.network.async.client.UpdateNetworkNotification.SubnetIdMap subnetIdMap, + @WebParam(name = "rollback", targetNamespace = "") + NetworkRollback rollback); + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify_Service.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify_Service.java new file mode 100644 index 0000000000..fb69db702a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkAdapterNotify_Service.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import java.net.URL; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.WebServiceFeature; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebServiceClient(name = "networkAdapterNotify", targetNamespace = "http://org.onap.so/networkNotify", wsdlLocation = "/NetworkAdapterNotify.wsdl") +public class NetworkAdapterNotify_Service + extends Service +{ + + private final static URL NETWORKADAPTERNOTIFY_WSDL_LOCATION; + private final static WebServiceException NETWORKADAPTERNOTIFY_EXCEPTION; + private final static QName NETWORKADAPTERNOTIFY_QNAME = new QName("http://org.onap.so/networkNotify", "networkAdapterNotify"); + + static { + NETWORKADAPTERNOTIFY_WSDL_LOCATION = org.onap.so.adapters.network.async.client.NetworkAdapterNotify_Service.class.getResource("/NetworkAdapterNotify.wsdl"); + WebServiceException e = null; + if (NETWORKADAPTERNOTIFY_WSDL_LOCATION == null) { + e = new WebServiceException("Cannot find '/NetworkAdapterNotify.wsdl' wsdl. Place the resource correctly in the classpath."); + } + NETWORKADAPTERNOTIFY_EXCEPTION = e; + } + + public NetworkAdapterNotify_Service() { + super(__getWsdlLocation(), NETWORKADAPTERNOTIFY_QNAME); + } + + public NetworkAdapterNotify_Service(WebServiceFeature... features) { + super(__getWsdlLocation(), NETWORKADAPTERNOTIFY_QNAME, features); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation) { + super(wsdlLocation, NETWORKADAPTERNOTIFY_QNAME); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation, WebServiceFeature... features) { + super(wsdlLocation, NETWORKADAPTERNOTIFY_QNAME, features); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public NetworkAdapterNotify_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { + super(wsdlLocation, serviceName, features); + } + + /** + * + * @return + * returns NetworkAdapterNotify + */ + @WebEndpoint(name = "MsoNetworkAdapterAsyncImplPort") + public NetworkAdapterNotify getMsoNetworkAdapterAsyncImplPort() { + return super.getPort(new QName("http://org.onap.so/networkNotify", "MsoNetworkAdapterAsyncImplPort"), NetworkAdapterNotify.class); + } + + /** + * + * @param features + * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values. + * @return + * returns NetworkAdapterNotify + */ + @WebEndpoint(name = "MsoNetworkAdapterAsyncImplPort") + public NetworkAdapterNotify getMsoNetworkAdapterAsyncImplPort(WebServiceFeature... features) { + return super.getPort(new QName("http://org.onap.so/networkNotify", "MsoNetworkAdapterAsyncImplPort"), NetworkAdapterNotify.class, features); + } + + private static URL __getWsdlLocation() { + if (NETWORKADAPTERNOTIFY_EXCEPTION!= null) { + throw NETWORKADAPTERNOTIFY_EXCEPTION; + } + return NETWORKADAPTERNOTIFY_WSDL_LOCATION; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkRollback.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkRollback.java new file mode 100644 index 0000000000..4fde850a53 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkRollback.java @@ -0,0 +1,370 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for networkRollback complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="networkRollback"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="cloudId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="msoRequest" type="{http://org.onap.so/networkNotify}msoRequest" minOccurs="0"/> + * <element name="networkCreated" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="networkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="networkStackId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="networkName" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="networkType" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="networkUpdated" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="neutronNetworkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="physicalNetwork" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="tenantId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="vlans" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "networkRollback", propOrder = { + "cloudId", + "msoRequest", + "networkCreated", + "networkId", + "networkStackId", + "networkName", + "networkType", + "networkUpdated", + "neutronNetworkId", + "physicalNetwork", + "tenantId", + "vlans" +}) +public class NetworkRollback { + + protected String cloudId; + protected MsoRequest msoRequest; + protected boolean networkCreated; + protected String networkId; + protected String networkStackId; + protected String networkName; + protected String networkType; + protected boolean networkUpdated; + protected String neutronNetworkId; + protected String physicalNetwork; + protected String tenantId; + @XmlElement(nillable = true) + protected List<Integer> vlans; + + /** + * Gets the value of the cloudId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCloudId() { + return cloudId; + } + + /** + * Sets the value of the cloudId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCloudId(String value) { + this.cloudId = value; + } + + /** + * Gets the value of the msoRequest property. + * + * @return + * possible object is + * {@link MsoRequest } + * + */ + public MsoRequest getMsoRequest() { + return msoRequest; + } + + /** + * Sets the value of the msoRequest property. + * + * @param value + * allowed object is + * {@link MsoRequest } + * + */ + public void setMsoRequest(MsoRequest value) { + this.msoRequest = value; + } + + /** + * Gets the value of the networkCreated property. + * + */ + public boolean isNetworkCreated() { + return networkCreated; + } + + /** + * Sets the value of the networkCreated property. + * + */ + public void setNetworkCreated(boolean value) { + this.networkCreated = value; + } + + /** + * Gets the value of the networkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkId() { + return networkId; + } + + /** + * Sets the value of the networkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkId(String value) { + this.networkId = value; + } + + /** + * Gets the value of the networkStackId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkStackId() { + return networkStackId; + } + + /** + * Sets the value of the networkStackId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkStackId(String value) { + this.networkStackId = value; + } + + /** + * Gets the value of the networkName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkName() { + return networkName; + } + + /** + * Sets the value of the networkName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkName(String value) { + this.networkName = value; + } + + /** + * Gets the value of the networkType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkType() { + return networkType; + } + + /** + * Sets the value of the networkType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkType(String value) { + this.networkType = value; + } + + /** + * Gets the value of the networkUpdated property. + * + */ + public boolean isNetworkUpdated() { + return networkUpdated; + } + + /** + * Sets the value of the networkUpdated property. + * + */ + public void setNetworkUpdated(boolean value) { + this.networkUpdated = value; + } + + /** + * Gets the value of the neutronNetworkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNeutronNetworkId() { + return neutronNetworkId; + } + + /** + * Sets the value of the neutronNetworkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNeutronNetworkId(String value) { + this.neutronNetworkId = value; + } + + /** + * Gets the value of the physicalNetwork property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getPhysicalNetwork() { + return physicalNetwork; + } + + /** + * Sets the value of the physicalNetwork property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setPhysicalNetwork(String value) { + this.physicalNetwork = value; + } + + /** + * Gets the value of the tenantId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTenantId() { + return tenantId; + } + + /** + * Sets the value of the tenantId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTenantId(String value) { + this.tenantId = value; + } + + /** + * Gets the value of the vlans property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the vlans property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getVlans().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link Integer } + * + * + */ + public List<Integer> getVlans() { + if (vlans == null) { + vlans = new ArrayList<Integer>(); + } + return this.vlans; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkStatus.java new file mode 100644 index 0000000000..982f214bd8 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/NetworkStatus.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for networkStatus. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * <p> + * <pre> + * <simpleType name="networkStatus"> + * <restriction base="{http://www.w3.org/2001/XMLSchema}string"> + * <enumeration value="NOTFOUND"/> + * <enumeration value="ACTIVE"/> + * <enumeration value="DOWN"/> + * <enumeration value="BUILD"/> + * <enumeration value="ERROR"/> + * <enumeration value="UNKNOWN"/> + * </restriction> + * </simpleType> + * </pre> + * + */ +@XmlType(name = "networkStatus") +@XmlEnum +public enum NetworkStatus { + + NOTFOUND, + ACTIVE, + DOWN, + BUILD, + ERROR, + UNKNOWN; + + public String value() { + return name(); + } + + public static NetworkStatus fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/ObjectFactory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/ObjectFactory.java new file mode 100644 index 0000000000..91243769aa --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/ObjectFactory.java @@ -0,0 +1,298 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.onap.so.adapters.network.async.client package. + * <p>An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _RollbackNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "rollbackNetworkNotification"); + private final static QName _UpdateNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "updateNetworkNotification"); + private final static QName _QueryNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "queryNetworkNotificationResponse"); + private final static QName _UpdateNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "updateNetworkNotificationResponse"); + private final static QName _CreateNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "createNetworkNotificationResponse"); + private final static QName _DeleteNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "deleteNetworkNotification"); + private final static QName _DeleteNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "deleteNetworkNotificationResponse"); + private final static QName _CreateNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "createNetworkNotification"); + private final static QName _QueryNetworkNotification_QNAME = new QName("http://org.onap.so/networkNotify", "queryNetworkNotification"); + private final static QName _RollbackNetworkNotificationResponse_QNAME = new QName("http://org.onap.so/networkNotify", "rollbackNetworkNotificationResponse"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.onap.so.adapters.network.async.client + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link QueryNetworkNotification } + * + */ + public QueryNetworkNotification createQueryNetworkNotification() { + return new QueryNetworkNotification(); + } + + /** + * Create an instance of {@link QueryNetworkNotification.SubnetIdMap } + * + */ + public QueryNetworkNotification.SubnetIdMap createQueryNetworkNotificationSubnetIdMap() { + return new QueryNetworkNotification.SubnetIdMap(); + } + + /** + * Create an instance of {@link CreateNetworkNotification } + * + */ + public CreateNetworkNotification createCreateNetworkNotification() { + return new CreateNetworkNotification(); + } + + /** + * Create an instance of {@link CreateNetworkNotification.SubnetIdMap } + * + */ + public CreateNetworkNotification.SubnetIdMap createCreateNetworkNotificationSubnetIdMap() { + return new CreateNetworkNotification.SubnetIdMap(); + } + + /** + * Create an instance of {@link UpdateNetworkNotification } + * + */ + public UpdateNetworkNotification createUpdateNetworkNotification() { + return new UpdateNetworkNotification(); + } + + /** + * Create an instance of {@link UpdateNetworkNotification.SubnetIdMap } + * + */ + public UpdateNetworkNotification.SubnetIdMap createUpdateNetworkNotificationSubnetIdMap() { + return new UpdateNetworkNotification.SubnetIdMap(); + } + + /** + * Create an instance of {@link UpdateNetworkNotificationResponse } + * + */ + public UpdateNetworkNotificationResponse createUpdateNetworkNotificationResponse() { + return new UpdateNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link CreateNetworkNotificationResponse } + * + */ + public CreateNetworkNotificationResponse createCreateNetworkNotificationResponse() { + return new CreateNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link RollbackNetworkNotification } + * + */ + public RollbackNetworkNotification createRollbackNetworkNotification() { + return new RollbackNetworkNotification(); + } + + /** + * Create an instance of {@link QueryNetworkNotificationResponse } + * + */ + public QueryNetworkNotificationResponse createQueryNetworkNotificationResponse() { + return new QueryNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link RollbackNetworkNotificationResponse } + * + */ + public RollbackNetworkNotificationResponse createRollbackNetworkNotificationResponse() { + return new RollbackNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link DeleteNetworkNotification } + * + */ + public DeleteNetworkNotification createDeleteNetworkNotification() { + return new DeleteNetworkNotification(); + } + + /** + * Create an instance of {@link DeleteNetworkNotificationResponse } + * + */ + public DeleteNetworkNotificationResponse createDeleteNetworkNotificationResponse() { + return new DeleteNetworkNotificationResponse(); + } + + /** + * Create an instance of {@link NetworkRollback } + * + */ + public NetworkRollback createNetworkRollback() { + return new NetworkRollback(); + } + + /** + * Create an instance of {@link MsoRequest } + * + */ + public MsoRequest createMsoRequest() { + return new MsoRequest(); + } + + /** + * Create an instance of {@link QueryNetworkNotification.SubnetIdMap.Entry } + * + */ + public QueryNetworkNotification.SubnetIdMap.Entry createQueryNetworkNotificationSubnetIdMapEntry() { + return new QueryNetworkNotification.SubnetIdMap.Entry(); + } + + /** + * Create an instance of {@link CreateNetworkNotification.SubnetIdMap.Entry } + * + */ + public CreateNetworkNotification.SubnetIdMap.Entry createCreateNetworkNotificationSubnetIdMapEntry() { + return new CreateNetworkNotification.SubnetIdMap.Entry(); + } + + /** + * Create an instance of {@link UpdateNetworkNotification.SubnetIdMap.Entry } + * + */ + public UpdateNetworkNotification.SubnetIdMap.Entry createUpdateNetworkNotificationSubnetIdMapEntry() { + return new UpdateNetworkNotification.SubnetIdMap.Entry(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link RollbackNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "rollbackNetworkNotification") + public JAXBElement<RollbackNetworkNotification> createRollbackNetworkNotification(RollbackNetworkNotification value) { + return new JAXBElement<RollbackNetworkNotification>(_RollbackNetworkNotification_QNAME, RollbackNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link UpdateNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "updateNetworkNotification") + public JAXBElement<UpdateNetworkNotification> createUpdateNetworkNotification(UpdateNetworkNotification value) { + return new JAXBElement<UpdateNetworkNotification>(_UpdateNetworkNotification_QNAME, UpdateNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link QueryNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "queryNetworkNotificationResponse") + public JAXBElement<QueryNetworkNotificationResponse> createQueryNetworkNotificationResponse(QueryNetworkNotificationResponse value) { + return new JAXBElement<QueryNetworkNotificationResponse>(_QueryNetworkNotificationResponse_QNAME, QueryNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link UpdateNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "updateNetworkNotificationResponse") + public JAXBElement<UpdateNetworkNotificationResponse> createUpdateNetworkNotificationResponse(UpdateNetworkNotificationResponse value) { + return new JAXBElement<UpdateNetworkNotificationResponse>(_UpdateNetworkNotificationResponse_QNAME, UpdateNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link CreateNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "createNetworkNotificationResponse") + public JAXBElement<CreateNetworkNotificationResponse> createCreateNetworkNotificationResponse(CreateNetworkNotificationResponse value) { + return new JAXBElement<CreateNetworkNotificationResponse>(_CreateNetworkNotificationResponse_QNAME, CreateNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link DeleteNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "deleteNetworkNotification") + public JAXBElement<DeleteNetworkNotification> createDeleteNetworkNotification(DeleteNetworkNotification value) { + return new JAXBElement<DeleteNetworkNotification>(_DeleteNetworkNotification_QNAME, DeleteNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link DeleteNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "deleteNetworkNotificationResponse") + public JAXBElement<DeleteNetworkNotificationResponse> createDeleteNetworkNotificationResponse(DeleteNetworkNotificationResponse value) { + return new JAXBElement<DeleteNetworkNotificationResponse>(_DeleteNetworkNotificationResponse_QNAME, DeleteNetworkNotificationResponse.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link CreateNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "createNetworkNotification") + public JAXBElement<CreateNetworkNotification> createCreateNetworkNotification(CreateNetworkNotification value) { + return new JAXBElement<CreateNetworkNotification>(_CreateNetworkNotification_QNAME, CreateNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link QueryNetworkNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "queryNetworkNotification") + public JAXBElement<QueryNetworkNotification> createQueryNetworkNotification(QueryNetworkNotification value) { + return new JAXBElement<QueryNetworkNotification>(_QueryNetworkNotification_QNAME, QueryNetworkNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link RollbackNetworkNotificationResponse }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/networkNotify", name = "rollbackNetworkNotificationResponse") + public JAXBElement<RollbackNetworkNotificationResponse> createRollbackNetworkNotificationResponse(RollbackNetworkNotificationResponse value) { + return new JAXBElement<RollbackNetworkNotificationResponse>(_RollbackNetworkNotificationResponse_QNAME, RollbackNetworkNotificationResponse.class, null, value); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotification.java new file mode 100644 index 0000000000..55a8e3d0d1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotification.java @@ -0,0 +1,497 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for queryNetworkNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="queryNetworkNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="networkExists" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/> + * <element name="networkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="neutronNetworkId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="status" type="{http://org.onap.so/networkNotify}networkStatus" minOccurs="0"/> + * <element name="vlans" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/> + * <element name="subnetIdMap" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "queryNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "networkExists", + "networkId", + "neutronNetworkId", + "status", + "vlans", + "subnetIdMap" +}) +public class QueryNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected Boolean networkExists; + protected String networkId; + protected String neutronNetworkId; + protected NetworkStatus status; + @XmlElement(type = Integer.class) + protected List<Integer> vlans; + protected QueryNetworkNotification.SubnetIdMap subnetIdMap; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the networkExists property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isNetworkExists() { + return networkExists; + } + + /** + * Sets the value of the networkExists property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setNetworkExists(Boolean value) { + this.networkExists = value; + } + + /** + * Gets the value of the networkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNetworkId() { + return networkId; + } + + /** + * Sets the value of the networkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNetworkId(String value) { + this.networkId = value; + } + + /** + * Gets the value of the neutronNetworkId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getNeutronNetworkId() { + return neutronNetworkId; + } + + /** + * Sets the value of the neutronNetworkId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setNeutronNetworkId(String value) { + this.neutronNetworkId = value; + } + + /** + * Gets the value of the status property. + * + * @return + * possible object is + * {@link NetworkStatus } + * + */ + public NetworkStatus getStatus() { + return status; + } + + /** + * Sets the value of the status property. + * + * @param value + * allowed object is + * {@link NetworkStatus } + * + */ + public void setStatus(NetworkStatus value) { + this.status = value; + } + + /** + * Gets the value of the vlans property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the vlans property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getVlans().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link Integer } + * + * + */ + public List<Integer> getVlans() { + if (vlans == null) { + vlans = new ArrayList<Integer>(); + } + return this.vlans; + } + + /** + * Gets the value of the subnetIdMap property. + * + * @return + * possible object is + * {@link QueryNetworkNotification.SubnetIdMap } + * + */ + public QueryNetworkNotification.SubnetIdMap getSubnetIdMap() { + return subnetIdMap; + } + + /** + * Sets the value of the subnetIdMap property. + * + * @param value + * allowed object is + * {@link QueryNetworkNotification.SubnetIdMap } + * + */ + public void setSubnetIdMap(QueryNetworkNotification.SubnetIdMap value) { + this.subnetIdMap = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class SubnetIdMap { + + protected List<QueryNetworkNotification.SubnetIdMap.Entry> entry; + + /** + * Gets the value of the entry property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the entry property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getEntry().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link QueryNetworkNotification.SubnetIdMap.Entry } + * + * + */ + public List<QueryNetworkNotification.SubnetIdMap.Entry> getEntry() { + if (entry == null) { + entry = new ArrayList<QueryNetworkNotification.SubnetIdMap.Entry>(); + } + return this.entry; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotificationResponse.java new file mode 100644 index 0000000000..0320df27fc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/QueryNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for queryNetworkNotificationResponse complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="queryNetworkNotificationResponse"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "queryNetworkNotificationResponse") +public class QueryNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotification.java new file mode 100644 index 0000000000..08f37fc85d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotification.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for rollbackNetworkNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="rollbackNetworkNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "rollbackNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage" +}) +public class RollbackNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotificationResponse.java new file mode 100644 index 0000000000..44db3a1583 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/RollbackNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for rollbackNetworkNotificationResponse complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="rollbackNetworkNotificationResponse"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "rollbackNetworkNotificationResponse") +public class RollbackNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotification.java new file mode 100644 index 0000000000..f61d0a8dea --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotification.java @@ -0,0 +1,383 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for updateNetworkNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="updateNetworkNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/networkNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="subnetIdMap" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <element name="rollback" type="{http://org.onap.so/networkNotify}networkRollback" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "updateNetworkNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "subnetIdMap", + "rollback" +}) +public class UpdateNetworkNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected UpdateNetworkNotification.SubnetIdMap subnetIdMap; + protected NetworkRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the subnetIdMap property. + * + * @return + * possible object is + * {@link UpdateNetworkNotification.SubnetIdMap } + * + */ + public UpdateNetworkNotification.SubnetIdMap getSubnetIdMap() { + return subnetIdMap; + } + + /** + * Sets the value of the subnetIdMap property. + * + * @param value + * allowed object is + * {@link UpdateNetworkNotification.SubnetIdMap } + * + */ + public void setSubnetIdMap(UpdateNetworkNotification.SubnetIdMap value) { + this.subnetIdMap = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link NetworkRollback } + * + */ + public NetworkRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link NetworkRollback } + * + */ + public void setRollback(NetworkRollback value) { + this.rollback = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class SubnetIdMap { + + protected List<UpdateNetworkNotification.SubnetIdMap.Entry> entry; + + /** + * Gets the value of the entry property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the entry property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getEntry().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link UpdateNetworkNotification.SubnetIdMap.Entry } + * + * + */ + public List<UpdateNetworkNotification.SubnetIdMap.Entry> getEntry() { + if (entry == null) { + entry = new ArrayList<UpdateNetworkNotification.SubnetIdMap.Entry>(); + } + return this.entry; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotificationResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotificationResponse.java new file mode 100644 index 0000000000..e0016d9b8e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/UpdateNetworkNotificationResponse.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for updateNetworkNotificationResponse complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="updateNetworkNotificationResponse"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "updateNetworkNotificationResponse") +public class UpdateNetworkNotificationResponse { + + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/package-info.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/package-info.java new file mode 100644 index 0000000000..fdd8711170 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/async/client/package-info.java @@ -0,0 +1,21 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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========================================================= + */ +@javax.xml.bind.annotation.XmlSchema(namespace = "http://org.onap.so/networkNotify") +package org.onap.so.adapters.network.async.client; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkException.java new file mode 100644 index 0000000000..cb4cd8b927 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkException.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * This class simply extends Exception (without addition additional functionality) + * to provide an identifier for Network related exceptions on create, delete, query. + * + * + */ +@WebFault (name="NetworkException", faultBean="org.onap.so.adapters.network.exceptions.NetworkExceptionBean", targetNamespace="http://org.onap.so/network") +public class NetworkException extends Exception { + + private static final long serialVersionUID = 1L; + + private NetworkExceptionBean faultInfo; + + public NetworkException (String msg) { + super(msg); + faultInfo = new NetworkExceptionBean (msg); + } + + public NetworkException (Throwable e) { + super(e); + faultInfo = new NetworkExceptionBean (e.getMessage()); + } + + public NetworkException (String msg, Throwable e) { + super (msg, e); + faultInfo = new NetworkExceptionBean (msg); + } + + public NetworkException (String msg, MsoExceptionCategory category) { + super(msg); + faultInfo = new NetworkExceptionBean (msg, category); + } + + public NetworkException (String msg, MsoExceptionCategory category, Throwable e) { + super (msg, e); + faultInfo = new NetworkExceptionBean (msg, category); + } + + public NetworkException (MsoException e) { + super (e); + faultInfo = new NetworkExceptionBean (e.getContextMessage(), e.getCategory()); + } + + public NetworkExceptionBean getFaultInfo() { + return faultInfo; + } + + public void setFaultInfo(NetworkExceptionBean faultInfo) { + this.faultInfo = faultInfo; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkExceptionBean.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkExceptionBean.java new file mode 100644 index 0000000000..5256891ffa --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/exceptions/NetworkExceptionBean.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.network.exceptions; + + +import java.io.Serializable; + +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * Jax-WS Fault Bean for Network Exceptions + */ +public class NetworkExceptionBean implements Serializable { + + private static final long serialVersionUID = 1655343530371342871L; + + private String message; + private MsoExceptionCategory category; + private Boolean rolledBack; + + public NetworkExceptionBean () {} + + public NetworkExceptionBean (String message) { + this.message = message; + } + + public NetworkExceptionBean (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-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java new file mode 100644 index 0000000000..d29818614d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java @@ -0,0 +1,190 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.openstack; + +import java.util.Arrays; + +import javax.xml.ws.Endpoint; + +import org.apache.cxf.Bus; +import org.apache.cxf.bus.spring.SpringBus; +import org.apache.cxf.endpoint.Server; +import org.apache.cxf.feature.LoggingFeature; +import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; +import org.apache.cxf.jaxrs.swagger.Swagger2Feature; +import org.apache.cxf.jaxws.EndpointImpl; +import org.apache.cxf.transport.servlet.CXFServlet; +import org.onap.so.adapters.network.MsoNetworkAdapterAsyncImpl; +import org.onap.so.adapters.network.MsoNetworkAdapterImpl; +import org.onap.so.adapters.network.NetworkAdapterRest; +import org.onap.so.adapters.tenant.MsoTenantAdapterImpl; +import org.onap.so.adapters.tenant.TenantAdapterRest; +import org.onap.so.adapters.vnf.MsoVnfAdapterAsyncImpl; +import org.onap.so.adapters.vnf.MsoVnfAdapterImpl; +import org.onap.so.adapters.vnf.MsoVnfCloudifyAdapterImpl; +import org.onap.so.adapters.vnf.VnfAdapterRest; +import org.onap.so.adapters.vnf.VnfAdapterRestV2; +import org.onap.so.adapters.vnf.VolumeAdapterRest; +import org.onap.so.adapters.vnf.VolumeAdapterRestV2; +import org.onap.so.client.policy.JettisonStyleMapperProvider; +import org.onap.so.logger.MsoLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + + +@Configuration +public class CXFConfiguration { + private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, CXFConfiguration.class); + + @Autowired + private NetworkAdapterRest networkAdapterRest; + @Autowired + private TenantAdapterRest tenantAdapterRest; + @Autowired + private VnfAdapterRest vnfAdapterRest; + @Autowired + private VnfAdapterRestV2 vnfAdapterRestV2; + @Autowired + private VolumeAdapterRest volumeAdapterRest; + @Autowired + private VolumeAdapterRestV2 volumeAdapterRestV2; + @Autowired + private MsoNetworkAdapterImpl networkAdapterImpl; + @Autowired + private MsoNetworkAdapterAsyncImpl networkAdapterAsyncImpl; + @Autowired + private MsoTenantAdapterImpl tenantAdapterImpl; + @Autowired + private MsoVnfAdapterImpl vnfAdapterImpl; + @Autowired + private MsoVnfAdapterAsyncImpl vnfAdapterAsyncImpl; + @Autowired + private MsoVnfCloudifyAdapterImpl vnfCloudifyAdapterImpl; + @Autowired + private JettisonStyleMapperProvider jettisonStyleObjectMapper; + + + @Bean(name=Bus.DEFAULT_BUS_ID) + public SpringBus springBus() { + return new SpringBus(); + } + + @Bean + public ServletRegistrationBean SoapDispatcherServlet() { + ServletRegistrationBean servletRegistrationBean = + new ServletRegistrationBean(new CXFServlet(), "/services/*"); + servletRegistrationBean.setName("services"); + return servletRegistrationBean; + } + + /* + * network adapter endpoint + */ + @Bean + public Endpoint networkAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), networkAdapterImpl); + endpoint.publish("/NetworkAdapter"); + endpoint.setWsdlLocation("NetworkAdapter.wsdl"); + return endpoint; + } + + @Bean + public Endpoint networkAdapterAsyncEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), networkAdapterAsyncImpl); + endpoint.publish("/NetworkAdapterAsync"); + endpoint.setWsdlLocation("NetworkAdapterAsync.wsdl"); + return endpoint; + } + + /* + * tenant adapter endpoint + */ + @Bean + public Endpoint tenantAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), tenantAdapterImpl); + endpoint.publish("/TenantAdapter"); + endpoint.setWsdlLocation("TenantAdapter.wsdl"); + return endpoint; + } + + /* + * vnfAdapterEndpoint + * VnfAsyncAdapterEndpoint + * VnfCloudAdapterEndpoint + */ + @Bean + public Endpoint vnfAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), vnfAdapterImpl); + endpoint.publish("/VnfAdapter"); + endpoint.setWsdlLocation("VnfAdapter.wsdl"); + return endpoint; + } + + @Bean + public Endpoint VnfAsyncAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), vnfAdapterAsyncImpl); + endpoint.publish("/VnfAsyncAdapter"); + endpoint.setWsdlLocation("VnfAsyncAdapter.wsdl"); + return endpoint; + } + + @Bean + public Endpoint VnfCloudAdapterEndpoint() { + EndpointImpl endpoint = new EndpointImpl(springBus(), vnfCloudifyAdapterImpl); + endpoint.publish("/VnfCloudifyAdapterImpl"); + endpoint.setWsdlLocation("VnfCloudifyAdapterImpl.wsdl"); + return endpoint; + } + + @Bean + public Server rsServer() { + JAXRSServerFactoryBean endpoint = new JAXRSServerFactoryBean(); + endpoint.setBus(springBus()); + endpoint.setServiceBeans(Arrays.<Object>asList(networkAdapterRest, + tenantAdapterRest, + vnfAdapterRest, + vnfAdapterRestV2, + volumeAdapterRest, + volumeAdapterRestV2)); + endpoint.setAddress("/rest"); + endpoint.setFeatures(Arrays.asList(createSwaggerFeature(), new LoggingFeature())); + endpoint.setProvider(new JacksonJsonProvider(jettisonStyleObjectMapper.getMapper())); + return endpoint.create(); + } + + + @Bean + public Swagger2Feature createSwaggerFeature() { + Swagger2Feature swagger2Feature= new Swagger2Feature(); + swagger2Feature.setPrettyPrint(true); + swagger2Feature.setTitle("SO Orchestration Application"); + swagger2Feature.setContact("The ONAP SO team"); + swagger2Feature.setDescription("This project is the SO Orchestration Engine"); + swagger2Feature.setVersion("1.0.0"); + swagger2Feature.setResourcePackage("org.onap.so.adapters.network,org.onap.so.adapters.tenant,org.onap.so.adapters.vnf"); + swagger2Feature.setScan(true); + return swagger2Feature; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java new file mode 100644 index 0000000000..d67a4b684c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.openstack; + +import java.util.concurrent.Executor; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@SpringBootApplication(scanBasePackages = { "org.onap.so" }) +@EnableAsync +@EnableJpaRepositories({ "org.onap.so.db.catalog.data.repository", + "org.onap.so.db.request.data.repository" }) +@EntityScan({ "org.onap.so.db.catalog.beans", "org.onap.so.db.request.beans" }) +public class MsoOpenstackAdaptersApplication { + + @Value("${mso.async.core-pool-size}") + private int corePoolSize; + + @Value("${mso.async.max-pool-size}") + private int maxPoolSize; + + @Value("${mso.async.queue-capacity}") + private int queueCapacity; + + private static final String LOGS_DIR = "logs_dir"; + + private static void setLogsDir() { + if (System.getProperty(LOGS_DIR) == null) { + System.getProperties().setProperty(LOGS_DIR, "./logs/openstack/"); + } + } + + public static void main(String[] args) { + SpringApplication.run(MsoOpenstackAdaptersApplication.class, args); + setLogsDir(); + } + + @Bean + public Executor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setThreadNamePrefix("OpenstackAdapters-"); + executor.initialize(); + return executor; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java new file mode 100644 index 0000000000..6bbdebea52 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.adapters.openstack; + +import org.onap.so.security.MSOSpringFirewall; +import org.onap.so.security.WebSecurityConfig; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.firewall.StrictHttpFirewall; +import org.springframework.util.StringUtils; + +@EnableWebSecurity +public class WebSecurityConfigImpl extends WebSecurityConfig { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable() + .authorizeRequests() + .antMatchers("/manage/health","/manage/info").permitAll() + .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(),",").toString()) + .and() + .httpBasic(); + } + + @Override + public void configure(WebSecurity web) throws Exception { + super.configure(web); + StrictHttpFirewall firewall = new MSOSpringFirewall(); + web.httpFirewall(firewall); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapter.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapter.java new file mode 100644 index 0000000000..ef66d6876c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapter.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.tenant; + + +import java.util.Map; + +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.onap.so.adapters.tenant.exceptions.TenantAlreadyExists; +import org.onap.so.adapters.tenant.exceptions.TenantException; +import org.onap.so.adapters.tenantrest.TenantRollback; +import org.onap.so.entity.MsoRequest; + +@WebService (name="TenantAdapter", targetNamespace="http://org.onap.so/tenant") +public interface MsoTenantAdapter +{ + /** + * This is the "Create Tenant" Web Service Endpoint definition. + */ + @WebMethod + public void createTenant (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantName") @XmlElement(required=true) String tenantName, + @WebParam(name="metadata") Map<String,String> metadata, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="tenantId", mode=Mode.OUT) Holder<String> tenantId, + @WebParam(name="rollback", mode=Mode.OUT) Holder<TenantRollback> rollback ) + throws TenantException, TenantAlreadyExists; + + @WebMethod + public void queryTenant (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantNameOrId") @XmlElement(required=true) String tenantNameOrId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="tenantId", mode=Mode.OUT) Holder<String> tenantId, + @WebParam(name="tenantName", mode=Mode.OUT) Holder<String> tenantName, + @WebParam(name="metadata", mode=Mode.OUT) Holder<Map<String,String>> metadata ) + throws TenantException; + + @WebMethod + public void deleteTenant (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId, + @WebParam(name="tenantId") @XmlElement(required=true) String tenantId, + @WebParam(name="request") MsoRequest msoRequest, + @WebParam(name="tenantDeleted", mode=Mode.OUT) Holder<Boolean> tenantDeleted) + throws TenantException; + + @WebMethod + public void rollbackTenant (@WebParam(name="rollback") @XmlElement(required=true) TenantRollback rollback) + throws TenantException; + + @WebMethod + public void healthCheck (); +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapterImpl.java new file mode 100644 index 0000000000..f58382f53c --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/MsoTenantAdapterImpl.java @@ -0,0 +1,295 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.tenant; + + +import java.util.Map; + +import javax.annotation.Resource; +import javax.jws.WebService; +import javax.xml.ws.Holder; +import javax.xml.ws.WebServiceContext; + +import org.onap.so.adapters.tenant.exceptions.TenantAlreadyExists; +import org.onap.so.adapters.tenant.exceptions.TenantException; +import org.onap.so.adapters.tenantrest.TenantRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.MsoTenant; +import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.utils.MsoTenantUtils; +import org.onap.so.openstack.utils.MsoTenantUtilsFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@WebService(serviceName = "TenantAdapter", endpointInterface = "org.onap.so.adapters.tenant.MsoTenantAdapter", targetNamespace = "http://org.onap.so/tenant") +@Component +public class MsoTenantAdapterImpl implements MsoTenantAdapter { + public static final String CREATE_TENANT = "CreateTenant"; + public static final String OPENSTACK = "OpenStack"; + public static final String QUERY_TENANT = "QueryTenant"; + public static final String DELETE_TENANT = "DeleteTenant"; + public static final String ROLLBACK_TENANT = "RollbackTenant"; + + @Resource + private WebServiceContext wsContext; + + @Autowired + private MsoTenantUtilsFactory tFactory; + private static MsoLogger logger = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoTenantAdapterImpl.class); + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheck () { + logger.debug ("Health check call in Tenant Adapter"); + } + + /** + * This is the "Create Tenant" web service implementation. It will create + * a new Tenant in the specified cloud. If the tenant already exists, this + * can be considered a success or failure, depending on the value of the + * 'failIfExists' parameter. + * + * The method returns the tenantId (the Openstack ID), and a TenantRollback + * object. This last object can be passed as-is to the rollbackTenant method + * to undo what (if anything) was created. This is useful if a Tenant is + * successfully created but the orchestrator fails on a subsequent operation. + */ + @Override + public void createTenant (String cloudSiteId, + String tenantName, + Map <String, String> metadata, + Boolean failIfExists, + Boolean backout, + MsoRequest msoRequest, + Holder <String> tenantId, + Holder <TenantRollback> rollback) throws TenantException, TenantAlreadyExists { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (CREATE_TENANT); + + logger.debug ("Call to MSO createTenant adapter. Creating Tenant: " + tenantName + + "in " + + cloudSiteId); + + // Will capture total time for metrics + long startTime = System.currentTimeMillis (); + + // Start building up rollback object + TenantRollback tenantRollback = new TenantRollback (); + tenantRollback.setCloudId (cloudSiteId); + tenantRollback.setMsoRequest (msoRequest); + + MsoTenantUtils tUtils; + try { + tUtils = tFactory.getTenantUtils (cloudSiteId); + } catch (MsoCloudSiteNotFound me) { + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "no implementation found for " + cloudSiteId, me); + throw new TenantException (me); + } + + MsoTenant newTenant = null; + String newTenantId; + long queryTenantStartTime = System.currentTimeMillis (); + try { + newTenant = tUtils.queryTenantByName (tenantName, cloudSiteId); + logger.recordMetricEvent (queryTenantStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", OPENSTACK, QUERY_TENANT, null); + } catch (MsoException me) { + logger.recordMetricEvent (queryTenantStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with Open Stack", OPENSTACK, QUERY_TENANT, null); + String error = "Create Tenant " + tenantName + ": " + me; + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "Exception while communicate with Open Stack", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + if (newTenant == null) { + if (backout == null) + backout = true; + long createTenantStartTime = System.currentTimeMillis (); + try { + newTenantId = tUtils.createTenant (tenantName, cloudSiteId, metadata, backout.booleanValue ()); + logger.recordMetricEvent (createTenantStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", OPENSTACK, CREATE_TENANT, null); + } catch (MsoException me) { + logger.recordMetricEvent (createTenantStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with Open Stack", OPENSTACK, CREATE_TENANT, null); + String error = "Create Tenant " + tenantName + ": " + me; + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "Exception while communicate with Open Stack", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + tenantRollback.setTenantId (newTenantId); + tenantRollback.setTenantCreated (true); + logger.debug ("Tenant " + tenantName + " successfully created with ID " + newTenantId); + } else { + if (failIfExists != null && failIfExists) { + String error = CREATE_TENANT + ": Tenant " + tenantName + " already exists in " + cloudSiteId; + logger.error (MessageEnum.RA_TENANT_ALREADY_EXIST, tenantName, cloudSiteId, OPENSTACK, "", MsoLogger.ErrorCode.DataError, CREATE_TENANT + ", Tenant already exists"); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error); + throw new TenantAlreadyExists (tenantName, cloudSiteId, newTenant.getTenantId ()); + } + + newTenantId = newTenant.getTenantId (); + tenantRollback.setTenantCreated (false); + logger.debug ("Tenant " + tenantName + " already exists with ID " + newTenantId); + } + + + tenantId.value = newTenantId; + rollback.value = tenantRollback; + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create tenant"); + return; + } + + @Override + public void queryTenant (String cloudSiteId, + String tenantNameOrId, + MsoRequest msoRequest, + Holder <String> tenantId, + Holder <String> tenantName, + Holder <Map <String, String>> metadata) throws TenantException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (QUERY_TENANT); + logger.debug ("Querying Tenant " + tenantNameOrId + " in " + cloudSiteId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoTenantUtils tUtils; + try { + tUtils = tFactory.getTenantUtils (cloudSiteId); + } catch (MsoCloudSiteNotFound me) { + logger.error (MessageEnum.RA_CREATE_TENANT_ERR, me.getMessage(), OPENSTACK, "createTenant", MsoLogger.ErrorCode.DataError, "no implementation found for " + cloudSiteId, me); + throw new TenantException (me); + } + + MsoTenant qTenant = null; + long subStartTime = System.currentTimeMillis (); + try { + qTenant = tUtils.queryTenant (tenantNameOrId, cloudSiteId); + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", OPENSTACK, QUERY_TENANT, null); + if (qTenant == null) { + // Not found by ID, Try by name. + qTenant = tUtils.queryTenantByName (tenantNameOrId, cloudSiteId); + } + + if (qTenant == null) { + logger.debug ("QueryTenant: Tenant " + tenantNameOrId + " not found"); + tenantId.value = null; + tenantName.value = null; + metadata.value = null; + } else { + logger.debug ("QueryTenant: Tenant " + tenantNameOrId + " found with ID " + qTenant.getTenantId ()); + tenantId.value = qTenant.getTenantId (); + tenantName.value = qTenant.getTenantName (); + metadata.value = qTenant.getMetadata (); + } + } catch (MsoException me) { + String error = "Query Tenant " + tenantNameOrId + ": " + me; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, OPENSTACK, QUERY_TENANT, null); + logger.error (MessageEnum.RA_GENERAL_EXCEPTION, me.getMessage(), OPENSTACK, "", MsoLogger.ErrorCode.DataError, "Exception in queryTenant", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query tenant"); + return; + } + + @Override + public void deleteTenant (String cloudSiteId, + String tenantId, + MsoRequest msoRequest, + Holder <Boolean> tenantDeleted) throws TenantException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName (DELETE_TENANT); + + logger.debug ("Deleting Tenant " + tenantId + " in " + cloudSiteId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Delete the Tenant. + long subStartTime = System.currentTimeMillis (); + try { + + MsoTenantUtils tUtils = tFactory.getTenantUtils (cloudSiteId); + boolean deleted = tUtils.deleteTenant (tenantId, cloudSiteId); + tenantDeleted.value = deleted; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully communicate with Open Stack", OPENSTACK, DELETE_TENANT, null); + } catch (MsoException me) { + String error = "Delete Tenant " + tenantId + ": " + me; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, OPENSTACK, DELETE_TENANT, null); + logger.error (MessageEnum.RA_DELETE_TEMAMT_ERR, me.getMessage(), OPENSTACK, "", MsoLogger.ErrorCode.DataError, "Exception - DeleteTenant", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + + // On success, nothing is returned. + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully delete tenant"); + 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. + * + * The rollback includes removing the VNF and deleting the tenant if the + * tenant did not exist prior to the VNF creation. + */ + @Override + public void rollbackTenant (TenantRollback rollback) throws TenantException { + long startTime = System.currentTimeMillis (); + MsoLogger.setServiceName (ROLLBACK_TENANT); + // rollback may be null (e.g. if stack already existed when Create was called) + if (rollback == null) { + logger.warn (MessageEnum.RA_ROLLBACK_NULL, OPENSTACK, "rollbackTenant", MsoLogger.ErrorCode.DataError, "rollbackTenant, rollback is null"); + return; + } + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudId (); + String tenantId = rollback.getTenantId (); + + MsoLogger.setLogContext (rollback.getMsoRequest ()); + logger.debug ("Rolling Back Tenant " + rollback.getTenantId () + " in " + cloudSiteId); + + long subStartTime = System.currentTimeMillis (); + if (rollback.getTenantCreated ()) { + try { + + MsoTenantUtils tUtils = tFactory.getTenantUtils (cloudSiteId); + tUtils.deleteTenant (tenantId, cloudSiteId); + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully communicate with Open Stack", OPENSTACK, ROLLBACK_TENANT, null); + } catch (MsoException me) { + me.addContext (ROLLBACK_TENANT); + // Failed to delete the tenant. + String error = "Rollback Tenant " + tenantId + ": " + me; + logger.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, OPENSTACK, ROLLBACK_TENANT, null); + logger.error (MessageEnum.RA_ROLLBACK_TENANT_ERR, me.getMessage(), OPENSTACK, "rollbackTenant", MsoLogger.ErrorCode.DataError, "Exception - rollbackTenant", me); + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new TenantException (me); + } + } + logger.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back tenant"); + return; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java new file mode 100644 index 0000000000..2bba3f559e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java @@ -0,0 +1,345 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.tenant; + + +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +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.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.tenant.exceptions.TenantAlreadyExists; +import org.onap.so.adapters.tenant.exceptions.TenantException; +import org.onap.so.adapters.tenantrest.CreateTenantError; +import org.onap.so.adapters.tenantrest.CreateTenantRequest; +import org.onap.so.adapters.tenantrest.CreateTenantResponse; +import org.onap.so.adapters.tenantrest.DeleteTenantError; +import org.onap.so.adapters.tenantrest.DeleteTenantRequest; +import org.onap.so.adapters.tenantrest.DeleteTenantResponse; +import org.onap.so.adapters.tenantrest.QueryTenantError; +import org.onap.so.adapters.tenantrest.QueryTenantResponse; +import org.onap.so.adapters.tenantrest.RollbackTenantError; +import org.onap.so.adapters.tenantrest.RollbackTenantRequest; +import org.onap.so.adapters.tenantrest.RollbackTenantResponse; +import org.onap.so.adapters.tenantrest.TenantRollback; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.MsoTenant; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * This class services calls to the REST interface for Tenants (http://host:port/vnfs/rest/v1/tenants) + * Both XML and JSON can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. + */ +@Path("/v1/tenants") +@Api(value = "/v1/tenants", description = "root of tenant adapters restful web service") +@Component +public class TenantAdapterRest { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, TenantAdapterRest.class); + + //RAA? No logging in wrappers + @Autowired + private MsoTenantAdapterImpl tenantImpl; + + + + /* + URL: + EP: http://host:8080/tenants/rest + Resource: v1/tenants + REQ - metadata? + { + "cloudSiteId": "DAN", + "tenantName": "RAA_1", + "failIfExists": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + }} + RESP- + { + "cloudSiteId": "DAN", + "tenantId": "128e10b9996d43a7874f19bbc4eb6749", + "tenantCreated": true, + "tenantRollback": { + "tenantId": "128e10b9996d43a7874f19bbc4eb6749", + "cloudId": "DAN", // RAA? cloudId instead of cloudSiteId + "tenantCreated": true, + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + } + } + } + */ + @POST + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateTenant", + response = Response.class, + notes = "Creates a new tenant, CreateTenantRequest data is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully created"), + @ApiResponse(code = 500, message = "create tenant failed") }) + public Response createTenant( + @ApiParam(value = "details of tenant being created", required = true) + CreateTenantRequest req) { + LOGGER.debug("createTenant enter: " + req.toJsonString()); + + String newTenantId = null; + TenantRollback tenantRollback = new TenantRollback (); + + try { + Holder<String> htenant = new Holder<>(); + Holder<TenantRollback> hrollback = new Holder<>(); + MsoTenantAdapter impl = tenantImpl; + impl.createTenant( + req.getCloudSiteId(), + req.getTenantName(), + req.getMetadata(), + req.getFailIfExists(), + req.getBackout(), + req.getMsoRequest(), + htenant, + hrollback); + newTenantId = htenant.value; + tenantRollback = hrollback.value; +// TenantAdapterCore TAImpl = new TenantAdapterCore(); +// newTenantId = TAImpl.createTenant (req.getCloudSiteId(), +// req.getTenantName(), +// req.getFailIfExists(), +// req.getBackout(), +// req.getMetadata(), +// req.getMsoRequest(), +// tenantRollback); + } + catch (TenantAlreadyExists tae) { + LOGGER.debug("Exception :",tae); + CreateTenantError exc = new CreateTenantError(tae.getMessage(), tae.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_NOT_IMPLEMENTED).entity(exc).build(); + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + CreateTenantError exc = new CreateTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + CreateTenantError exc = new CreateTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + + CreateTenantResponse resp = new CreateTenantResponse (req.getCloudSiteId(), newTenantId, tenantRollback.getTenantCreated(), tenantRollback); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } + + /* + URL: + http://host:8080/tenants/rest + Resource: v1/tenant/tennatId + REQ: + {"cloudSiteId": "DAN", + "tenantId": "ca84cd3d3df44272845da554656b3ace", + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + } + } + RESP: + {"tenantDeleted": true} + */ + @DELETE + @Path("{tenantId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "DeleteTenant", + response = Response.class, + notes = "Delete an existing tenant") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully deleted"), + @ApiResponse(code = 500, message = "delete tenant failed") }) + public Response deleteTenant( + @ApiParam(value = "tenantId of tenant being deleted", required = true) + @PathParam("tenantId") String tenantId, + @ApiParam(value = "DeleteTenantRequest object containing additional information of tenant being deleted", required = false) + DeleteTenantRequest req) + { + boolean tenantDeleted = false; + + try { + Holder<Boolean> deleted = new Holder<>(); + MsoTenantAdapter impl = tenantImpl; + impl.deleteTenant( + req.getCloudSiteId(), + req.getTenantId(), + req.getMsoRequest(), + deleted); + tenantDeleted = deleted.value; + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + DeleteTenantError exc = new DeleteTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + DeleteTenantError exc = new DeleteTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + DeleteTenantResponse resp = new DeleteTenantResponse(); + resp.setTenantDeleted(tenantDeleted); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } + + /* + URL + EP://http://host:8080/tenants/rest + Resource: /v1/tenants + Params:?tenantNameOrId=RAA_1&cloudSiteId=DAN + RESP + { + "tenantId": "214b428a1f554c02935e66330f6a5409", + "tenantName": "RAA_1", + "metadata": {} + } + */ + @GET + @Path("{tenantId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryTenant", + response = Response.class, + notes = "Query an existing tenant") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully queried"), + @ApiResponse(code = 500, message = "query tenant failed") }) + public Response queryTenant( + @ApiParam(value = "tenantId", required = true) + @PathParam("tenantId") String tenantId, +// @QueryParam("tenantNameOrId") String tenantNameOrId, //RAA? diff from doc + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId) + { + MsoTenant tenant = null; + try { + Holder<String> htenant = new Holder<>(); + Holder<String> tenantName = new Holder<>(); + Holder<Map<String,String>> metadata = new Holder<>(); + MsoTenantAdapter impl = tenantImpl; + impl.queryTenant( + cloudSiteId, + tenantId, + null, + htenant, + tenantName, + metadata + ); + tenant = new MsoTenant(htenant.value, tenantName.value, metadata.value); +// TenantAdapterCore TAImpl = new TenantAdapterCore(); +// MsoRequest msoReq = new MsoRequest(); +// tenant = TAImpl.queryTenant (cloudSiteId, tenantId, msoReq); + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + QueryTenantError exc = new QueryTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory()); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + QueryTenantError exc = new QueryTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + QueryTenantResponse resp = new QueryTenantResponse(tenant.getTenantId(), tenant.getTenantName(), tenant.getMetadata()); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } + + /* + URL + EP: //http://host:8080/tenants/rest + Resource: /v1/tenants/rollback + REQ + {"cloudSiteId": "DAN", + "tenantId": "f58abb05041d4ff384d4d22d1ccd2a6c", + "msoRequest": { + "requestId": "ra1", + "serviceInstanceId": "sa1" + } + } + RESP: + {"tenantDeleted": true} + */ + @DELETE + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "RollbackTenant", + response = Response.class, + notes = "Rollback an existing tenant") + @ApiResponses({ + @ApiResponse(code = 200, message = "tenant has been successfully rolledback"), + @ApiResponse(code = 500, message = "rollback tenant failed") }) + public Response rollbackTenant( + @ApiParam(value = "rollback, command action", required = true) + @QueryParam("rollback") String action, // WTF? + @ApiParam(value = "RollbackTenantRequest", required = true) + RollbackTenantRequest req) + { + try { + MsoTenantAdapter impl = tenantImpl; + impl.rollbackTenant(req.getTenantRollback()); + } + catch (TenantException te) { + LOGGER.debug("Exception :",te); + RollbackTenantError exc = new RollbackTenantError(te.getFaultInfo().getMessage(), te.getFaultInfo().getCategory(), Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + catch (Exception e) { + LOGGER.debug("Exception :",e); + RollbackTenantError exc = new RollbackTenantError(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE); + return Response.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).entity(exc).build(); + } + + RollbackTenantResponse resp = new RollbackTenantResponse (); + resp.setTenantRolledback(req != null); + return Response.status(HttpServletResponse.SC_OK).entity(resp).build(); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantAlreadyExists.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantAlreadyExists.java new file mode 100644 index 0000000000..5b8e7c7294 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantAlreadyExists.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.tenant.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + + +/** + * 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="TenantAlreadyExists", faultBean="org.onap.so.adapters.tenant.exceptions.TenantExceptionBean", targetNamespace="http://org.onap.so/tenant") +public class TenantAlreadyExists extends TenantException { + + private static final long serialVersionUID = 1L; + + public TenantAlreadyExists (String name, String cloudId, String tenantId) { + super("Tenant " + name + " already exists in " + cloudId + " with ID " + tenantId, MsoExceptionCategory.USERDATA); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantException.java new file mode 100644 index 0000000000..b8074ef7fc --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantException.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.tenant.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * This class simply extends Exception (without addition additional functionality) + * to provide an identifier for Tenant related exceptions on create, delete, query. + * + * + */ +@WebFault (name="TenantException", faultBean="org.onap.so.adapters.tenant.exceptions.TenantExceptionBean", targetNamespace="http://org.onap.so/tenant") +public class TenantException extends Exception { + + private static final long serialVersionUID = 1L; + + private TenantExceptionBean faultInfo; + + public TenantException (String msg) { + super(msg); + faultInfo = new TenantExceptionBean (msg); + } + + public TenantException (String msg, Throwable e) { + super (msg, e); + faultInfo = new TenantExceptionBean (msg); + } + + public TenantException (String msg, MsoExceptionCategory category) { + super(msg); + faultInfo = new TenantExceptionBean (msg, category); + } + + public TenantException (String msg, MsoExceptionCategory category, Throwable e) { + super (msg, e); + faultInfo = new TenantExceptionBean (msg, category); + } + + public TenantException (MsoException e) { + super (e); + faultInfo = new TenantExceptionBean (e.getContextMessage(), e.getCategory()); + } + + public TenantExceptionBean getFaultInfo() { + return faultInfo; + } + + public void setFaultInfo(TenantExceptionBean faultInfo) { + this.faultInfo = faultInfo; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantExceptionBean.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantExceptionBean.java new file mode 100644 index 0000000000..1dada60e93 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/exceptions/TenantExceptionBean.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.tenant.exceptions; + + +import java.io.Serializable; + +import org.onap.so.openstack.exceptions.MsoExceptionCategory; + +/** + * Jax-WS Fault Bean for Network Exceptions + */ +public class TenantExceptionBean implements Serializable { + + private static final long serialVersionUID = -9062290006520066109L; + + private String message; + private MsoExceptionCategory category; + + public TenantExceptionBean () {} + + public TenantExceptionBean (String message) { + this.message = message; + } + + public TenantExceptionBean (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; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/GenericValetResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/GenericValetResponse.java new file mode 100644 index 0000000000..344895f8f3 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/GenericValetResponse.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +/* + * The purpose of this class is to encapsulate the possible responses from Valet in to one generic class + * that the vnf adapter can more easily utilize. This will ensure we get an object back. Any status + * code other than 200 will be treated as a failure. We may still get a 200 back - but the + * ValetStatus.status is "failed" - which will also be treated as a failure. The T class is + * expected to be one of the Valet*Response pojos. + */ +public class GenericValetResponse<T> { + private int statusCode; + private String errorMessage; + private T returnObject; + + @Override + public String toString() { + return new ToStringBuilder(this).append("statusCode", statusCode).append("errorMessage", errorMessage) + .append("returnObject", returnObject).toString(); + } + public GenericValetResponse(int statusCode, String errorMessage, T obj) { + super(); + this.statusCode = statusCode; + this.errorMessage = errorMessage; + this.returnObject = obj; + } + public GenericValetResponse() { + this(-1, "not set", null); + } + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + public String getErrorMessage() { + return this.errorMessage; + } + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + public int getStatusCode() { + return this.statusCode; + } + public void setReturnObject(T obj) { + this.returnObject = obj; + } + public T getReturnObject() { + return this.returnObject; + } + +} + diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java new file mode 100644 index 0000000000..f4bda4aaa0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java @@ -0,0 +1,326 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.valet; + +import org.onap.so.adapters.valet.beans.HeatRequest; +import org.onap.so.adapters.valet.beans.ValetConfirmRequest; +import org.onap.so.adapters.valet.beans.ValetConfirmResponse; +import org.onap.so.adapters.valet.beans.ValetCreateRequest; +import org.onap.so.adapters.valet.beans.ValetCreateResponse; +import org.onap.so.adapters.valet.beans.ValetDeleteRequest; +import org.onap.so.adapters.valet.beans.ValetDeleteResponse; +import org.onap.so.adapters.valet.beans.ValetRollbackRequest; +import org.onap.so.adapters.valet.beans.ValetRollbackResponse; +import org.onap.so.adapters.valet.beans.ValetUpdateRequest; +import org.onap.so.adapters.valet.beans.ValetUpdateResponse; + +import java.net.URI; + +import javax.annotation.PostConstruct; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; + +import org.onap.so.adapters.valet.GenericValetResponse; + +import org.onap.so.logger.MsoLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +public class ValetClient { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, ValetClient.class); + + @Autowired + private Environment environment; + + private static final String VALET_BASE_URL = "org.onap.so.adapters.valet.base_url"; + private static final String VALET_BASE_PATH = "org.onap.so.adapters.valet.base_path"; + private static final String VALET_AUTH = "org.onap.so.adapters.valet.basic_auth"; + private static final String REQ_ID_HEADER_NAME = "X-RequestID"; + protected static final String NO_STATUS_RETURNED = "no status returned from Valet"; + + private static final String DEFAULT_BASE_URL = "http://localhost:8080/"; + private static final String DEFAULT_BASE_PATH = "api/valet/placement/v1"; + private static final String DEFAULT_AUTH_STRING = ""; + + @Autowired + private ObjectMapper mapper; + + protected String baseUrl; + protected String basePath; + protected String authString; + + /* + * Setup the properties needed from properties file. Each will fall to a default + */ + @PostConstruct + private void setupParams() { + try { + this.baseUrl = this.environment.getProperty(ValetClient.VALET_BASE_URL, ValetClient.DEFAULT_BASE_URL); + this.basePath = this.environment.getProperty(ValetClient.VALET_BASE_PATH, ValetClient.DEFAULT_BASE_PATH); + this.authString = this.environment.getProperty(ValetClient.VALET_AUTH, ValetClient.DEFAULT_AUTH_STRING); + } catch (Exception e) { + LOGGER.debug("Error retrieving valet properties. " + e.getMessage()); + } + } + + /* + * This method will be invoked to send a Create request to Valet. + */ + public GenericValetResponse<ValetCreateResponse> callValetCreateRequest(String requestId, String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) throws Exception { + ResponseEntity<ValetCreateResponse> response = null; + GenericValetResponse<ValetCreateResponse> gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(baseUrl).path(basePath).queryParam("requestId", requestId); + URI uri = builder.build(); + + ValetCreateRequest vcr = this.createValetCreateRequest(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vcr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity<String> entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet create req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.POST, entity, ValetCreateResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetCreateRequest", e); + throw e; + } + return gvr; + } + + /* + * This method will be invoked to send an Update request to Valet. + */ + public GenericValetResponse<ValetUpdateResponse> callValetUpdateRequest(String requestId, String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) throws Exception { + ResponseEntity<ValetUpdateResponse> response = null; + GenericValetResponse<ValetUpdateResponse> gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(baseUrl).path(basePath).queryParam("requestId", requestId); + URI uri = builder.build(); + + ValetUpdateRequest vur = this.createValetUpdateRequest(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vur); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity<String> entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet update req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.PUT, entity, ValetUpdateResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetUpdateRequest", e); + throw e; + } + return gvr; + } + + /* + * This method will be invoked to send a Delete request to Valet. + */ + public GenericValetResponse<ValetDeleteResponse> callValetDeleteRequest(String requestId, String regionId, String tenantId, String vfModuleId, String vfModuleName) throws Exception { + ResponseEntity<ValetDeleteResponse> response = null; + GenericValetResponse<ValetDeleteResponse> gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(baseUrl).path(basePath).queryParam("requestId", requestId); + URI uri = builder.build(); + + ValetDeleteRequest vdr = this.createValetDeleteRequest(regionId, tenantId, vfModuleId, vfModuleName); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vdr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity<String> entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet delete req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.DELETE, entity, ValetDeleteResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetDeleteRequest", e); + throw e; + } + return gvr; + } + + /* + * This method is called to invoke a Confirm request to Valet. + */ + public GenericValetResponse<ValetConfirmResponse> callValetConfirmRequest(String requestId, String stackId) throws Exception { + ResponseEntity<ValetConfirmResponse> response = null; + GenericValetResponse<ValetConfirmResponse> gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(this.baseUrl).path(this.basePath).path("{requestId}/confirm/"); + URI uri = builder.build(requestId); + + ValetConfirmRequest vcr = this.createValetConfirmRequest(stackId); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vcr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity<String> entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet confirm req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body); + + response = restTemplate.exchange(uri, HttpMethod.PUT, entity, ValetConfirmResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetConfirmRequest", e); + throw e; + } + return gvr; + } + + /* + * This method is called to invoke a Rollback request to Valet. + */ + public GenericValetResponse<ValetRollbackResponse> callValetRollbackRequest(String requestId, String stackId, Boolean suppressRollback, String errorMessage) throws Exception { + ResponseEntity<ValetRollbackResponse> response = null; + GenericValetResponse<ValetRollbackResponse> gvr = null; + + try { + UriBuilder builder = UriBuilder.fromPath(this.baseUrl).path(this.basePath).path("{requestId}/rollback/"); + URI uri = builder.build(requestId); + + ValetRollbackRequest vrr = this.createValetRollbackRequest(stackId, suppressRollback, errorMessage); + RestTemplate restTemplate = new RestTemplate(); + String body = mapper.writeValueAsString(vrr); + HttpHeaders headers = generateHeaders(requestId); + HttpEntity<String> entity = new HttpEntity<>(body, headers); + LOGGER.debug("valet rollback req: " + uri.toString() + ", headers=" + headers.toString() + ", body=" + body.toString()); + + response = restTemplate.exchange(uri, HttpMethod.PUT, entity, ValetRollbackResponse.class); + gvr = this.getGVRFromResponse(response); + } catch (Exception e) { + LOGGER.error("An exception occurred in callValetRollbackRequest", e); + throw e; + } + return gvr; + } + + /* + * This method is to construct the ValetCreateRequest pojo + */ + private ValetCreateRequest createValetCreateRequest(String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) { + ValetCreateRequest vcr = new ValetCreateRequest(); + vcr.setHeatRequest(heatRequest); + vcr.setKeystoneUrl(keystoneUrl); + vcr.setRegionId(regionId); + vcr.setServiceInstanceId(serviceInstanceId); + vcr.setTenantId(tenantId); + vcr.setVfModuleId(vfModuleId); + vcr.setVfModuleName(vfModuleName); + vcr.setVnfId(vnfId); + vcr.setVnfName(vnfName); + + return vcr; + } + + /* + * This method is to construct the ValetUpdateRequest pojo + */ + private ValetUpdateRequest createValetUpdateRequest(String regionId, String tenantId, String serviceInstanceId, + String vnfId, String vnfName, String vfModuleId, String vfModuleName, String keystoneUrl, HeatRequest heatRequest) { + ValetUpdateRequest vur = new ValetUpdateRequest(); + vur.setHeatRequest(heatRequest); + vur.setKeystoneUrl(keystoneUrl); + vur.setRegionId(regionId == null ? "" : regionId); + vur.setServiceInstanceId(serviceInstanceId == null ? "" : serviceInstanceId); + vur.setTenantId(tenantId == null ? "" : tenantId); + vur.setVfModuleId(vfModuleId == null ? "" : vfModuleId); + vur.setVfModuleName(vfModuleName == null ? "" : vfModuleName); + vur.setVnfId(vnfId == null ? "" : vnfId); + vur.setVnfName(vnfName == null ? "" : vnfName); + + return vur; + } + + /* + * This method is to construct the ValetDeleteRequest pojo + */ + private ValetDeleteRequest createValetDeleteRequest(String regionId, String tenantId, String vfModuleId, String vfModuleName) { + ValetDeleteRequest vdr = new ValetDeleteRequest(); + vdr.setRegionId(regionId == null ? "" : regionId); + vdr.setTenantId(tenantId == null ? "" : tenantId); + vdr.setVfModuleId(vfModuleId == null ? "" : vfModuleId); + vdr.setVfModuleName(vfModuleName == null ? "" : vfModuleName); + + return vdr; + } + + /* + * This method is to construct the ValetDeleteRequest pojo + */ + private ValetConfirmRequest createValetConfirmRequest(String stackId) { + ValetConfirmRequest vcr = new ValetConfirmRequest(); + vcr.setStackId(stackId); + + return vcr; + } + + /* + * This method is to construct the ValetRollbackRequest pojo + */ + private ValetRollbackRequest createValetRollbackRequest(String stackId, Boolean suppressRollback, String errorMessage) { + ValetRollbackRequest vrr = new ValetRollbackRequest(); + vrr.setStackId(stackId); + vrr.setSuppressRollback(suppressRollback); + vrr.setErrorMessage(errorMessage); + + return vrr; + } + + private HttpHeaders generateHeaders(String requestId) { + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + if (!(this.authString == null || this.authString.isEmpty())) { + headers.add("Authorization", "Basic " + this.authString); + } + headers.add(ValetClient.REQ_ID_HEADER_NAME, requestId); + + return headers; + } + + private <T> GenericValetResponse<T> getGVRFromResponse(ResponseEntity<T> response) { + GenericValetResponse<T> gvr = null; + if (response != null) { + T responseObj = response.getBody(); + gvr = new GenericValetResponse<>(response.getStatusCodeValue(), ValetClient.NO_STATUS_RETURNED, responseObj); + + } else { + gvr = new GenericValetResponse<>(-1, ValetClient.NO_STATUS_RETURNED, null); + } + return gvr; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/HeatRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/HeatRequest.java new file mode 100644 index 0000000000..dfd257b06b --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/HeatRequest.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.woorea.openstack.heat.model.CreateStackParam; + +/* + * This class represents the heat request as sent to OpenStack as defined in the + * Valet Placement Operations API + */ +public class HeatRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + @JsonProperty("stack_name") + private String stackName; + @JsonProperty("disable_rollback") + private Boolean disableRollback; + @JsonProperty("timeout_mins") + private Integer timeoutMins; + @JsonProperty("template") + private String template; + @JsonProperty("environment") + private String environment; + @JsonProperty("files") + private Map<String, Object> files = new HashMap<String, Object>(); + @JsonProperty("parameters") + private Map<String, Object> parameters = new HashMap<String, Object>(); + + public HeatRequest(String stackName, boolean disableRollback, int timeoutMins, String template, String environment, Map<String, Object> files, Map<String, Object> parameters) { + super(); + this.stackName = stackName; + this.disableRollback = disableRollback; + this.timeoutMins = timeoutMins; + this.template = template; + this.environment = environment; + this.files = files; + this.parameters = parameters; + } + + public String getStackName() { + return this.stackName; + } + public void setStackName(String stackName) { + this.stackName = stackName; + } + public Boolean getDisableRollback() { + return this.disableRollback; + } + public void setDisableRollback(Boolean disableRollback) { + this.disableRollback = disableRollback; + } + public Integer getTimeoutMins() { + return this.timeoutMins; + } + public void setTimeoutMins(Integer timeoutMins) { + this.timeoutMins = timeoutMins; + } + public String getTemplate() { + return this.template; + } + public void setTemplate(String template) { + this.template = template; + } + public String getEnvironment() { + return this.environment; + } + public void setEnvironment(String environment) { + this.environment = environment; + } + public Map<String, Object> getFiles() { + return this.files; + } + public void setFiles(Map<String, Object> files) { + this.files = files; + } + public Map<String, Object> getParameters() { + return this.parameters; + } + public void setParameters(Map<String, Object> parameters) { + this.parameters = parameters; + } + @Override + public int hashCode() { + return Objects.hash(stackName, disableRollback, timeoutMins, template, environment, files, parameters); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof HeatRequest)) { + return false; + } + HeatRequest hr = (HeatRequest) o; + return Objects.equals(stackName, hr.stackName) + && Objects.equals(disableRollback, hr.disableRollback) + && Objects.equals(timeoutMins, hr.timeoutMins) + && Objects.equals(template, hr.template) + && Objects.equals(environment, hr.environment) + && Objects.equals(files, hr.files) + && Objects.equals(parameters, hr.parameters); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmRequest.java new file mode 100644 index 0000000000..36083e8be6 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmRequest.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +/* + * This class represents the body of a Confirm operation on a Valet Placement API call + */ +public class ValetConfirmRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("stack_id") + private String stackId; + + public ValetConfirmRequest() { + super(); + } + public ValetConfirmRequest(String stackId) { + super(); + this.stackId = stackId; + } + + public String getStackId() { + return this.stackId; + } + public void setStackId(String stackId) { + this.stackId = stackId; + } + + @Override + public int hashCode() { + return Objects.hash(stackId); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetConfirmRequest)) { + return false; + } + ValetConfirmRequest vcr = (ValetConfirmRequest) o; + return Objects.equals(stackId, vcr.stackId); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmResponse.java new file mode 100644 index 0000000000..c009da9608 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetConfirmResponse.java @@ -0,0 +1,30 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; + +/* This class has no body - placeholder if needed - for the response to a Confirm operation */ + +public class ValetConfirmResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateRequest.java new file mode 100644 index 0000000000..d692416ea1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateRequest.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Create request operation on a Valet Placement API call + */ +public class ValetCreateRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("region_id") + private String regionId; + @JsonProperty("tenant_id") + private String tenantId; + @JsonProperty("service_instance_id") + private String serviceInstanceId; + @JsonProperty("vnf_id") + private String vnfId; + @JsonProperty("vnf_name") + private String vnfName; + @JsonProperty("vf_module_id") + private String vfModuleId; + @JsonProperty("vf_module_name") + private String vfModuleName; + @JsonProperty("keystone_url") + private String keystoneUrl; + @JsonProperty("heat_request") + private HeatRequest heatRequest; + + public ValetCreateRequest() { + super(); + } + + public String getRegionId() { + return this.regionId; + } + public void setRegionId(String regionId) { + this.regionId = regionId; + } + public String getTenantId() { + return this.tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getServiceInstanceId() { + return this.serviceInstanceId; + } + public void setServiceInstanceId(String serviceInstanceId) { + this.serviceInstanceId = serviceInstanceId; + } + public String getVnfId() { + return this.vnfId; + } + public void setVnfId(String vnfId) { + this.vnfId = vnfId; + } + public String getVnfName() { + return this.vnfName; + } + public void setVnfName(String vnfName) { + this.vnfName = vnfName; + } + public String getVfModuleId() { + return this.vfModuleId; + } + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + public String getVfModuleName() { + return this.vfModuleName; + } + public void setVfModuleName(String vfModuleName) { + this.vfModuleName = vfModuleName; + } + public String getKeystoneUrl() { + return this.keystoneUrl; + } + public void setKeystoneUrl(String keystoneUrl) { + this.keystoneUrl = keystoneUrl; + } + public HeatRequest getHeatRequest() { + return this.heatRequest; + } + public void setHeatRequest(HeatRequest heatRequest) { + this.heatRequest = heatRequest; + } + + @Override + public int hashCode() { + return Objects.hash(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetCreateRequest)) { + return false; + } + ValetCreateRequest vcr = (ValetCreateRequest) o; + return Objects.equals(regionId, vcr.regionId) + && Objects.equals(tenantId, vcr.tenantId) + && Objects.equals(serviceInstanceId, vcr.serviceInstanceId) + && Objects.equals(vnfId, vcr.vnfId) + && Objects.equals(vnfName, vcr.vnfName) + && Objects.equals(vfModuleId, vcr.vfModuleId) + && Objects.equals(vfModuleName, vcr.vfModuleName) + && Objects.equals(keystoneUrl, vcr.keystoneUrl) + && Objects.equals(heatRequest, vcr.heatRequest); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateResponse.java new file mode 100644 index 0000000000..e0c750e79f --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetCreateResponse.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import java.util.Objects; +import java.io.Serializable; +/* + * This class represents the body of a Create response on a Valet Placement API call + */ +public class ValetCreateResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("status") + private ValetStatus status; + @JsonProperty("parameters") + private Map<String, Object> parameters; + + public ValetCreateResponse() { + super(); + } + + public ValetStatus getStatus() { + return this.status; + } + public void setStatus(ValetStatus status) { + this.status = status; + } + public Map<String, Object> getParameters() { + return this.parameters; + } + public void setParameters(Map<String, Object> parameters) { + this.parameters = parameters; + } + + @Override + public int hashCode() { + return Objects.hash(status, parameters); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetCreateResponse)) { + return false; + } + ValetCreateResponse vcr = (ValetCreateResponse) o; + return Objects.equals(status, vcr.status) + && Objects.equals(parameters, vcr.parameters); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteRequest.java new file mode 100644 index 0000000000..7bd5855d0e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteRequest.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Delete request on a Valet Placement API call + */ +public class ValetDeleteRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("region_id") + private String regionId; + @JsonProperty("tenant_id") + private String tenantId; + @JsonProperty("vf_module_id") + private String vfModuleId; + @JsonProperty("vf_module_name") + private String vfModuleName; + + public String getRegionId() { + return this.regionId; + } + public void setRegionId(String regionId) { + this.regionId = regionId; + } + public String getTenantId() { + return this.tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getVfModuleId() { + return this.vfModuleId; + } + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + public String getVfModuleName() { + return this.vfModuleName; + } + public void setVfModuleName(String vfModuleName) { + this.vfModuleName = vfModuleName; + } + @Override + public int hashCode() { + return Objects.hash(regionId, tenantId, vfModuleId, vfModuleName); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetDeleteRequest)) { + return false; + } + ValetDeleteRequest vdr = (ValetDeleteRequest) o; + return Objects.equals(regionId, vdr.regionId) + && Objects.equals(tenantId, vdr.tenantId) + && Objects.equals(vfModuleId, vdr.vfModuleId) + && Objects.equals(vfModuleName, vdr.vfModuleName); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteResponse.java new file mode 100644 index 0000000000..fa58752d61 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetDeleteResponse.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Delete response on a Valet Placement API call + */ +public class ValetDeleteResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + @JsonProperty("status") + private ValetStatus status; + + public ValetDeleteResponse() { + super(); + } + public ValetDeleteResponse(ValetStatus status) { + super(); + this.status = status; + } + + public ValetStatus getStatus() { + return this.status; + } + public void setStatus(ValetStatus status) { + this.status = status; + } + + @Override + public int hashCode() { + return Objects.hash(status); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetDeleteResponse)) { + return false; + } + ValetDeleteResponse vdr = (ValetDeleteResponse) o; + return Objects.equals(status, vdr.status); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackRequest.java new file mode 100644 index 0000000000..ae0af67f80 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackRequest.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of a Rollback request on a Valet Placement API call + */ +public class ValetRollbackRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("stack_id") + private String stackId; + @JsonProperty("suppress_rollback") + private Boolean suppressRollback = false; + @JsonProperty("error_message") + private String errorMessage; + + public ValetRollbackRequest() { + super(); + } + + public String getStackId() { + return this.stackId; + } + public void setStackId(String stackId) { + this.stackId = stackId; + } + public Boolean getSuppressRollback() { + return this.suppressRollback; + } + public void setSuppressRollback(Boolean suppressRollback) { + this.suppressRollback = suppressRollback; + } + public String getErrorMessage() { + return this.errorMessage; + } + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public int hashCode() { + return Objects.hash(stackId, suppressRollback, errorMessage); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetRollbackRequest)) { + return false; + } + ValetRollbackRequest vrr = (ValetRollbackRequest) o; + return Objects.equals(stackId, vrr.stackId) + && Objects.equals(suppressRollback, vrr.suppressRollback) + && Objects.equals(errorMessage, vrr.errorMessage); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackResponse.java new file mode 100644 index 0000000000..429aa95af0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetRollbackResponse.java @@ -0,0 +1,29 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +/* This class has no body - placeholder - body of a Rollback response on a Valet Placement Operation */ + +public class ValetRollbackResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetStatus.java new file mode 100644 index 0000000000..067a6727c1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetStatus.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.builder.ToStringBuilder; + +/* + * This class represents the status object as defined in the Valet Placement Operations API - part of Response objects + */ +public class ValetStatus implements Serializable { + private static final long serialVersionUID = 1L; + @JsonProperty("status") + private String status; + @JsonProperty("message") + private String message; + + @Override + public String toString() { + return new ToStringBuilder(this).append("status", status).append("message", message).toString(); + } + + public ValetStatus() { + super(); + } + + public ValetStatus(String statusCode, String statusMessage) { + super(); + this.status = statusCode; + this.message = statusMessage; + } + + public String getStatus() { + return this.status; + } + public void setStatus(String statusCode) { + this.status = statusCode; + } + public String getMessage() { + return this.message; + } + public void setMessage(String statusMessage) { + this.message = statusMessage; + } + + @Override + public int hashCode() { + return Objects.hash(status, message); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetStatus)) { + return false; + } + ValetStatus vs = (ValetStatus) o; + return Objects.equals(status, vs.status) && Objects.equals(message, vs.message); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateRequest.java new file mode 100644 index 0000000000..360c07b225 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateRequest.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of an Update request on a Valet Placement API call + */ +public class ValetUpdateRequest implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + + @JsonProperty("region_id") + private String regionId; + @JsonProperty("tenant_id") + private String tenantId; + @JsonProperty("service_instance_id") + private String serviceInstanceId; + @JsonProperty("vnf_id") + private String vnfId; + @JsonProperty("vnf_name") + private String vnfName; + @JsonProperty("vf_module_id") + private String vfModuleId; + @JsonProperty("vf_module_name") + private String vfModuleName; + @JsonProperty("keystone_url") + private String keystoneUrl; + @JsonProperty("heat_request") + private HeatRequest heatRequest; + + public ValetUpdateRequest() { + super(); + } + + public String getRegionId() { + return this.regionId; + } + public void setRegionId(String regionId) { + this.regionId = regionId; + } + public String getTenantId() { + return this.tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getServiceInstanceId() { + return this.serviceInstanceId; + } + public void setServiceInstanceId(String serviceInstanceId) { + this.serviceInstanceId = serviceInstanceId; + } + public String getVnfId() { + return this.vnfId; + } + public void setVnfId(String vnfId) { + this.vnfId = vnfId; + } + public String getVnfName() { + return this.vnfName; + } + public void setVnfName(String vnfName) { + this.vnfName = vnfName; + } + public String getVfModuleId() { + return this.vfModuleId; + } + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + public String getVfModuleName() { + return this.vfModuleName; + } + public void setVfModuleName(String vfModuleName) { + this.vfModuleName = vfModuleName; + } + public String getKeystoneUrl() { + return this.keystoneUrl; + } + public void setKeystoneUrl(String keystoneUrl) { + this.keystoneUrl = keystoneUrl; + } + public HeatRequest getHeatRequest() { + return this.heatRequest; + } + public void setHeatRequest(HeatRequest heatRequest) { + this.heatRequest = heatRequest; + } + @Override + public int hashCode() { + return Objects.hash(regionId, tenantId, serviceInstanceId, vnfId, vnfName, vfModuleId, vfModuleName, keystoneUrl, heatRequest); + + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetUpdateRequest)) { + return false; + } + ValetUpdateRequest vur = (ValetUpdateRequest) o; + return Objects.equals(regionId, vur.regionId) + && Objects.equals(tenantId, vur.tenantId) + && Objects.equals(serviceInstanceId, vur.serviceInstanceId) + && Objects.equals(vnfId, vur.vnfId) + && Objects.equals(vnfName, vur.vnfName) + && Objects.equals(vfModuleId, vur.vfModuleId) + && Objects.equals(vfModuleName, vur.vfModuleName) + && Objects.equals(keystoneUrl, vur.keystoneUrl) + && Objects.equals(heatRequest, vur.heatRequest); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateResponse.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateResponse.java new file mode 100644 index 0000000000..36f11d30c0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/beans/ValetUpdateResponse.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.valet.beans; + +import java.io.Serializable; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * This class represents the body of an Update response on a Valet Placement API call + */ +public class ValetUpdateResponse implements Serializable { + private static final long serialVersionUID = 768026109321305392L; + @JsonProperty("status") + private ValetStatus status; + @JsonProperty("parameters") + private Map<String, Object> parameters; + + public ValetUpdateResponse() { + super(); + } + + public ValetStatus getStatus() { + return this.status; + } + public void setStatus(ValetStatus status) { + this.status = status; + } + public Map<String, Object> getParameters() { + return this.parameters; + } + public void setParameters(Map<String, Object> parameters) { + this.parameters = parameters; + } + + @Override + public int hashCode() { + return Objects.hash(status, parameters); + } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ValetUpdateResponse)) { + return false; + } + ValetUpdateResponse vur = (ValetUpdateResponse) o; + return Objects.equals(status, vur.status) + && Objects.equals(parameters, vur.parameters); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java new file mode 100644 index 0000000000..f6442b6252 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vdu/mapper/VfModuleCustomizationToVduMapper.java @@ -0,0 +1,127 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2018 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.onap.so.adapters.vdu.mapper; + +import java.util.List; + +import org.onap.so.adapters.vdu.VduModelInfo; +import org.onap.so.adapters.vdu.VduArtifact; +import org.onap.so.adapters.vdu.VduArtifact.ArtifactType; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatFiles; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.springframework.stereotype.Component; + +@Component +public class VfModuleCustomizationToVduMapper { + + public VduModelInfo mapVfModuleCustomizationToVdu(VfModuleCustomization vfModuleCustom) + { + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID(vfModuleCustom.getModelCustomizationUUID()); + + // Map the cloud templates, attached files, and environment file + mapCloudTemplates(vfModuleCustom.getVfModule().getModuleHeatTemplate(), vduModel); + mapCloudFiles(vfModuleCustom,vduModel); + mapEnvironment(vfModuleCustom.getHeatEnvironment(), vduModel); + + return vduModel; + } + + public VduModelInfo mapVfModuleCustVolumeToVdu(VfModuleCustomization vfModuleCustom) + { + VduModelInfo vduModel = new VduModelInfo(); + vduModel.setModelCustomizationUUID(vfModuleCustom.getModelCustomizationUUID()); + + // Map the cloud templates, attached files, and environment file + mapCloudTemplates(vfModuleCustom.getVfModule().getVolumeHeatTemplate(), vduModel); + mapCloudFiles(vfModuleCustom,vduModel); + mapEnvironment(vfModuleCustom.getVolumeHeatEnv(), vduModel); + + return vduModel; + } + + private void mapCloudTemplates(HeatTemplate heatTemplate, VduModelInfo vduModel) { + // TODO: These catalog objects will be refactored to be non-Heat-specific + + List<VduArtifact> vduArtifacts = vduModel.getArtifacts(); + + // Main template. Also set the VDU timeout based on the main template. + vduArtifacts.add(mapHeatTemplateToVduArtifact(heatTemplate, ArtifactType.MAIN_TEMPLATE)); + vduModel.setTimeoutMinutes(heatTemplate.getTimeoutMinutes()); + + // Nested templates + List<HeatTemplate> childTemplates = heatTemplate.getChildTemplates(); + if (childTemplates != null) { + for(HeatTemplate childTemplate : childTemplates){ + vduArtifacts.add(mapHeatTemplateToVduArtifact(childTemplate, ArtifactType.NESTED_TEMPLATE)); + } + } + } + + private VduArtifact mapHeatTemplateToVduArtifact(HeatTemplate heatTemplate, ArtifactType artifactType) { + VduArtifact vduArtifact = new VduArtifact(); + vduArtifact.setName(heatTemplate.getTemplateName()); + vduArtifact.setContent(heatTemplate.getHeatTemplate().getBytes()); + vduArtifact.setType(artifactType); + return vduArtifact; + } + + private void mapCloudFiles(VfModuleCustomization vfModuleCustom, VduModelInfo vduModel) { + // TODO: These catalog objects will be refactored to be non-Heat-specific + + List<VduArtifact> vduArtifacts = vduModel.getArtifacts(); + + // Attached Files + List<HeatFiles> heatFiles = vfModuleCustom.getVfModule().getHeatFiles(); + if (heatFiles != null) { + for(HeatFiles file : heatFiles){ + vduArtifacts.add(mapCloudFileToVduArtifact(file, ArtifactType.TEXT_FILE)); + } + } + } + + private VduArtifact mapCloudFileToVduArtifact(HeatFiles heatFile, ArtifactType artifactType) { + VduArtifact vduArtifact = new VduArtifact(); + vduArtifact.setName(heatFile.getFileName()); + vduArtifact.setContent(heatFile.getFileBody().getBytes()); + vduArtifact.setType(artifactType); + return vduArtifact; + } + + private void mapEnvironment(HeatEnvironment heatEnvironment, VduModelInfo vduModel) { + // TODO: These catalog objects will be refactored to be non-Heat-specific + if (heatEnvironment != null) { + List<VduArtifact> vduArtifacts = vduModel.getArtifacts(); + vduArtifacts.add(mapEnvironmentFileToVduArtifact(heatEnvironment)); + } + } + + private VduArtifact mapEnvironmentFileToVduArtifact(HeatEnvironment heatEnv) { + VduArtifact vduArtifact = new VduArtifact(); + vduArtifact.setName(heatEnv.getName()); + vduArtifact.setContent(heatEnv.getEnvironment().getBytes()); + vduArtifact.setType(ArtifactType.ENVIRONMENT); + return vduArtifact; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java new file mode 100644 index 0000000000..6383f57693 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java @@ -0,0 +1,296 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf; + + +import java.security.GeneralSecurityException; +import java.util.Set; +import java.util.TreeSet; + +import javax.annotation.PostConstruct; +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.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * 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.onap.so.adapters.vnf.bpelauth encrypted authorization string to send to BEPL engine + * org.onap.so.adapters.vnf.sockettimeout socket timeout value + * org.onap.so.adapters.vnf.connecttimeout connect timeout value + * org.onap.so.adapters.vnf.retrycount number of times to retry failed connections + * org.onap.so.adapters.vnf.retryinterval interval (in seconds) between retries + * org.onap.so.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code + * 900 means "connection was not established") + */ +@Component("VnfBpel") +@Scope("prototype") +public class BpelRestClient { + public static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER"; + private static final String PROPERTY_DOMAIN = "org.onap.so.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, BpelRestClient.class); + + /** 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 = ""; + + @Autowired + private Environment env; + // 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 = ""; + + } + + @PostConstruct + protected void init() { + + socketTimeout = env.getProperty(SOCKET_TIMEOUT_PROPERTY, Integer.class, DEFAULT_SOCKET_TIMEOUT); + connectTimeout = env.getProperty(CONN_TIMEOUT_PROPERTY, Integer.class, DEFAULT_CONNECT_TIMEOUT); + retryCount = env.getProperty(RETRY_COUNT_PROPERTY, Integer.class, DEFAULT_RETRY_COUNT); + retryInterval = env.getProperty(RETRY_INTERVAL_PROPERTY, Integer.class, DEFAULT_RETRY_INTERVAL); + setRetryList(env.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST)); + credentials = getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY); + } + + 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) { + int newRetryCount = retryCount; + if (newRetryCount < 0) + newRetryCount = DEFAULT_RETRY_COUNT; + this.retryCount = newRetryCount; + } + + 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.isEmpty()) + return ""; + String t = retryList.toString(); + return t.substring(1, t.length()-1); + } + + public void setRetryList(String retryList) { + Set<Integer> s = new TreeSet<>(); + 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) { + LOGGER.debug("Exception while Thread sleep", e); + Thread.currentThread().interrupt(); + } + } + } + private void debug(String m) { + LOGGER.debug(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); + + 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); + } + + private String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + if (env.getProperty(key) != null) { + try { + return CryptoUtils.decrypt(env.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + env.getProperty(key), e); + } + } + return defaultValue; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java new file mode 100644 index 0000000000..bbfcef02e2 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java @@ -0,0 +1,192 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2018 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.onap.so.adapters.vnf; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.onap.so.adapters.vdu.VduArtifact; +import org.onap.so.adapters.vdu.VduArtifact.ArtifactType; +import org.onap.so.adapters.vdu.VduModelInfo; +import org.onap.so.adapters.vnf.exceptions.VnfException; + +import com.google.common.io.Files; + +/** + * The purpose of this class is to create a CSAR byte array from Vdu inputs for the purpose + * of forwarding to a TOSCA orchestrator. + * + * @author DeWayne + * + */ +public class CSAR { + private static final String MANIFEST_FILENAME = "MANIFEST.MF"; + private VduModelInfo vduModel; + + public CSAR(VduModelInfo model){ + this.vduModel = model; + } + + /** + * Creates a byte array representation of a CSAR corresponding to the VduBlueprint arg in the + * constructor. + * + * @return + * @throws VnfException + */ + public byte[] create() { + File dir = Files.createTempDir(); + + /** + * Create subdir + */ + File metadir = new File(dir.getAbsolutePath() + "/TOSCA-Metadata"); + if (!metadir.mkdir()) { + throw new RuntimeException("CSAR TOSCA-Metadata directory create failed"); + } + + /** + * Organize model info for consumption + */ + VduArtifact mainTemplate = null; + List<VduArtifact> extraFiles = new ArrayList<>(); + for(VduArtifact artifact: vduModel.getArtifacts()) { + if(artifact.getType() == ArtifactType.MAIN_TEMPLATE ) { + mainTemplate = artifact; + } else{ + extraFiles.add(artifact); + } + } + + if (mainTemplate == null) { // make a dummy to avoid null pointers + mainTemplate = new VduArtifact("", new byte[0], null); + } + + /** + * Write template files + */ + try (OutputStream ofs = new FileOutputStream(new File(dir, mainTemplate.getName())); + PrintStream mfstream = new PrintStream(new File(metadir.getAbsolutePath() + '/' + MANIFEST_FILENAME)); + ) { + ofs.write(mainTemplate.getContent()); + + /** + * Write other files + */ + if (!extraFiles.isEmpty()) { + for (VduArtifact artifact: extraFiles){ + try (OutputStream out = new FileOutputStream(new File(dir, artifact.getName()));) { + out.write(artifact.getContent()); + } + } + } + + + /** + * Create manifest + */ + mfstream.println("TOSCA-Meta-File-Version: 1.0"); + mfstream.println("CSAR-Version: 1.1"); + mfstream.println("Created-by: ONAP"); + mfstream.println("Entry-Definitions: " + mainTemplate.getName()); + + /** + * ZIP it up + */ + ByteArrayOutputStream zipbytes = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(zipbytes); + compressTree(zos, "", dir, dir); + zos.close(); + return zipbytes.toByteArray(); + + } catch (Exception e) { + throw new RuntimeException("Failed to create CSAR: " + e.getMessage()); + } finally { + /** + * Clean up tmpdir + */ + deleteDirectory(dir); + } + } + + /** + * Private methods + */ + + /** + * Compresses (ZIPs) a directory tree + * + * @param dir + * @throws IOException + */ + private void compressTree(ZipOutputStream zos, String path, File basedir, File dir) throws IOException { + if (!dir.isDirectory()) + return; + + for (File f : dir.listFiles()) { + if (f.isDirectory()) { + String newpath = path + f.getName() + '/'; + ZipEntry entry = new ZipEntry(newpath); + zos.putNextEntry(entry); + zos.closeEntry(); + compressTree(zos, newpath, basedir, f); + } else { + ZipEntry ze = new ZipEntry( + f.getAbsolutePath().substring(basedir.getAbsolutePath().length() + 1).replaceAll("\\\\", "/")); + zos.putNextEntry(ze); + // read the file and write to ZipOutputStream + try (FileInputStream fis = new FileInputStream(f);) { + byte[] buffer = new byte[1024]; + int len; + while ((len = fis.read(buffer)) > 0) { + zos.write(buffer, 0, len); + } + } + zos.closeEntry(); + } + } + } + + private boolean deleteDirectory(File directory) { + if (directory.exists()) { + File[] files = directory.listFiles(); + if (null != files) { + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + deleteDirectory(files[i]); + } else { + files[i].delete(); + } + } + } + } + return (directory.delete()); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java new file mode 100644 index 0000000000..5efcc2c90d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java @@ -0,0 +1,147 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf; + + +import java.util.Map; + +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.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; + +@WebService (name="VnfAdapter", targetNamespace="http://org.onap.so/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="enableBridge") Boolean enableBridge, + @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 = "modelCustomizationUuid") @XmlElement(required = false) String modelCustomizationUuid, + @WebParam(name="inputs") Map<String,String> inputs, + @WebParam(name="failIfExists") Boolean failIfExists, + @WebParam(name="backout") Boolean backout, + @WebParam(name="enableBridge") Boolean enableBridge, + @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, + @WebParam(name = "vfModuleOutputs", mode = Mode.OUT) Holder<Map<String, String>> vfModuleOutputs) + 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 = "modelCustomizationUuid") @XmlElement(required = false) String modelCustomizationUuid, + @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-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsync.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsync.java new file mode 100644 index 0000000000..b67a412c3e --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsync.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf; + + +import java.util.Map; + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; + +import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.VnfRollback; + +/** + * 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://org.onap.so/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="enableBridge") Boolean enableBridge, + @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-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java new file mode 100644 index 0000000000..95135f579d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java @@ -0,0 +1,666 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.vnf; + + +import java.net.MalformedURLException; +import java.net.URL; +import java.security.GeneralSecurityException; +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.onap.so.adapters.vnf.async.client.CreateVnfNotification; +import org.onap.so.adapters.vnf.async.client.QueryVnfNotification; +import org.onap.so.adapters.vnf.async.client.UpdateVnfNotification; +import org.onap.so.adapters.vnf.async.client.VnfAdapterNotify; +import org.onap.so.adapters.vnf.async.client.VnfAdapterNotify_Service; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.utils.CryptoUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@WebService(serviceName = "VnfAdapterAsync", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapterAsync", targetNamespace = "http://org.onap.so/vnfA") +@Component +public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { + + public static final String MSO_PROP_VNF_ADAPTER="MSO_PROP_VNF_ADAPTER"; + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfAdapterAsyncImpl.class); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String BPEL_AUTH_PROP = "org.onap.so.adapters.vnf.bpelauth"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + + @Autowired + private Environment environment; + + @Autowired + private MsoVnfAdapterImpl vnfImpl; + + /** + * 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, + Boolean enableBridge, + 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"); + // Use the synchronous method to perform the actual Create + MsoVnfAdapter vnfAdapter = vnfImpl; + // Synchronous Web Service Outputs + Holder <String> vnfId = new Holder <> (); + Holder <Map <String, String>> outputs = new Holder <> (); + Holder <VnfRollback> vnfRollback = new Holder <> (); + + try { + vnfAdapter.createVnf (cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + requestType, + volumeGroupHeatStackId, + inputs, + failIfExists, + backout, + enableBridge, + 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.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.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", ""); + 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); + LOGGER.info (MessageEnum.RA_ASYNC_UPDATE_VNF, vnfName, vnfType, cloudSiteId, tenantId, "UpdateVnfA"); + + // Use the synchronous method to perform the actual Create + MsoVnfAdapter vnfAdapter = vnfImpl; + + // Synchronous Web Service Outputs + Holder <String> vnfId = new Holder <> (); + Holder <Map <String, String>> outputs = new Holder <> (); + Holder <VnfRollback> vnfRollback = new Holder <> (); + + 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.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.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); + LOGGER.info (MessageEnum.RA_ASYNC_QUERY_VNF, vnfName, cloudSiteId, tenantId); + + // Use the synchronous method to perform the actual query + MsoVnfAdapter vnfAdapter = vnfImpl; + + // Synchronous Web Service Outputs + Holder <Boolean> vnfExists = new Holder <> (); + Holder <String> vnfId = new Holder <> (); + Holder <VnfStatus> status = new Holder <> (); + Holder <Map <String, String>> outputs = new Holder <> (); + + 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.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.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.onap.so.adapters.vnf.async.client.VnfStatus vnfS = org.onap.so.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); + LOGGER.info (MessageEnum.RA_ASYNC_DELETE_VNF, vnfName, cloudSiteId, tenantId); + + // Use the synchronous method to perform the actual delete + MsoVnfAdapter vnfAdapter = vnfImpl; + + 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.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.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); + 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 = vnfImpl; + + 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.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; + String eMsg = null; + try { + eMsg = e.getFaultInfo ().getMessage (); + exCat = org.onap.so.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.onap.so.adapters.vnf.async.client.VnfRollback copyVrb (Holder <VnfRollback> hVrb) { + org.onap.so.adapters.vnf.async.client.VnfRollback cvrb = new org.onap.so.adapters.vnf.async.client.VnfRollback (); + + if (hVrb != null && hVrb.value != null) { + org.onap.so.adapters.vnf.async.client.MsoRequest cmr = new org.onap.so.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 <> (); + 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 <> (); + sMap = hMap.value; + UpdateVnfNotification.Outputs.Entry entry = new UpdateVnfNotification.Outputs.Entry (); + + for (Map.Entry<String,String> mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + 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 <> (); + sMap = hMap.value; + + QueryVnfNotification.Outputs.Entry entry = new QueryVnfNotification.Outputs.Entry (); + + for (Map.Entry<String,String> mapEntry : sMap.entrySet ()) { + String key = mapEntry.getKey(); + String value = mapEntry.getValue(); + entry.setKey (key); + entry.setValue (value); + 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://org.onap.so/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); + } + + if(null != epUrl) { + LOGGER.debug ("Notification Endpoint URL: " + epUrl.toExternalForm ()); + bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY, epUrl.toExternalForm ()); + } + else { + LOGGER.debug ("epUrl is NULL:"); + } + + // authentication + try { + Map <String, Object> reqCtx = bp.getRequestContext (); + Map <String, List <String>> headers = new HashMap <> (); + + String userCredentials = this.getEncryptedProperty(BPEL_AUTH_PROP, "", ENCRYPTION_KEY); + + String basicAuth = "Basic " + DatatypeConverter.printBase64Binary (userCredentials.getBytes ()); + reqCtx.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; + } + + public String getEncryptedProperty(String key, String defaultValue, String encryptionKey) { + try { + return CryptoUtils.decrypt(this.environment.getProperty(key), encryptionKey); + } catch (GeneralSecurityException e) { + LOGGER.debug("Exception while decrypting property: " + this.environment.getProperty(key), e); + } + return defaultValue; + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java new file mode 100644 index 0000000000..994a83c422 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java @@ -0,0 +1,2347 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.vnf; + + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnf.exceptions.VnfNotFound; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatFiles; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.HeatTemplateParam; +import org.onap.so.db.catalog.beans.VfModule; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.onap.so.db.catalog.beans.VnfResource; +import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository; +import org.onap.so.db.catalog.data.repository.VnfResourceRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.HeatStatus; +import org.onap.so.openstack.beans.StackInfo; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.exceptions.MsoHeatNotFoundException; +import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry; +import org.onap.so.openstack.utils.MsoHeatUtils; +import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate; +import org.onap.so.adapters.valet.ValetClient; +import org.onap.so.adapters.valet.beans.HeatRequest; +import org.onap.so.adapters.valet.beans.ValetConfirmResponse; +import org.onap.so.adapters.valet.beans.ValetCreateResponse; +import org.onap.so.adapters.valet.beans.ValetDeleteResponse; +import org.onap.so.adapters.valet.beans.ValetRollbackResponse; +import org.onap.so.adapters.valet.beans.ValetStatus; +import org.onap.so.adapters.valet.beans.ValetUpdateResponse; +import org.onap.so.adapters.valet.GenericValetResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf") +@Component +@Transactional +public class MsoVnfAdapterImpl implements MsoVnfAdapter { + + @Autowired + private CloudConfig cloudConfig; + + @Autowired + private Environment environment; + + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static final String VNF_ADAPTER_SERVICE_NAME = "MSO-BPMN:MSO-VnfAdapter."; + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA,MsoVnfAdapterImpl.class); + private static final MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters"; + private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + private static final String VALET_ENABLED = "org.onap.so.adapters.vnf.valet_enabled"; + private static final String FAIL_REQUESTS_ON_VALET_FAILURE = "org.onap.so.adapters.vnf.fail_requests_on_valet_failure"; + + @Autowired + private VFModuleCustomizationRepository vfModuleCustomRepo; + + + @Autowired + private VnfResourceRepository vnfResourceRepo; + + @Autowired + private MsoHeatUtilsWithUpdate heatU; + @Autowired + private MsoHeatUtils heat; + @Autowired + private ValetClient vci; + /** + * 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 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, + Boolean enableBridge, + 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 && 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,e); + } + this.createVfModule(cloudSiteId, + tenantId, + vnfType, + vnfVersion, + vnfName, + newRequestType, + vfVolGroupHeatStackId, + vfBaseHeatStackId, + null, + inputs, + failIfExists, + backout, + enableBridge, + 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, + null, + inputs, + failIfExists, + backout, + enableBridge, + 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 { + // As of 1707 - this method should no longer be called + MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ()); + MsoLogger.setServiceName ("UpdateVnf"); + LOGGER.debug("UpdateVnf called?? This should not be called any longer - update vfModule"); + } + + /** + * 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 (); + + 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<>(); // 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 (); + + // 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.toString(), "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); + + // 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 <> (); + for (Map.Entry<String,Object> entry : stackOutputs.entrySet ()) { + String key = entry.getKey(); + Object value = entry.getValue(); + try { + stringOutputs.put(key, value.toString()); + } catch (Exception e) { + StringBuilder msg = new StringBuilder("Unable to add " + key + " to outputs"); + if (value instanceof Integer) { // nothing to add to the message + } else if (value instanceof JsonNode) { + msg.append(" - exception converting JsonNode"); + } else if (value instanceof java.util.LinkedHashMap) { + msg.append(" exception converting LinkedHashMap"); + } else { + msg.append(" - unable to call .toString() " + e.getMessage()); + } + LOGGER.debug(msg.toString(), e); + } + } + return stringOutputs; + } + + private Map <String, Object> copyStringInputs (Map <String, String> stringInputs) { + return new HashMap <> (stringInputs); + } + + protected boolean callHeatbridge(String heatStackId) { + String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge"; + String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = ""; + long waitTimeMs = 10000L; + try { + String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, tenant, region, owner, heatStackId}; + String[] envp = null; + File dir = new File(executionDir); + LOGGER.debug("Calling HeatBridgeMain.py in " + dir + " with arguments " + Arrays.toString(cmdarray)); + Runtime r = Runtime.getRuntime(); + Process p = r.exec(cmdarray, envp, dir); + boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS); + + LOGGER.debug(" HeatBridgeMain.py returned " + wait + " with code " + p.exitValue()); + return wait && p.exitValue()==0; + } catch (IOException e) { + LOGGER.debug(" HeatBridgeMain.py failed with IO Exception! " + e); + return false; + } catch (InterruptedException e) { + LOGGER.debug(" HeatBridgeMain.py failed when interrupted! " + e); + return false; + } catch (RuntimeException e) { + LOGGER.debug(" HeatBridgeMain.py failed for unknown reasons!" + e); + return false; + } + } + + private void sendMapToDebug(Map<String, Object> inputs, String optionalName) { + int i = 0; + StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName); + if (inputs == null) { + sb.append("\tNULL"); + } + else if (inputs.size() < 1) { + sb.append("\tEMPTY"); + } else { + for (Map.Entry<String,Object> entry : inputs.entrySet()) { + String outputString; + String str = entry.getKey(); + Object value = entry.getValue(); + try { + outputString = value.toString(); + } catch (Exception e) { + LOGGER.debug("Exception :",e); + outputString = "Unable to call toString() on the value for " + str; + } + sb.append("\t\nitem ").append(i++).append(": '").append(str).append("'='").append(outputString) + .append("'"); + } + } + LOGGER.debug(sb.toString()); + return; + } + + 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 (Map.Entry<String, String> entry: inputs.entrySet()) { + sb.append("\titem ").append(i++).append(": ").append(entry.getKey()).append("=").append(entry.getValue()); + } + } + LOGGER.debug(sb.toString()); + return; + } + + private String convertNode(final JsonNode node) { + try { + final Object obj = JSON_MAPPER.treeToValue(node, Object.class); + return JSON_MAPPER.writeValueAsString(obj); + } catch (JsonParseException jpe) { + LOGGER.debug("Error converting json to string " + jpe.getMessage(),jpe); + } catch (Exception e) { + LOGGER.debug("Error converting json to string " + e.getMessage(),e); + } + return "[Error converting json to string]"; + } + + private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) { + if (objectMap == null) { + return null; + } + Map<String, String> stringMap = new HashMap<>(); + for (String key : objectMap.keySet()) { + if (!stringMap.containsKey(key)) { + Object obj = objectMap.get(key); + if (obj instanceof String) { + stringMap.put(key, (String) objectMap.get(key)); + } else if (obj instanceof JsonNode ){ + // This is a bit of mess - but I think it's the least impacting + // let's convert it BACK to a string - then it will get converted back later + try { + String str = this.convertNode((JsonNode) obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key,e); + //okay in this instance - only string values (fqdn) are expected to be needed + } + } else if (obj instanceof java.util.LinkedHashMap) { + LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode"); + try { + String str = JSON_MAPPER.writeValueAsString(obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key,e); + } + } else if (obj instanceof Integer) { + try { + String str = "" + obj; + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key,e); + } + } else { + try { + String str = obj.toString(); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")",e); + } + } + } + } + + return stringMap; + } + + @Override + public void createVfModule(String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + String baseVfHeatStackId, + String modelCustomizationUuid, + Map <String, String> inputs, + Boolean failIfExists, + Boolean backout, + Boolean enableBridge, + MsoRequest msoRequest, + Holder <String> vnfId, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException { + String vfModuleName = vnfName; + String vfModuleType = vnfType; + String vfVersion = vnfVersion; + String mcu = modelCustomizationUuid; + boolean useMCUuid = false; + if (mcu != null && !mcu.isEmpty()) { + if ("null".equalsIgnoreCase(mcu)) { + LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid); + useMCUuid = false; + mcu = ""; + } else { + LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu); + useMCUuid = true; + } + } + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateVfModule"); + String requestTypeString = ""; + if (requestType != null && !"".equals(requestType)) { + requestTypeString = requestType; + } + String nestedStackId = null; + if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) { + nestedStackId = volumeGroupHeatStackId; + } + String nestedBaseStackId = null; + if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) { + nestedBaseStackId = baseVfHeatStackId; + } + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap<>(); + 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); + vfRollback.setModelCustomizationUuid(mcu); + + // Put data into A&AI through Heatstack + if(enableBridge != null && enableBridge) { + callHeatbridge(baseVfHeatStackId); + } + + 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 (); + Map<String, Object> nestedVolumeOutputs = null; + 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 *later*"); + //this.sendMapToDebug(inputs); + nestedVolumeOutputs = nestedHeatStack.getOutputs(); + this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs"); + //TODO + //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 (); + Map<String, Object> baseStackOutputs = null; + 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 - these values will be copied to inputs *later*"); + //this.sendMapToDebug(inputs); + baseStackOutputs = nestedBaseHeatStack.getOutputs(); + this.sendMapToDebug(baseStackOutputs, "baseStackOutputs"); + //TODO + //heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); + //this.sendMapToDebug(inputs); + } + } + + // Ready to deploy the new VNF + + + + try { + // Retrieve the VF + VfModule vf = null; + VnfResource vnfResource = null; + VfModuleCustomization vfmc = null; + LOGGER.debug("version: " + vfVersion); + if (useMCUuid) { + // 1707 - db refactoring + vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(mcu); + if(vfmc != null) + vf=vfmc.getVfModule(); + else + vf=null; + + // 1702 - this will be the new way going forward. We find the vf by mcu - otherwise, code is the same. + if (vf == null) { + LOGGER.debug("Unable to find vfModuleCust with modelCustomizationUuid=" + mcu); + String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + mcu; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", modelCustomizationUuid, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Unable to find vfModule with modelCustomizationUuid=" + mcu); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found vfModuleCust entry " + vfmc.toString()); + } + if (vf.getIsBase()) { + 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 { // This is to support gamma only - get info from vnf_resource table + if (vfVersion != null && !vfVersion.isEmpty()) { + vnfResource = vnfResourceRepo.findByModelNameAndModelVersion(vnfType, vnfVersion); + } else { + vnfResource = vnfResourceRepo.findByModelName(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 && vf.getVnfResources() != null) { + vnfResource = vf.getVnfResources(); + if (vnfResource == null) { + LOGGER.debug("Unable to find vnfResource 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",e); + minVersionVnf = null; + maxVersionVnf = null; + } + if (minVersionVnf != null && "".equals(minVersionVnf)) { + minVersionVnf = null; + } + if (maxVersionVnf != null && "".equals(maxVersionVnf)) { + maxVersionVnf = null; + } + } + if (minVersionVnf != null && maxVersionVnf != null) { + MavenLikeVersioning aicV = new MavenLikeVersioning(); + + // double check + if (this.cloudConfig != null) { + Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId); + if (cloudSiteOpt.isPresent()) { + aicV.setVersion(cloudSiteOpt.get().getAicVersion()); + // Add code to handle unexpected values in here + boolean moreThanMin = true; + boolean equalToMin = true; + boolean moreThanMax = true; + boolean equalToMax = true; + boolean doNotTest = false; + try { + moreThanMin = aicV.isMoreRecentThan(minVersionVnf); + equalToMin = aicV.isTheSameVersion(minVersionVnf); + moreThanMax = aicV.isMoreRecentThan(maxVersionVnf); + equalToMax = aicV.isTheSameVersion(maxVersionVnf); + } catch (Exception e) { + LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + " - will default to not check",e); + doNotTest = true; + } + if (!doNotTest) { + if ((moreThanMin || equalToMin) // aic >= min + && (equalToMax || !(moreThanMax))) { //aic <= max + LOGGER.debug("VNF Resource " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getAicVersion()); + } else { + // ERROR + String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getAicVersion(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + } else { + LOGGER.debug("bypassing testing AIC version..."); + } + } // 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; + + + + // By the time we get here - heatTemplateId and heatEnvtId should be populated (or null) + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (oldWay) { + //This will handle old Gamma BrocadeVCE VNF + heatTemplate = vnfResource.getHeatTemplates(); + } + else { + if (vf != null) { + if (isVolumeRequest) { + heatTemplate = vf.getVolumeHeatTemplate(); + heatEnvironment = vfmc.getVolumeHeatEnv(); + } else { + heatTemplate = vf.getModuleHeatTemplate(); + heatEnvironment = vfmc.getHeatEnvironment(); + } + } + } + + if (heatTemplate == 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 { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (oldWay) { + //This will handle old Gamma BrocadeVCE VNF + LOGGER.debug ("No environment parameter found for this Type " + vfModuleType); + } else { + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "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.getEnvironment()); + } + } + // Replace flavors in environment with those returned by OOF + if (!oldWay) { + Map<String, Object> returnMap = updateFlavorsFromOof(heatEnvironment.getEnvironment(), inputs); + String heatEnvironmentString = returnMap.get("heatEnvironmentString").toString(); + LOGGER.debug("After OOF Update Heat Env String is: " + heatEnvironmentString); + if (returnMap.get("inputs") instanceof Map) { + inputs = (Map<String, String>) returnMap.get("inputs"); + LOGGER.debug("After OOF Update inputs are: " + inputs.toString()); + } else { + LOGGER.debug("inputs is not an instance of a Map: " + returnMap.get("inputs")); + throw new VnfException("Updating inputs using OOF info failed.", MsoExceptionCategory.INTERNAL); + } + } + + LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId=" + + heatTemplate.getArtifactUuid ()); + + + List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates(); + Map <String, Object> nestedTemplatesChecked = new HashMap <> (); + if (nestedTemplates != null && !nestedTemplates.isEmpty()) { + // for debugging print them out + LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:"); + for (HeatTemplate entry : nestedTemplates) { + nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody()); + LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody()); + } + } else { + LOGGER.debug ("No nested templates found - nothing to do here"); + nestedTemplatesChecked = null; + } + + // 1510 - Also add the files: for any get_files associated with this vnf_resource_id + // *if* there are any + List<HeatFiles> heatFiles = null; + + Map<String, Object> heatFilesObjects = new HashMap<>(); + + // Add ability to turn on adding get_files with volume requests (by property). + boolean addGetFilesOnVolumeReq = false; + try { + String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ); + 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, this should not happen - old way is gamma only - no heat files!"); + } else { + // 1607 - now use VF_MODULE_TO_HEAT_FILES table + LOGGER.debug("In MsoVnfAdapterImpl createVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId=" + + vf.getModelUUID()); + heatFiles = vf.getHeatFiles(); + } + if (heatFiles != null && !heatFiles.isEmpty()) { + // 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(HeatFiles heatfile : heatFiles){ + LOGGER.debug(heatfile.getFileName() + " -> " + + heatfile.getFileBody()); + heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody()); + } + } 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 <> (); + + // 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 checkRequiredParameters = true; + try { + String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + 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 (heatEnvironment != null && heatEnvironment.getEnvironment() != null && heatEnvironment.getEnvironment().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"); + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + //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 with 1707 - all variables converted to their native object types + Map<String, Object> goldenInputs = null; + + LOGGER.debug("Now handle the inputs....first convert"); + ArrayList<String> parameterNames = new ArrayList<>(); + HashMap<String, String> aliasToParam = new HashMap<>(); + StringBuilder sb = new StringBuilder("\nTemplate Parameters:\n"); + int cntr = 0; + try { + for (HeatTemplateParam htp : heatTemplate.getParameters()) { + sb.append("param[" + cntr++ + "]=" + htp.getParamName()); + parameterNames.add(htp.getParamName()); + if (htp.getParamAlias() != null && !"".equals(htp.getParamAlias())) { + aliasToParam.put(htp.getParamAlias(), htp.getParamName()); + sb.append(" ** (alias=" + htp.getParamAlias() + ")"); + } + sb.append("\n"); + } + LOGGER.debug(sb.toString()); + } catch (Exception e) { + LOGGER.debug("??An exception occurred trying to go through Parameter Names " + e.getMessage(),e); + } + // Step 1 - convert what we got as inputs (Map<String, String>) to a + // Map<String, Object> - where the object matches the param type identified in the template + // This will also not copy over params that aren't identified in the template + goldenInputs = heat.convertInputMap(inputs, heatTemplate); + // Step 2 - now simply add the outputs as we received them - no need to convert to string + LOGGER.debug("Now add in the base stack outputs if applicable"); + heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam); + // Step 3 - add the volume inputs if any + LOGGER.debug("Now add in the volume stack outputs if applicable"); + heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam); + this.sendMapToDebug(goldenInputs, "Final inputs sent to openstack"); + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + LOGGER.debug ("Parameter:'" + parm.getParamName () + + "', isRequired=" + + parm.isRequired () + + ", alias=" + + parm.getParamAlias ()); + + if (parm.isRequired () && (goldenInputs == null || !goldenInputs.containsKey (parm.getParamName ()))) { + // The check for an alias was moved to the method in MsoHeatUtils - when we converted the Map<String, String> to Map<String, Object> + LOGGER.debug("**Parameter " + parm.getParamName() + " is required and not in the inputs...check environment"); + 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"); + } + // We can now remove the recreating of the ENV with only legit params - that check is done for us, + // and it causes problems with json that has arrays + String newEnvironmentString = null; + if (mhee != null) { + newEnvironmentString = mhee.getRawEntry().toString(); + } + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + // Valet - 1806 + boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false); + boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false); + LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure); + if (oldWay || isVolumeRequest) { + isValetEnabled = false; + LOGGER.debug("do not send to valet for volume requests or brocade"); + } + boolean sendResponseToValet = false; + if (isValetEnabled) { + Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>(); + sendResponseToValet = this.valetCreateRequest(cloudSiteId, tenantId, heatFilesObjects, + nestedTemplatesChecked, vfModuleName, backout, heatTemplate, newEnvironmentString, goldenInputs, + msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder); + if (sendResponseToValet) { + goldenInputs = valetModifiedParamsHolder.value; + } + } + + // 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!!"); + + heatStack = heat.createStack (cloudSiteId, + tenantId, + vfModuleName, + template, + goldenInputs, + true, + heatTemplate.getTimeoutMinutes(), + newEnvironmentString, + nestedTemplatesChecked, + heatFilesObjects, + backout.booleanValue()); + } + else { + LOGGER.debug("heat is null!"); + throw new MsoHeatNotFoundException(); + } + 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); + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet"); + try { + GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, backout, me.getMessage()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Rollback to Valet ", e); + } + } + 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",e); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating stack with OpenStack"); + throw new VnfException("Exception during heat.createStack! " + 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; + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the orchestration succeeded - now send confirm to valet with stack id"); + try { + GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Confirm to Valet ", e); + } + } + LOGGER.debug ("VF Module " + vfModuleName + " successfully created"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module"); + return; + } catch (Exception e) { + LOGGER.debug("unhandled exception in create VF",e); + throw new VnfException("Exception during create VF " + e.getMessage()); + } + } + + @Override + public void deleteVfModule (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest, + Holder <Map <String, String>> outputs) 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 (); + + // 1702 capture the output parameters on a delete + // so we'll need to query first + Map<String, Object> stackOutputs = null; + try { + stackOutputs = heat.queryStackForOutputs(cloudSiteId, tenantId, vnfName); + } catch (MsoException me) { + // Failed to query the Stack due to an openstack exception. + // Convert to a generic VnfException + me.addContext ("DeleteVFModule"); + String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (startTime, 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 - QueryStack", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types + outputs.value = this.convertMapStringObjectToStringString(stackOutputs); + + boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false); + boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false); + LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure); + boolean valetDeleteRequestSucceeded = false; + if (isValetEnabled) { + valetDeleteRequestSucceeded = this.valetDeleteRequest(cloudSiteId, tenantId, vnfName, msoRequest, failRequestOnValetFailure); + } + + // 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); + if (isValetEnabled && valetDeleteRequestSucceeded) { + LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet"); + try { + GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), vnfName, false, me.getMessage()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Rollback to Valet ", e); + } + } + throw new VnfException (me); + } + if (isValetEnabled && valetDeleteRequestSucceeded) { + // only if the original request succeeded do we send a confirm + LOGGER.debug("valet is enabled, the delete succeeded - now send confirm to valet"); + try { + GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), vnfName); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Confirm to Valet ", e); + } + } + + // 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, + String modelCustomizationUuid, + Map <String, String> inputs, + MsoRequest msoRequest, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException { + String vfModuleName = vnfName; + String vfModuleType = vnfType; + String methodName = "updateVfModule"; + MsoLogger.setLogContext (msoRequest.getRequestId (), msoRequest.getServiceInstanceId ()); + String serviceName = VNF_ADAPTER_SERVICE_NAME + methodName; + MsoLogger.setServiceName (serviceName); + + StringBuilder sbInit = new StringBuilder(); + sbInit.append("updateVfModule: \n"); + sbInit.append("cloudSiteId=" + cloudSiteId + "\n"); + sbInit.append("tenantId=" + tenantId + "\n"); + sbInit.append("vnfType=" + vnfType + "\n"); + sbInit.append("vnfVersion=" + vnfVersion + "\n"); + sbInit.append("vnfName=" + vnfName + "\n"); + sbInit.append("requestType=" + requestType + "\n"); + sbInit.append("volumeGroupHeatStackId=" + volumeGroupHeatStackId + "\n"); + sbInit.append("baseVfHeatStackId=" + baseVfHeatStackId + "\n"); + sbInit.append("vfModuleStackId=" + vfModuleStackId + "\n"); + sbInit.append("modelCustomizationUuid=" + modelCustomizationUuid + "\n"); + LOGGER.debug(sbInit.toString()); + + String mcu = modelCustomizationUuid; + boolean useMCUuid = false; + if (mcu != null && !mcu.isEmpty()) { + if (mcu.equalsIgnoreCase("null")) { + LOGGER.debug("modelCustomizationUuid: passed in as the string 'null' - will ignore: " + modelCustomizationUuid); + useMCUuid = false; + mcu = ""; + } else { + LOGGER.debug("Found modelCustomizationUuid! Will use that: " + mcu); + useMCUuid = true; + } + } + + String requestTypeString = ""; + if (requestType != null && !"".equals(requestType)) { + requestTypeString = requestType; + } + + String nestedStackId = null; + if (volumeGroupHeatStackId != null && !"".equals(volumeGroupHeatStackId) && !"null".equalsIgnoreCase(volumeGroupHeatStackId)) { + nestedStackId = volumeGroupHeatStackId; + } + String nestedBaseStackId = null; + if (baseVfHeatStackId != null && !"".equals(baseVfHeatStackId) && !"null".equalsIgnoreCase(baseVfHeatStackId)) { + nestedBaseStackId = baseVfHeatStackId; + } + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap<>(); + 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 || "".equals(vfModuleName.trim())) && vfModuleStackId != null) { + vfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId); + } + + LOGGER.debug ("Updating VFModule: " + vfModuleName + " of type " + vfModuleType + "in " + cloudSiteId + "/" + tenantId); + LOGGER.debug("requestTypeString = " + requestTypeString + ", nestedVolumeStackId = " + 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); + vfRollback.setModelCustomizationUuid(mcu); + + 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 (); + Map<String, Object> nestedVolumeOutputs = null; + 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 *later*"); + nestedVolumeOutputs = nestedHeatStack.getOutputs(); + //this.sendMapToDebug(inputs); + this.sendMapToDebug(nestedVolumeOutputs, "volumeStackOutputs"); + //TODO + 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; + Map<String, Object> baseStackOutputs = 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 *later*"); + baseStackOutputs = nestedBaseHeatStack.getOutputs(); + //this.sendMapToDebug(inputs); + this.sendMapToDebug(baseStackOutputs, "baseStackOutputs"); + //TODO + heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); + //this.sendMapToDebug(inputs); + } + } + + // Ready to deploy the new VNF + + + + // Retrieve the VF definition + VnfResource vnfResource = null; + VfModule vf = null; + VfModuleCustomization vfmc = null; + if (useMCUuid){ + vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid); + vf = vfmc != null ? vfmc.getVfModule() : null; + if (vf == null) { + LOGGER.debug("Unable to find a vfModule matching modelCustomizationUuid=" + mcu); + } + } else { + LOGGER.debug("1707 and later - MUST PROVIDE Model Customization UUID!"); + } + if (vf == null) { + String error = "Update VfModule: unable to find vfModule with modelCustomizationUuid=" + mcu; + 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 ()); + if (vf.getIsBase()) { + isBaseRequest = true; + LOGGER.debug("This a BASE update request"); + } else { + LOGGER.debug("This is *not* a BASE VF update request"); + if (!isVolumeRequest && nestedBaseStackId == null) { + LOGGER.debug("DANGER WILL ROBINSON! This is unexpected - no nestedBaseStackId with this non-base request"); + } + } + + //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 (vf.getModelUUID() != null) { + String vnfResourceModelUuid = vf.getModelUUID(); + + vnfResource = vf.getVnfResources(); + if (vnfResource == null) { + LOGGER.debug("Unable to find vnfResource at " + vnfResourceModelUuid + " 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",e); + minVersionVnf = null; + maxVersionVnf = null; + } + if (minVersionVnf != null && "".equals(minVersionVnf)) { + minVersionVnf = null; + } + if (maxVersionVnf != null && "".equals(maxVersionVnf)) { + maxVersionVnf = null; + } + } + if (minVersionVnf != null && maxVersionVnf != null) { + MavenLikeVersioning aicV = new MavenLikeVersioning(); + + // double check + if (this.cloudConfig != null) { + Optional<CloudSite> cloudSiteOpt = this.cloudConfig.getCloudSite(cloudSiteId); + if (cloudSiteOpt.isPresent()) { + aicV.setVersion(cloudSiteOpt.get().getAicVersion()); + boolean moreThanMin = true; + boolean equalToMin = true; + boolean moreThanMax = true; + boolean equalToMax = true; + boolean doNotTest = false; + try { + moreThanMin = aicV.isMoreRecentThan(minVersionVnf); + equalToMin = aicV.isTheSameVersion(minVersionVnf); + moreThanMax = aicV.isMoreRecentThan(maxVersionVnf); + equalToMax = aicV.isTheSameVersion(maxVersionVnf); + } catch (Exception e) { + LOGGER.debug("An exception occured while trying to test AIC Version " + e.getMessage() + + " - will default to not check", e); + doNotTest = true; + } + if (!doNotTest) { + if ((moreThanMin || equalToMin) // aic >= min + && ((equalToMax) || !(moreThanMax))) { // aic <= max + LOGGER.debug("VNF Resource " + vnfResource.getModelName() + " VersionMin=" + minVersionVnf + + " VersionMax:" + maxVersionVnf + " supported on Cloud: " + cloudSiteId + + " with AIC_Version:" + aicV); + } else { + // ERROR + String error = "VNF Resource type: " + vnfResource.getModelName() + " VersionMin=" + + minVersionVnf + " VersionMax:" + maxVersionVnf + " NOT supported on Cloud: " + + cloudSiteId + " with AIC_Version:" + aicV; + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", + MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + } else { + LOGGER.debug("bypassing testing AIC version..."); + } + } // 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 - do not error for now - not checked."); + } + // End Version check 1607 + + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (isVolumeRequest) { + heatTemplate = vf.getVolumeHeatTemplate(); + heatEnvironment = vfmc.getVolumeHeatEnv(); + } else { + heatTemplate = vf.getModuleHeatTemplate(); + heatEnvironment = vfmc.getHeatEnvironment(); + } + + if (heatTemplate == 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 { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "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.getEnvironment()); + } + + LOGGER.debug ("In MsoVnfAdapterImpl, about to call db.getNestedTemplates avec templateId=" + + heatTemplate.getArtifactUuid ()); + + + List<HeatTemplate> nestedTemplates = heatTemplate.getChildTemplates(); + Map <String, Object> nestedTemplatesChecked = new HashMap <> (); + if (nestedTemplates != null && !nestedTemplates.isEmpty()) { + // for debugging print them out + LOGGER.debug ("Contents of nestedTemplates - to be added to files: on stack:"); + for (HeatTemplate entry : nestedTemplates) { + + nestedTemplatesChecked.put (entry.getTemplateName(), entry.getTemplateBody()); + LOGGER.debug (entry.getTemplateName() + " -> " + entry.getTemplateBody()); + } + } 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.getModelUUID()); + + List<HeatFiles> heatFiles = null; + Map <String, Object> heatFilesObjects = new HashMap <> (); + + // Add ability to turn on adding get_files with volume requests (by property). + boolean addGetFilesOnVolumeReq = false; + try { + String propertyString = this.environment.getProperty(MsoVnfAdapterImpl.ADD_GET_FILES_ON_VOLUME_REQ); + 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) { + LOGGER.debug("In MsoVnfAdapterImpl updateVfModule, about to call db.getHeatFilesForVfModule avec vfModuleId=" + + vf.getModelUUID()); + + heatFiles = vf.getHeatFiles(); + if (heatFiles != null && !heatFiles.isEmpty()) { + // 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(HeatFiles heatfile : heatFiles){ + LOGGER.debug(heatfile.getFileName() + " -> " + + heatfile.getFileBody()); + heatFilesObjects.put(heatfile.getFileName(), heatfile.getFileBody()); + } + } 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 <> (); + + // 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 checkRequiredParameters = true; + try { + String propertyString = this.environment.getProperty (MsoVnfAdapterImpl.CHECK_REQD_PARAMS); + 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 (heatEnvironment != null && heatEnvironment.getEnvironment().toLowerCase ().contains ("parameters:")) { + LOGGER.debug("Enhanced environment checking enabled - 1604"); + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + 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<>(); + 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 || "".equals(parameterType.trim())) { + parameterType = "String"; + } + JsonNode jsonNode = null; + if ("json".equalsIgnoreCase(parameterType) && 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,jpe); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e); + 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,jpe); + hasJson = false; + jsonNode = null; + } catch (Exception e) { + // or here? + LOGGER.debug("Json Error Converting " + parm.getParamName() + " " + e.getMessage(),e); + 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"); + } + + // Just submit the envt entry as received from the database + String newEnvironmentString = null; + if (mhee != null) { + newEnvironmentString = mhee.getRawEntry().toString(); + } + // Remove any extraneous parameters (don't throw an error) + if (inputs != null) { + List <String> extraParams = new ArrayList <> (); + 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); + } + } + Map<String, Object> goldenInputs = copyStringInputs(inputs); + // 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<>(); + for (Map.Entry<String, String> entry : inputs.entrySet()) { + String keyParamName = entry.getKey(); + String value = entry.getValue(); + if (jsonParams.containsKey(keyParamName)) { + inputsTwo.put(keyParamName, jsonParams.get(keyParamName)); + } else { + inputsTwo.put(keyParamName, value); + } + } + goldenInputs = inputsTwo; + } + + // "Fix" the template if it has CR/LF (getting this from Oracle) + String template = heatTemplate.getHeatTemplate (); + template = template.replaceAll ("\r\n", "\n"); + + boolean isValetEnabled = this.checkBooleanProperty(MsoVnfAdapterImpl.VALET_ENABLED, false); + boolean failRequestOnValetFailure = this.checkBooleanProperty(MsoVnfAdapterImpl.FAIL_REQUESTS_ON_VALET_FAILURE, false); + LOGGER.debug("isValetEnabled=" + isValetEnabled + ", failRequestsOnValetFailure=" + failRequestOnValetFailure); + if (isVolumeRequest) { + isValetEnabled = false; + LOGGER.debug("never send a volume request to valet"); + } + boolean sendResponseToValet = false; + if (isValetEnabled) { + Holder<Map<String, Object>> valetModifiedParamsHolder = new Holder<>(); + String parsedVfModuleName = this.getVfModuleNameFromModuleStackId(vfModuleStackId); + // Make sure it is set to something. + if (parsedVfModuleName == null || parsedVfModuleName.isEmpty()) { + parsedVfModuleName = "unknown"; + } + sendResponseToValet = this.valetUpdateRequest(cloudSiteId, tenantId, heatFilesObjects, + nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, (HashMap<String, Object>) goldenInputs, + msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder); + if (sendResponseToValet) { + goldenInputs = valetModifiedParamsHolder.value; + } + } + + // 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, + vfModuleName, + template, + goldenInputs, + 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); + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the orchestration failed - now sending rollback to valet"); + try { + GenericValetResponse<ValetRollbackResponse> gvr = this.vci.callValetRollbackRequest(msoRequest.getRequestId(), null, false, me.getMessage()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Rollback response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Rollback to Valet ", e); + } + } + 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); + + if (isValetEnabled && sendResponseToValet) { + LOGGER.debug("valet is enabled, the update succeeded - now send confirm to valet with stack id"); + try { + GenericValetResponse<ValetConfirmResponse> gvr = this.vci.callValetConfirmRequest(msoRequest.getRequestId(), heatStack.getCanonicalName()); + // Nothing to really do here whether it succeeded or not other than log it. + LOGGER.debug("Return code from Confirm response is " + gvr.getStatusCode()); + } catch (Exception e) { + LOGGER.error("Exception encountered while sending Confirm to Valet ", e); + } + } + + 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) { + LOGGER.debug("Exception", e); + vfModuleName = null; + } + return vfModuleName; + } + + private Map<String, Object> updateFlavorsFromOof(String heatEnvironmentString, Map<String, String> inputs) { + Map<String, Object> returnMap = new HashMap<>(); + for (Map.Entry<String, String> input : inputs.entrySet()){ + if (heatEnvironmentString.contains("label_" + input.getKey())){ + heatEnvironmentString = heatEnvironmentString.replace("label_" + input.getKey(), + input.getValue()); + inputs.remove("label_" + input.getKey()); + } + } + returnMap.put("heatEnvironmentString", heatEnvironmentString); + returnMap.put("inputs", inputs); + return returnMap; + } + /* + * Helper method to check a boolean property value - on error return provided default + */ + private boolean checkBooleanProperty(String propertyName, boolean defaultValue) { + boolean property = defaultValue; + try { + String propertyString = this.environment.getProperty(propertyName); + if ("true".equalsIgnoreCase(propertyString) || "y".equalsIgnoreCase(propertyString)) { + property = true; + } else if ("false".equalsIgnoreCase(propertyString) || "n".equalsIgnoreCase(propertyString)) { + property = false; + } + } catch (Exception e) { + LOGGER.debug ("An exception occured trying to get property " + propertyName + " - defaulting to " + defaultValue, e); + property = defaultValue; + } + return property; + } + + /* + * Helper method to combine getFiles and nestedTemplates in to a single Map + */ + private Map<String, Object> combineGetFilesAndNestedTemplates(Map<String, Object> getFiles, Map<String, Object> nestedTemplates) { + boolean haveGetFiles = true; + boolean haveNestedTemplates = true; + Map<String, Object> files = new HashMap<String, Object>(); + if (getFiles == null || getFiles.isEmpty()) { + haveGetFiles = false; + } + if (nestedTemplates == null || nestedTemplates.isEmpty()) { + haveNestedTemplates = false; + } + if (haveGetFiles && haveNestedTemplates) { + for (String keyString : getFiles.keySet ()) { + files.put (keyString, getFiles.get (keyString)); + } + for (String keyString : nestedTemplates.keySet ()) { + files.put (keyString, nestedTemplates.get (keyString)); + } + } else { + // Handle if we only have one or neither: + if (haveGetFiles) { + files = getFiles; + } + if (haveNestedTemplates) { + files = nestedTemplates; + } + } + return files; + } + + /* + * Valet Create request + */ + private boolean valetCreateRequest(String cloudSiteId, String tenantId, Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, + String vfModuleName, boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, Map<String, Object> goldenInputs, + MsoRequest msoRequest, Map<String, String> inputs, boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException { + boolean valetSucceeded = false; + String valetErrorMessage = "more detail not available"; + try { + String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId); + Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects, + nestedTemplatesChecked); + HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(), + heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs); + GenericValetResponse<ValetCreateResponse> createReq = this.vci.callValetCreateRequest(msoRequest.getRequestId(), + cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), inputs.get("vnf_id"), + inputs.get("vnf_name"), inputs.get("vf_module_id"), inputs.get("vf_module_name"), keystoneUrl, + heatRequest); + ValetCreateResponse vcr = createReq.getReturnObject(); + if (vcr != null && createReq.getStatusCode() == 200) { + ValetStatus status = vcr.getStatus(); + if (status != null) { + String statusCode = status.getStatus(); // "ok" or "failed" + if ("ok".equalsIgnoreCase(statusCode)) { + Map<String, Object> newInputs = vcr.getParameters(); + if (newInputs != null) { + Map<String, Object> oldGold = goldenInputs; + LOGGER.debug("parameters before being modified by valet:" + oldGold.toString()); + goldenInputs = new HashMap<String, Object>(); + for (String key : newInputs.keySet()) { + goldenInputs.put(key, newInputs.get(key)); + } + valetModifiedParamsHolder.value = goldenInputs; + LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString()); + valetSucceeded = true; + } + } else { + valetErrorMessage = status.getMessage(); + } + } + } else { + LOGGER.debug("Got a bad response back from valet"); + valetErrorMessage = "Bad response back from Valet"; + valetSucceeded = false; + } + } catch (Exception e) { + LOGGER.error("An exception occurred trying to call valet ...", e); + valetSucceeded = false; + valetErrorMessage = e.getMessage(); + } + if (failRequestOnValetFailure && !valetSucceeded) { + // The valet request failed - and property says to fail the request + //TODO Create a new exception class for valet? + throw new VnfException("A failure occurred with Valet: " + valetErrorMessage); + } + return valetSucceeded; + } + + /* + * Valet update request + */ + + private boolean valetUpdateRequest(String cloudSiteId, String tenantId, + Map<String, Object> heatFilesObjects, Map<String, Object> nestedTemplatesChecked, String vfModuleName, + boolean backout, HeatTemplate heatTemplate, String newEnvironmentString, + Map<String, Object> goldenInputs, MsoRequest msoRequest, Map<String, String> inputs, + boolean failRequestOnValetFailure, Holder<Map<String, Object>> valetModifiedParamsHolder) throws VnfException { + + boolean valetSucceeded = false; + String valetErrorMessage = "more detail not available"; + try { + String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId); + Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects, + nestedTemplatesChecked); + HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(), + heatTemplate.getTemplateBody(), newEnvironmentString, files, goldenInputs); + // vnf name is not sent to MSO on update requests - so we will set it to the vf module name for now + GenericValetResponse<ValetUpdateResponse> updateReq = this.vci.callValetUpdateRequest(msoRequest.getRequestId(), + cloudSiteId, tenantId, msoRequest.getServiceInstanceId(), inputs.get("vnf_id"), + vfModuleName, inputs.get("vf_module_id"), vfModuleName, keystoneUrl, + heatRequest); + ValetUpdateResponse vur = updateReq.getReturnObject(); + if (vur != null && updateReq.getStatusCode() == 200) { + ValetStatus status = vur.getStatus(); + if (status != null) { + String statusCode = status.getStatus(); // "ok" or "failed" + if ("ok".equalsIgnoreCase(statusCode)) { + Map<String, Object> newInputs = vur.getParameters(); + if (newInputs != null) { + Map<String, Object> oldGold = goldenInputs; + LOGGER.debug("parameters before being modified by valet:" + oldGold.toString()); + goldenInputs = new HashMap<String, Object>(); + for (String key : newInputs.keySet()) { + goldenInputs.put(key, newInputs.get(key)); + } + valetModifiedParamsHolder.value = goldenInputs; + LOGGER.debug("parameters after being modified by valet:" + goldenInputs.toString()); + valetSucceeded = true; + } + } else { + valetErrorMessage = status.getMessage(); + } + } + } else { + LOGGER.debug("Got a bad response back from valet"); + valetErrorMessage = "Got a bad response back from valet"; + valetSucceeded = false; + } + } catch (Exception e) { + LOGGER.error("An exception occurred trying to call valet - will continue processing for now...", e); + valetErrorMessage = e.getMessage(); + valetSucceeded = false; + } + if (failRequestOnValetFailure && !valetSucceeded) { + // The valet request failed - and property says to fail the request + // TODO Create a new exception class for valet? + throw new VnfException("A failure occurred with Valet: " + valetErrorMessage); + } + return valetSucceeded; + } + + /* + * Valet delete request + */ + private boolean valetDeleteRequest(String cloudSiteId, String tenantId, String vnfName, + MsoRequest msoRequest, boolean failRequestOnValetFailure) { + boolean valetDeleteRequestSucceeded = false; + String valetErrorMessage = "more detail not available"; + try { + String vfModuleId = vnfName; + String vfModuleName = vnfName; + try { + vfModuleName = vnfName.substring(0, vnfName.indexOf('/')); + vfModuleId = vnfName.substring(vnfName.indexOf('/') + 1); + } catch (Exception e) { + // do nothing - send what we got for vnfName for both to valet + } + GenericValetResponse<ValetDeleteResponse> deleteReq = this.vci.callValetDeleteRequest(msoRequest.getRequestId(), + cloudSiteId, tenantId, vfModuleId, vfModuleName); + ValetDeleteResponse vdr = deleteReq.getReturnObject(); + if (vdr != null && deleteReq.getStatusCode() == 200) { + ValetStatus status = vdr.getStatus(); + if (status != null) { + String statusCode = status.getStatus(); // "ok" or "failed" + if ("ok".equalsIgnoreCase(statusCode)) { + LOGGER.debug("delete request to valet returned success"); + valetDeleteRequestSucceeded = true; + } else { + LOGGER.debug("delete request to valet returned failure"); + valetDeleteRequestSucceeded = false; + valetErrorMessage = status.getMessage(); + } + } + } else { + LOGGER.debug("Got a bad response back from valet - delete request failed"); + valetDeleteRequestSucceeded = false; + valetErrorMessage = "Got a bad response back from valet - delete request failed"; + } + } catch (Exception e) { + LOGGER.error("An exception occurred trying to call valet - valetDeleteRequest failed", e); + valetDeleteRequestSucceeded = false; + valetErrorMessage = e.getMessage(); + } + if (valetDeleteRequestSucceeded == false && failRequestOnValetFailure == true) { + LOGGER.error("ValetDeleteRequestFailed - del req still will be sent to openstack", new VnfException("ValetDeleteRequestFailedError")); + } + return valetDeleteRequestSucceeded; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java new file mode 100644 index 0000000000..0266e87523 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java @@ -0,0 +1,1218 @@ +/*- + * ============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.onap.so.adapters.vnf; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.cloudify.beans.DeploymentInfo; +import org.onap.so.cloudify.beans.DeploymentStatus; +import org.onap.so.cloudify.exceptions.MsoCloudifyManagerNotFound; +import org.onap.so.cloudify.utils.MsoCloudifyUtils; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatFiles; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.HeatTemplateParam; +import org.onap.so.db.catalog.beans.VfModule; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.onap.so.db.catalog.beans.VnfResource; +import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.MsoTenant; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry; +import org.onap.so.openstack.utils.MsoHeatEnvironmentParameter; +import org.onap.so.openstack.utils.MsoKeystoneUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Transactional +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf") +public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter { + + 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, MsoVnfCloudifyAdapterImpl.class); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters"; + private static final String ADD_GET_FILES_ON_VOLUME_REQ = "org.onap.so.adapters.vnf.addGetFilesOnVolumeReq"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + + @Autowired + protected CloudConfig cloudConfig; + + @Autowired + private VFModuleCustomizationRepository vfModuleCustomRepo; + + @Autowired + private Environment environment; + + @Autowired + protected MsoKeystoneUtils keystoneUtils; + + @Autowired + protected MsoCloudifyUtils cloudifyUtils; + /** + * 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 Cloudify Adapter"); + } + + /** + * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL. + * @see MsoVnfCloudifyAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory) + */ + public MsoVnfCloudifyAdapterImpl() { + + } + + /** + * This is the "Create VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @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, + Boolean enableBridge, + MsoRequest msoRequest, + Holder <String> vnfId, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) + throws VnfException + { + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("CreateVNF command attempted but not supported"); + throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * This is the "Update VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @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 + { + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("UpdateVNF command attempted but not supported"); + throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * This is the "Query VNF" web service implementation. + * + * This really should be QueryVfModule, but nobody ever changed it. + * + * For Cloudify, this will look up a deployment by its deployment ID, which is really the same + * as deployment name, since it assigned by the client when a deployment is created. + * Also, the input cloudSiteId is used only to identify which Cloudify instance to query, + * and the tenantId is ignored (since that really only applies for Openstack/Heat). + * + * The method returns an indicator that the VNF exists, along with its status and outputs. + * The input "vnfName" will also be reflected back as its ID. + * + * @param cloudSiteId CLLI code of the cloud site in which to query + * @param tenantId Openstack tenant identifier - ignored for Cloudify + * @param vnfName VNF Name (should match a deployment ID) + * @param msoRequest Request tracking information for logs + * @param vnfExists Flag reporting the result of the query + * @param vnfId Holder for output VNF ID + * @param outputs Holder for Map of VNF outputs from Cloudify deployment (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 ("QueryVnfCloudify"); + LOGGER.debug ("Querying VNF " + vnfName + " in " + cloudSiteId + "/" + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + long subStartTime = System.currentTimeMillis (); + + DeploymentInfo deployment = null; + + try { + deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "QueryDeployment", vnfName); + } + catch (MsoCloudifyManagerNotFound e) { + // This site does not have a Cloudify Manager. + // This isn't an error, just means we won't find the VNF here. + deployment = null; + } + catch (MsoException me) { + // Failed to query the Deployment due to a cloudify exception. + // Convert to a generic VnfException + me.addContext ("QueryVNF"); + String error = "Query VNF (Cloudify): " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", vnfName); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "Cloudify", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + + if (deployment != null && deployment.getStatus() != DeploymentStatus.NOTFOUND) { + vnfExists.value = Boolean.TRUE; + status.value = deploymentStatusToVnfStatus(deployment); + vnfId.value = deployment.getId(); + outputs.value = copyStringOutputs (deployment.getOutputs ()); + + LOGGER.debug ("VNF " + vnfName + " found in Cloudify, ID = " + vnfId.value); + } + else { + 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"); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF"); + return; + } + + + /** + * This is the "Delete VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @Override + public void deleteVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVnf"); + + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("DeleteVNF command attempted but not supported"); + throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * 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. + * + * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, + * but APIs were apparently never updated. + */ + @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", MsoLogger.getServiceName()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null"); + return; + } + + // Don't rollback if nothing was done originally + if (!rollback.getVnfCreated()) { + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back"); + return; + } + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudSiteId (); + String tenantId = rollback.getTenantId (); + String vfModuleId = rollback.getVfModuleStackId (); + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId); + + DeploymentInfo deployment = null; + + // Use the MsoCloudifyUtils to delete the deployment. 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 { + // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID. + // Go directly to Keystone until APIs could be updated to supply the name. + MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId); + String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId); + + // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that. + deployment = cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantName, vfModuleId, 5); + LOGGER.debug("Rolled back deployment: " + deployment.getId()); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "DeleteDeployment", null); + } catch (MsoException me) { + // Failed to rollback the VNF due to a cloudify exception. + // Convert to a generic VnfException + me.addContext ("RollbackVNF"); + String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "DeleteDeployment", null); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "Cloudify", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment", 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 VF Module"); + return; + } + + + private VnfStatus deploymentStatusToVnfStatus (DeploymentInfo deployment) { + // Determine the status based on last action & status + // DeploymentInfo object should be enhanced to report a better status internally. + DeploymentStatus status = deployment.getStatus(); + String lastAction = deployment.getLastAction(); + + if (status == null || lastAction == null) { + return VnfStatus.UNKNOWN; + } + else if (status == DeploymentStatus.NOTFOUND) { + return VnfStatus.NOTFOUND; + } + else if (status == DeploymentStatus.INSTALLED) { + return VnfStatus.ACTIVE; + } + else if (status == DeploymentStatus.CREATED) { + // Should have an INACTIVE status for this case. Shouldn't really happen, but + // Install was never run, or Uninstall was done but deployment didn't get deleted. + return VnfStatus.UNKNOWN; + } + else if (status == DeploymentStatus.FAILED) { + return VnfStatus.FAILED; + } + + 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)); + } else if (stackOutputs.get(key) instanceof Integer) { + try { + String str = "" + stackOutputs.get(key); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs"); + } + } else if (stackOutputs.get(key) instanceof JsonNode) { + try { + String str = this.convertNode((JsonNode) stackOutputs.get(key)); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode"); + } + } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) { + try { + String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key)); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap"); + } + } else { + try { + String str = stackOutputs.get(key).toString(); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage()); + } + } + } + return stringOutputs; + } + + + private void sendMapToDebug(Map<String, Object> inputs, String optionalName) { + int i = 0; + StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName); + if (inputs == null) { + sb.append("\tNULL"); + } + else if (inputs.size() < 1) { + sb.append("\tEMPTY"); + } else { + for (String str : inputs.keySet()) { + String outputString; + try { + outputString = inputs.get(str).toString(); + } catch (Exception e) { + outputString = "Unable to call toString() on the value for " + str; + } + sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'"); + } + } + LOGGER.debug(sb.toString()); + return; + } + + 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; + } + + private String convertNode(final JsonNode node) { + try { + final Object obj = JSON_MAPPER.treeToValue(node, Object.class); + final String json = JSON_MAPPER.writeValueAsString(obj); + return json; + } catch (JsonParseException jpe) { + LOGGER.debug("Error converting json to string " + jpe.getMessage()); + } catch (Exception e) { + LOGGER.debug("Error converting json to string " + e.getMessage()); + } + return "[Error converting json to string]"; + } + + private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) { + if (objectMap == null) { + return null; + } + Map<String, String> stringMap = new HashMap<String, String>(); + for (String key : objectMap.keySet()) { + if (!stringMap.containsKey(key)) { + Object obj = objectMap.get(key); + if (obj instanceof String) { + stringMap.put(key, (String) objectMap.get(key)); + } else if (obj instanceof JsonNode ){ + // This is a bit of mess - but I think it's the least impacting + // let's convert it BACK to a string - then it will get converted back later + try { + String str = this.convertNode((JsonNode) obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key); + //okay in this instance - only string values (fqdn) are expected to be needed + } + } else if (obj instanceof java.util.LinkedHashMap) { + LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode"); + try { + String str = JSON_MAPPER.writeValueAsString(obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key); + } + } else if (obj instanceof Integer) { + try { + String str = "" + obj; + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key); + } + } else { + try { + String str = obj.toString(); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")"); + } + } + } + } + + return stringMap; + } + + /** + * This is the "Create VF Module" web service implementation. + * It will instantiate a new VF Module of the requested type in the specified cloud + * and tenant. The tenant must exist before this service is called. + * + * If a VF Module with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * All VF Modules are defined in the MSO catalog. The caller must request + * one of the pre-defined module types or an error will be returned. Within the + * catalog, each VF Module references (among other things) a cloud template + * which is used to deploy the required artifacts (VMs, networks, etc.) + * to the cloud. In this adapter implementation, that artifact is expected + * to be a Cloudify blueprint. + * + * Depending on the blueprint, 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 module or an error will be thrown. + * + * The method returns the vfModuleId, a Map of 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 Module. This is useful if a VF module + * is successfully created but the orchestration fails on a subsequent step. + * + * @param cloudSiteId CLLI code of the cloud site in which to create the VNF + * @param tenantId Openstack tenant identifier + * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. + * Deprecated - should use modelCustomizationUuid + * @param vnfVersion VNF version key, should match a VNF definition in catalog DB + * Deprecated - VF Module versions also captured by modelCustomizationUuid + * @param vfModuleName Name to be assigned to the new VF Module + * @param requestType Indicates if this is a Volume Group or Module request + * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group + * to attach to a VF Module + * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if + * this is an Add-on module + * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces + * the use of vfModuleType. + * @param inputs Map of key=value inputs for VNF stack creation + * @param failIfExists Flag whether already existing VNF should be considered + * @param backout Flag whether to suppress automatic backout (for testing) + * @param msoRequest Request tracking information for logs + * @param vnfId Holder for output VNF Cloudify Deployment ID + * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc) + * @param rollback Holder for returning VnfRollback object + */ + @Override + public void createVfModule(String cloudSiteId, + String tenantId, + String vfModuleType, + String vnfVersion, + String vfModuleName, + String requestType, + String volumeGroupId, + String baseVfModuleId, + String modelCustomizationUuid, + Map <String, String> inputs, + Boolean failIfExists, + Boolean backout, + Boolean enableBridge, + MsoRequest msoRequest, + Holder <String> vnfId, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) + throws VnfException + { + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateVfModule"); + + // Require a model customization ID. Every VF Module definition must have one. + if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) { + LOGGER.debug("Missing required input: modelCustomizationUuid"); + String error = "Create vfModule error: Missing required input: modelCustomizationUuid"; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", "null", "Cloudify", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + + // Clean up some inputs to make comparisons easier + if (requestType == null) + requestType = ""; + + if ("".equals(volumeGroupId) || "null".equals(volumeGroupId)) + volumeGroupId = null; + + if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId)) + baseVfModuleId = null; + + 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); + } + + // Check if this is for a "Volume" module + boolean isVolumeRequest = false; + if (requestType.startsWith("VOLUME")) { + isVolumeRequest = true; + } + + LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId); + + // Build a default rollback object (no actions performed) + VnfRollback vfRollback = new VnfRollback(); + vfRollback.setCloudSiteId(cloudSiteId); + vfRollback.setTenantId(tenantId); + vfRollback.setMsoRequest(msoRequest); + vfRollback.setRequestType(requestType); + vfRollback.setIsBase(false); // Until we know better + vfRollback.setVolumeGroupHeatStackId(volumeGroupId); + vfRollback.setBaseGroupHeatStackId(baseVfModuleId); + vfRollback.setModelCustomizationUuid(modelCustomizationUuid); + vfRollback.setMode("CFY"); + + rollback.value = vfRollback; // Default rollback - no updates performed + + // Get the VNF/VF Module definition from the Catalog DB first. + // There are three relevant records: VfModule, VfModuleCustomization, VnfResource + + VfModule vf = null; + VnfResource vnfResource = null; + VfModuleCustomization vfmc = null; + + try { + vfmc = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid); + + if (vfmc == null) { + String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid; + LOGGER.debug(error); + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found vfModuleCust entry " + vfmc.toString()); + } + + // Get the vfModule and vnfResource records + vf = vfmc.getVfModule(); + vnfResource = vfmc.getVfModule().getVnfResources(); + } + catch (Exception e) { + + LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage()); + throw new VnfException("Exception during create VF " + e.getMessage()); + } + + // Perform a version check against cloudSite + // Obtain the cloud site information where we will create the VF Module + Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId); + if (!cloudSiteOp.isPresent()) { + throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId)); + } + CloudSite cloudSite = cloudSiteOp.get(); + MavenLikeVersioning aicV = new MavenLikeVersioning(); + aicV.setVersion(cloudSite.getAicVersion()); + + String vnfMin = vnfResource.getAicVersionMin(); + String vnfMax = vnfResource.getAicVersionMax(); + + if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) || + (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) + { + // ERROR + String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getAicVersion(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + // End Version check + + + DeploymentInfo cloudifyDeployment = null; + + // First, look up to see if the VF already exists. + + long subStartTime1 = System.currentTimeMillis (); + try { + cloudifyDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, vfModuleName); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "QueryDeployment", vfModuleName); + } + catch (MsoException me) { + // Failed to query the Deployment due to a cloudify exception. + String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment", me); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", vfModuleName); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + throw new VnfException (me); + } + + // More precise handling/messaging if the Module already exists + if (cloudifyDeployment != null && !(cloudifyDeployment.getStatus () == DeploymentStatus.NOTFOUND)) { + // CREATED, INSTALLED, INSTALLING, FAILED, UNINSTALLING, UNKNOWN + DeploymentStatus status = cloudifyDeployment.getStatus(); + LOGGER.debug ("Found Existing Deployment, status=" + status); + + if (status == DeploymentStatus.INSTALLED) { + // fail - it exists + if (failIfExists != null && failIfExists) { + String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } else { + // Found existing deployment and client has not requested "failIfExists". + // Populate the outputs from the existing deployment. + + vnfId.value = cloudifyDeployment.getId(); + outputs.value = copyStringOutputs (cloudifyDeployment.getOutputs ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)"); + return; + } + } + // Check through various detailed error cases + if (status == DeploymentStatus.INSTALLING || status == DeploymentStatus.UNINSTALLING) { + // fail - it's in progress - return meaningful error + String error = "Create VF: Deployment " + 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, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } + else if (status == DeploymentStatus.FAILED) { + // fail - it exists and is in a FAILED state + String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in FAILED state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } + else if (status == DeploymentStatus.UNKNOWN || status == DeploymentStatus.CREATED) { + // fail - it exists and is in a UNKNOWN state + String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in " + status.toString() + " state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } + else { + // Unexpected, since all known status values have been tested for + String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "Cloudify", "queryDeployment", MsoLogger.ErrorCode.DataError, "Deployment " + vfModuleName + " already exists and is in an unknown state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, cloudifyDeployment.getId()); + } + } + + + // Collect outputs from Base Modules and Volume Modules + Map<String, Object> baseModuleOutputs = null; + Map<String, Object> volumeGroupOutputs = null; + + // If a Volume Group was provided, query its outputs for inclusion in Module input parameters + if (volumeGroupId != null) { + long subStartTime2 = System.currentTimeMillis (); + DeploymentInfo volumeDeployment = null; + try { + volumeDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, volumeGroupId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", "Cloudify", "QueryDeployment", volumeGroupId); + } + catch (MsoException me) { + // Failed to query the Volume GroupDeployment due to a cloudify exception. + String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "Cloudify", "queryDeployment(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(volume)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment(volume)", volumeGroupId); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule(QueryVolume)"); + throw new VnfException (me); + } + + if (volumeDeployment == null || volumeDeployment.getStatus() == DeploymentStatus.NOTFOUND) { + String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, error, "Cloudify", "queryDeployment(volume)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached Volume Group 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 group"); + volumeGroupOutputs = volumeDeployment.getOutputs(); + this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs"); + } + } + + // If this is an Add-On Module, query the Base Module outputs + // Note: This will be performed whether or not the current request is for an + // Add-On Volume Group or Add-On VF Module + + if (vf.getIsBase()) { + LOGGER.debug("This is a BASE Module request"); + vfRollback.setIsBase(true); + } else { + LOGGER.debug("This is an Add-On Module request"); + + // Add-On Modules should always have a Base, but just treat as a warning if not provided. + // Add-on Volume requests may or may not specify a base. + if (!isVolumeRequest && baseVfModuleId == null) { + LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided"); + } + + if (baseVfModuleId != null) { + long subStartTime2 = System.currentTimeMillis (); + DeploymentInfo baseDeployment = null; + try { + baseDeployment = cloudifyUtils.queryDeployment (cloudSiteId, tenantId, baseVfModuleId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from Cloudify", "Cloudify", "QueryDeployment(Base)", baseVfModuleId); + } + catch (MsoException me) { + // Failed to query the Volume GroupDeployment due to a cloudify exception. + String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "Cloudify", "queryDeployment(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryDeployment(Base)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment(Base)", baseVfModuleId); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule(QueryBase)"); + throw new VnfException (me); + } + + if (baseDeployment == null || baseDeployment.getStatus() == DeploymentStatus.NOTFOUND) { + String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, "Cloudify", "queryDeployment(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module 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 base module"); + baseModuleOutputs = baseDeployment.getOutputs(); + this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs"); + } + } + } + + + // Ready to deploy the new VNF + + // NOTE: For this section, heatTemplate is used for both HEAT templates and Cloudify blueprints. + // In final implementation (post-POC), the template object would either be generic or there would + // be a separate DB Table/Object for Blueprints. + + + // NOTE: The template is fixed for the VF Module. The environment is part of the customization. + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (isVolumeRequest) { + heatTemplate = vf.getVolumeHeatTemplate(); + heatEnvironment = vfmc.getVolumeHeatEnv(); + } else { + heatTemplate = vf.getModuleHeatTemplate(); + heatEnvironment = vfmc.getHeatEnvironment(); + } + + if (heatTemplate == null) { + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType; + 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 { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "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.getEnvironment()); + } + + + try { + // All variables converted to their native object types + HashMap<String, Object> goldenInputs = new HashMap<String,Object>(); + List<String> extraInputs = new ArrayList<String>(); + + // NOTE: SKIP THIS FOR CLOUDIFY for now. Just use what was passed in. + // This whole section needs to be rewritten. + Boolean skipInputChecks = false; + + if (skipInputChecks) { + goldenInputs = new HashMap<String,Object>(); + for (String key : inputs.keySet()) { + goldenInputs.put(key, inputs.get(key)); + } + } + else { + // Build maps for the parameters (including aliases) to simplify checks + HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>(); + + Set<HeatTemplateParam> paramSet = heatTemplate.getParameters(); + LOGGER.debug("paramSet has " + paramSet.size() + " entries"); + + for (HeatTemplateParam htp : paramSet) { + params.put(htp.getParamName(), htp); + + // Include aliases. + String alias = htp.getParamAlias(); + if (alias != null && !alias.equals("") && !params.containsKey(alias)) { + params.put(alias, htp); + } + } + + // First, convert all inputs to their "template" type + for (String key : inputs.keySet()) { + if (params.containsKey(key)) { + Object value = cloudifyUtils.convertInputValue(inputs.get(key), params.get(key)); + if (value != null) { + goldenInputs.put(key, value); + } + else { + LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType()); + } + } else { + extraInputs.add(key); + } + } + + if (!extraInputs.isEmpty()) { + LOGGER.debug("Ignoring extra inputs: " + extraInputs); + } + + // Next add in Volume Group Outputs if there are any. Copy directly without conversions. + if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) { + for (String key : volumeGroupOutputs.keySet()) { + if (params.containsKey(key) && !goldenInputs.containsKey(key)) { + goldenInputs.put(key, volumeGroupOutputs.get(key)); + } + } + } + + // Next add in Base Module Outputs if there are any. Copy directly without conversions. + if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) { + for (String key : baseModuleOutputs.keySet()) { + if (params.containsKey(key) && !goldenInputs.containsKey(key)) { + goldenInputs.put(key, baseModuleOutputs.get(key)); + } + } + } + + // Last, add in values from the "environment" file. + // These are added to the inputs, since Cloudify doesn't pass an environment file like Heat. + + // TODO: This may take a different form for Cloudify, but for now process it + // with Heat environment file syntax + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb); + + if (mhee.getParameters() != null) { + for (MsoHeatEnvironmentParameter envParam : mhee.getParameters()) { + // If this is a template input, copy to golden inputs + String envKey = envParam.getName(); + if (params.containsKey(envKey) && !goldenInputs.containsKey(envKey)) { + Object value = cloudifyUtils.convertInputValue(envParam.getValue(), params.get(envKey)); + if (value != null) { + goldenInputs.put(envKey, value); + } + else { + LOGGER.debug("Failed to convert environment parameter " + envKey + "='" + envParam.getValue() + "' to " + params.get(envKey).getParamType()); + } + } + } + } + + this.sendMapToDebug(goldenInputs, "Final inputs sent to Cloudify"); + + + // Check that required parameters have been supplied from any of the sources + String missingParams = null; + boolean checkRequiredParameters = true; + try { + String propertyString = this.environment.getProperty(MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfCloudifyAdapterImpl.CHECK_REQD_PARAMS, e); + } + + + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) { + LOGGER.debug ("adding to missing parameters list: " + parm.getParamName ()); + if (missingParams == null) { + missingParams = parm.getParamName (); + } else { + missingParams += "," + 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, "Cloudify", "", 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 [" + missingParams + "] - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + + } // NOTE: END PARAMETER CHECKING + + // Ready to deploy the VF Module. + // *First step - make sure the blueprint is loaded into Cloudify. + String blueprintName = heatTemplate.getTemplateName(); + String blueprint = heatTemplate.getTemplateBody(); + String blueprintId = blueprintName; + + // Use the main blueprint name as the blueprint ID (strip yaml extensions). + if (blueprintId.endsWith(".yaml")) + blueprintId = blueprintId.substring(0,blueprintId.lastIndexOf(".yaml")); + + try { + if (! cloudifyUtils.isBlueprintLoaded (cloudSiteId, blueprintId)) { + LOGGER.debug ("Blueprint " + blueprintId + " is not loaded. Will upload it now."); + + Map<String,byte[]> blueprintFiles = new HashMap<String,byte[]>(); + + blueprintFiles.put(blueprintName, blueprint.getBytes()); + + // TODO: Implement nested blueprint logic based on Cloudify structures. + // For now, just use the Heat structures. + // The query returns a map of String->Object, where the map keys provide one layer of + // indirection from the Heat template names. For this case, assume the map key matches + // the nested blueprint name. + List<HeatTemplate> nestedBlueprints = heatTemplate.getChildTemplates(); + if (nestedBlueprints != null) { + for (HeatTemplate nestedBlueprint: nestedBlueprints) { + blueprintFiles.put(nestedBlueprint.getTemplateName(), nestedBlueprint.getTemplateBody().getBytes()); + } + } + + // TODO: Implement file artifact logic based on Cloudify structures. + // For now, just use the Heat structures. + List<HeatFiles> heatFiles = vf.getHeatFiles(); + if (heatFiles != null) { + for (HeatFiles heatFile: heatFiles) { + blueprintFiles.put(heatFile.getFileName(), heatFile.getFileBody().getBytes()); + } + } + + // Upload the blueprint package + cloudifyUtils.uploadBlueprint(cloudSiteId, blueprintId, blueprintName, blueprintFiles, false); + + } + } + + catch (MsoException me) { + me.addContext ("CreateVFModule"); + String error = "Create VF Module: Upload blueprint failed. Blueprint=" + blueprintName + ": " + me; + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "MsoException - uploadBlueprint", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + + } + + // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions + // because we already checked for those. + long createDeploymentStarttime = System.currentTimeMillis (); + try { + // KLUDGE - Cloudify requires Tenant Name for Openstack. We have the ID. + // Go directly to Keystone until APIs could be updated to supply the name. + MsoTenant msoTenant = keystoneUtils.queryTenant(tenantId, cloudSiteId); + String tenantName = (msoTenant != null? msoTenant.getTenantName() : tenantId); + + if (backout == null) { + backout = true; + } + + cloudifyDeployment = cloudifyUtils.createAndInstallDeployment (cloudSiteId, + tenantName, + vfModuleName, + blueprintId, + goldenInputs, + true, + heatTemplate.getTimeoutMinutes (), + backout.booleanValue()); + + LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Cloudify", "Cloudify", "CreateDeployment", vfModuleName); + } catch (MsoException me) { + me.addContext ("CreateVFModule"); + String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "CreateDeployment", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "MsoException - createDeployment", 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 (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "CreateDeployment", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "Cloudify", "", MsoLogger.ErrorCode.DataError, "NullPointerException - createDeployment", npe); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + LOGGER.debug("NULL POINTER EXCEPTION at cloudify.createAndInstallDeployment"); + //npe.addContext ("CreateVNF"); + throw new VnfException ("NullPointerException during cloudify.createAndInstallDeployment"); + } catch (Exception e) { + LOGGER.recordMetricEvent (createDeploymentStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify", "Cloudify", "CreateDeployment", vfModuleName); + LOGGER.debug("unhandled exception at cloudify.createAndInstallDeployment"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while creating deployment with Cloudify"); + throw new VnfException("Exception during cloudify.createAndInstallDeployment! " + 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 create is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfCreated (true); + vfRollback.setVnfId (cloudifyDeployment.getId()); + vnfId.value = cloudifyDeployment.getId(); + outputs.value = copyStringOutputs (cloudifyDeployment.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, + Holder <Map <String, String>> outputs) 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 (); + + // 1702 capture the output parameters on a delete + // so we'll need to query first + DeploymentInfo deployment = null; + try { + deployment = cloudifyUtils.queryDeployment(cloudSiteId, tenantId, vnfName); + } catch (MsoException me) { + // Failed to query the deployment. Convert to a generic VnfException + me.addContext ("DeleteVFModule"); + String error = "Delete VFModule: Query to get outputs: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "Cloudify", "QueryDeployment", null); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfName, cloudSiteId, tenantId, "Cloudify", "QueryDeployment", MsoLogger.ErrorCode.DataError, "Exception - QueryDeployment", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (me); + } + // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types + outputs.value = convertMapStringObjectToStringString(deployment.getOutputs()); + + // 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 { + cloudifyUtils.uninstallAndDeleteDeployment(cloudSiteId, tenantId, vnfName, 5); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from DeleteDeployment", "Cloudify", "DeleteDeployment", vnfName); + } catch (MsoException me) { + me.addContext ("DeleteVfModule"); + // Convert to a generic VnfException + String error = "Delete VF: " + vnfName + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteDeployment", "DeleteDeployment", vnfName); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vnfName, cloudSiteId, tenantId, "DeleteDeployment", "DeleteDeployment", MsoLogger.ErrorCode.DataError, "Exception - DeleteDeployment: " + me.getMessage()); + 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; + } + + // TODO: Should Update be supported for Cloudify? What would this look like? + @Override + public void updateVfModule (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + String baseVfHeatStackId, + String vfModuleStackId, + String modelCustomizationUuid, + Map <String, String> inputs, + MsoRequest msoRequest, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException + { + // This operation is not currently supported for Cloudify-orchestrated VF Modules. + LOGGER.debug ("Update VF Module command attempted but not supported"); + throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA); + } + +}
\ No newline at end of file diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java new file mode 100644 index 0000000000..0a7b30f9ca --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java @@ -0,0 +1,1229 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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========================================================= + */ + +/** + * This VNF Adapter implementation is based on the VDU Plugin model. It assumes that each + * VF Module definition in the MSO catalog is expressed via a set of template and/or file + * artifacts that are appropriate for some specific sub-orchestrator that provides an + * implementation of the VduPlugin interface. This adapter handles all of the common + * VF Module logic, including: + * - catalog lookups for artifact retrieval + * - parameter filtering and validation + * - base and volume module queries + * - rollback logic + * - logging and error handling + * + * Then based on the orchestration mode of the VNF, it will invoke different VDU plug-ins + * to perform the low level instantiations, deletions, and queries. At this time, the + * set of available plug-ins is hard-coded, though in the future a dynamic selection + * is expected (e.g. via a service-provider interface). + */ +package org.onap.so.adapters.vnf; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.onap.so.adapters.vdu.CloudInfo; +import org.onap.so.adapters.vdu.VduException; +import org.onap.so.adapters.vdu.VduInstance; +import org.onap.so.adapters.vdu.VduModelInfo; +import org.onap.so.adapters.vdu.VduPlugin; +import org.onap.so.adapters.vdu.VduStateType; +import org.onap.so.adapters.vdu.VduStatus; +import org.onap.so.adapters.vdu.mapper.VfModuleCustomizationToVduMapper; +import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; +import org.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.cloudify.utils.MsoCloudifyUtils; +import org.onap.so.db.catalog.beans.HeatEnvironment; +import org.onap.so.db.catalog.beans.HeatTemplate; +import org.onap.so.db.catalog.beans.HeatTemplateParam; +import org.onap.so.db.catalog.beans.VfModule; +import org.onap.so.db.catalog.beans.VfModuleCustomization; +import org.onap.so.db.catalog.beans.VnfResource; +import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository; +import org.onap.so.db.catalog.utils.MavenLikeVersioning; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoAlarmLogger; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound; +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry; +import org.onap.so.openstack.utils.MsoHeatUtils; +import org.onap.so.openstack.utils.MsoKeystoneUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf") +@Component +@Transactional +public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { + + private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError"; + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoVnfPluginAdapterImpl.class); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String CHECK_REQD_PARAMS = "org.onap.so.adapters.vnf.checkRequiredParameters"; + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + + @Autowired + protected CloudConfig cloudConfig; + + @Autowired + private VFModuleCustomizationRepository vfModuleCustomRepo; + + @Autowired + private Environment environment; + + @Autowired + protected MsoKeystoneUtils keystoneUtils; + + @Autowired + protected MsoCloudifyUtils cloudifyUtils; + + @Autowired + protected MsoHeatUtils heatUtils; + + @Autowired + protected VfModuleCustomizationToVduMapper vduMapper; + + /** + * 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 Plugin Adapter"); + } + + /** + * DO NOT use that constructor to instantiate this class, the msoPropertiesfactory will be NULL. + * @see MsoVnfPluginAdapterImpl#MsoVnfAdapterImpl(MsoPropertiesFactory, CloudConfigFactory) + */ + public MsoVnfPluginAdapterImpl() { + + } + + /** + * This is the "Create VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @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, + Boolean enableBridge, + MsoRequest msoRequest, + Holder <String> vnfId, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) + throws VnfException + { + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("CreateVNF command attempted but not supported"); + throw new VnfException ("CreateVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * This is the "Update VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @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 + { + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("UpdateVNF command attempted but not supported"); + throw new VnfException ("UpdateVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * This is the "Query VNF" web service implementation. + * + * This really should be QueryVfModule, but nobody ever changed it. + * + * The method returns an indicator that the VNF exists, along with its status and outputs. + * The input "vnfName" will also be reflected back as its ID. + * + * @param cloudSiteId CLLI code of the cloud site in which to query + * @param tenantId Openstack tenant identifier + * @param vnfNameOrId VNF Name or ID to query + * @param msoRequest Request tracking information for logs + * @param vnfExists Flag reporting the result of the query + * @param vnfId Holder for output VNF ID + * @param outputs Holder for Map of outputs from the deployed VF Module (assigned IPs, etc) + */ + @Override + public void queryVnf (String cloudSiteId, + String tenantId, + String vnfNameOrId, + 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 " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId); + + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + long subStartTime = System.currentTimeMillis (); + + VduInstance vduInstance = null; + CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null); + + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + try { + vduInstance = vduPlugin.queryVdu (cloudInfo, vnfNameOrId); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vnfNameOrId); + } + catch (VduException e) { + // Failed to query the VDU due to a plugin exception. + // Convert to a generic VnfException + e.addContext ("QueryVNF"); + String error = "Query VNF (VDU): " + vnfNameOrId + " in " + cloudSiteId + "/" + tenantId + ": " + e; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vnfNameOrId); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vnfNameOrId, cloudSiteId, tenantId, "VDU", "QueryVNF", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (e); + } + + if (vduInstance != null && vduInstance.getStatus().getState() != VduStateType.NOTFOUND) { + vnfExists.value = Boolean.TRUE; + status.value = vduStatusToVnfStatus(vduInstance); + vnfId.value = vduInstance.getVduInstanceId(); + outputs.value = copyStringOutputs (vduInstance.getOutputs ()); + + LOGGER.debug ("VNF " + vnfNameOrId + " found, ID = " + vnfId.value); + } + else { + 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 " + vnfNameOrId + " not found"); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully query VNF"); + return; + } + + + /** + * This is the "Delete VNF" web service implementation. + * This function is now unsupported and will return an error. + * + */ + @Override + public void deleteVnf (String cloudSiteId, + String tenantId, + String vnfName, + MsoRequest msoRequest) throws VnfException { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVnf"); + + // This operation is no longer supported at the VNF level. The adapter is only called to deploy modules. + LOGGER.debug ("DeleteVNF command attempted but not supported"); + throw new VnfException ("DeleteVNF: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /** + * 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. + * + * TODO: This should be rollbackVfModule and/or rollbackVolumeGroup, + * but APIs were apparently never updated. + */ + @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", MsoLogger.getServiceName()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "Rollback request content is null"); + return; + } + + // Don't rollback if nothing was done originally + if (!rollback.getVnfCreated()) { + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Rollback VF Module - nothing to roll back"); + return; + } + + // Get the elements of the VnfRollback object for easier access + String cloudSiteId = rollback.getCloudSiteId (); + String tenantId = rollback.getTenantId (); + CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null); + + String vfModuleId = rollback.getVfModuleStackId (); + + MsoLogger.setLogContext (rollback.getMsoRequest()); + + LOGGER.debug ("Rolling Back VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId); + + VduInstance vduInstance = null; + + // Use the VduPlugin to delete the VF Module. + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + long subStartTime = System.currentTimeMillis (); + try { + // TODO: Get a reasonable timeout. Use a global property, or store the creation timeout in rollback object and use that. + vduInstance = vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5); + + LOGGER.debug("Rolled back VDU instantiation: " + vduInstance.getVduInstanceId()); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VDU Plugin", "VDU", "DeleteVdu", null); + } + catch (VduException ve) { + // Failed to rollback the VF Module due to a plugin exception. + // Convert to a generic VnfException + ve.addContext ("RollbackVFModule"); + String error = "Rollback VF Module: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + ve; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "DeleteVdu", null); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu", ve); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (ve); + } + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully roll back VF Module"); + return; + } + + + private VnfStatus vduStatusToVnfStatus (VduInstance vdu) { + // Determine the status based on last action & status + // DeploymentInfo object should be enhanced to report a better status internally. + VduStatus vduStatus = vdu.getStatus(); + VduStateType status = vduStatus.getState(); + + if (status == null) { + return VnfStatus.UNKNOWN; + } + else if (status == VduStateType.NOTFOUND) { + return VnfStatus.NOTFOUND; + } + else if (status == VduStateType.INSTANTIATED) { + return VnfStatus.ACTIVE; + } + else if (status == VduStateType.FAILED) { + return VnfStatus.FAILED; + } + + return VnfStatus.UNKNOWN; + } + + /* + * Normalize an input value to an Object, based on the target parameter type. + * If the type is not recognized, it will just be returned unchanged (as a string). + */ + private Object convertInputValue (String inputValue, HeatTemplateParam templateParam) + { + String type = templateParam.getParamType(); + LOGGER.debug("Parameter: " + templateParam.getParamName() + " is of type " + type); + + if (type.equalsIgnoreCase("number")) { + try { + return Integer.valueOf(inputValue); + } + catch (Exception e) { + LOGGER.debug("Unable to convert " + inputValue + " to an integer!" , e); + return null; + } + } else if (type.equalsIgnoreCase("json")) { + try { + JsonNode jsonNode = new ObjectMapper().readTree(inputValue); + return jsonNode; + } + catch (Exception e) { + LOGGER.debug("Unable to convert " + inputValue + " to a JsonNode!", e); + return null; + } + } else if (type.equalsIgnoreCase("boolean")) { + return new Boolean(inputValue); + } + + // Nothing else matched. Return the original string + return inputValue; + } + + 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)); + } else if (stackOutputs.get(key) instanceof Integer) { + try { + String str = "" + stackOutputs.get(key); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs", e); + } + } else if (stackOutputs.get(key) instanceof JsonNode) { + try { + String str = this.convertNode((JsonNode) stackOutputs.get(key)); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - exception converting JsonNode", e); + } + } else if (stackOutputs.get(key) instanceof java.util.LinkedHashMap) { + try { + String str = JSON_MAPPER.writeValueAsString(stackOutputs.get(key)); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - exception converting LinkedHashMap", e); + } + } else { + try { + String str = stackOutputs.get(key).toString(); + stringOutputs.put(key, str); + } catch (Exception e) { + LOGGER.debug("Unable to add " + key + " to outputs - unable to call .toString() " + e.getMessage(), e); + } + } + } + return stringOutputs; + } + + + private void sendMapToDebug(Map<String, Object> inputs, String optionalName) { + int i = 0; + StringBuilder sb = new StringBuilder(optionalName == null ? "\ninputs" : "\n" + optionalName); + if (inputs == null) { + sb.append("\tNULL"); + } + else if (inputs.size() < 1) { + sb.append("\tEMPTY"); + } else { + for (String str : inputs.keySet()) { + String outputString; + try { + outputString = inputs.get(str).toString(); + } catch (Exception e) { + outputString = "Unable to call toString() on the value for " + str; + } + sb.append("\t\nitem " + i++ + ": '" + str + "'='" + outputString + "'"); + } + } + LOGGER.debug(sb.toString()); + return; + } + + 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; + } + + private String convertNode(final JsonNode node) { + try { + final Object obj = JSON_MAPPER.treeToValue(node, Object.class); + final String json = JSON_MAPPER.writeValueAsString(obj); + return json; + } catch (JsonParseException jpe) { + LOGGER.debug("Error converting json to string " + jpe.getMessage()); + } catch (Exception e) { + LOGGER.debug("Error converting json to string " + e.getMessage()); + } + return "[Error converting json to string]"; + } + + private Map<String, String> convertMapStringObjectToStringString(Map<String, Object> objectMap) { + if (objectMap == null) { + return null; + } + Map<String, String> stringMap = new HashMap<String, String>(); + for (String key : objectMap.keySet()) { + if (!stringMap.containsKey(key)) { + Object obj = objectMap.get(key); + if (obj instanceof String) { + stringMap.put(key, (String) objectMap.get(key)); + } else if (obj instanceof JsonNode ){ + // This is a bit of mess - but I think it's the least impacting + // let's convert it BACK to a string - then it will get converted back later + try { + String str = this.convertNode((JsonNode) obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for JsonNode "+ key, e); + //okay in this instance - only string values (fqdn) are expected to be needed + } + } else if (obj instanceof java.util.LinkedHashMap) { + LOGGER.debug("LinkedHashMap - this is showing up as a LinkedHashMap instead of JsonNode"); + try { + String str = JSON_MAPPER.writeValueAsString(obj); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for LinkedHashMap "+ key, e); + } + } else if (obj instanceof Integer) { + try { + String str = "" + obj; + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value for Integer "+ key, e); + } + } else { + try { + String str = obj.toString(); + stringMap.put(key, str); + } catch (Exception e) { + LOGGER.debug("DANGER WILL ROBINSON: unable to convert value "+ key + " (" + e.getMessage() + ")", e); + } + } + } + } + + return stringMap; + } + + /** + * This is the "Create VF Module" web service implementation. + * It will instantiate a new VF Module of the requested type in the specified cloud + * and tenant. The tenant must exist before this service is called. + * + * If a VF Module with the same name already exists, this can be considered a + * success or failure, depending on the value of the 'failIfExists' parameter. + * + * All VF Modules are defined in the MSO catalog. The caller must request one of + * the pre-defined module types or an error will be returned. Within the catalog, + * each VF Module references (among other things) a collection of artifacts that + * are used to deploy the required cloud resources (VMs, networks, etc.). + * + * Depending on the module templates, 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 module or an error will be thrown. + * + * The method returns the vfModuleId, a Map of 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 Module. This is useful if a VF module + * is successfully created but the orchestration fails on a subsequent step. + * + * @param cloudSiteId CLLI code of the cloud site in which to create the VNF + * @param tenantId Openstack tenant identifier + * @param vfModuleType VF Module type key, should match a VNF definition in catalog DB. + * Deprecated - should use modelCustomizationUuid + * @param vnfVersion VNF version key, should match a VNF definition in catalog DB + * Deprecated - VF Module versions also captured by modelCustomizationUuid + * @param vfModuleName Name to be assigned to the new VF Module + * @param requestType Indicates if this is a Volume Group or Module request + * @param volumeGroupId Identifier (i.e. deployment ID) for a Volume Group + * to attach to a VF Module + * @param baseVfModuleId Identifier (i.e. deployment ID) of the Base Module if + * this is an Add-on module + * @param modelCustomizationUuid Unique ID for the VF Module's model. Replaces + * the use of vfModuleType. + * @param inputs Map of key=value inputs for VNF stack creation + * @param failIfExists Flag whether already existing VNF should be considered + * @param backout Flag whether to suppress automatic backout (for testing) + * @param msoRequest Request tracking information for logs + * @param vnfId Holder for output VF Module instance ID in the cloud + * @param outputs Holder for Map of VNF outputs from Deployment (assigned IPs, etc) + * @param rollback Holder for returning VnfRollback object + */ + @Override + public void createVfModule(String cloudSiteId, + String tenantId, + String vfModuleType, + String vnfVersion, + String vfModuleName, + String requestType, + String volumeGroupId, + String baseVfModuleId, + String modelCustomizationUuid, + Map <String, String> inputs, + Boolean failIfExists, + Boolean backout, + Boolean enableBridge, + MsoRequest msoRequest, + Holder <String> vnfId, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) + throws VnfException + { + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("CreateVfModule"); + + // Require a model customization ID. Every VF Module definition must have one. + if (modelCustomizationUuid == null || modelCustomizationUuid.isEmpty()) { + LOGGER.debug("Missing required input: modelCustomizationUuid"); + String error = "Create vfModule error: Missing required input: modelCustomizationUuid"; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", "null", "VDU", "", MsoLogger.ErrorCode.DataError, "Create VF Module: Missing required input: modelCustomizationUuid"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + + // Clean up some inputs to make comparisons easier + if (requestType == null) + requestType = ""; + + if ("".equals(volumeGroupId) || "null".equals(volumeGroupId)) + volumeGroupId = null; + + if ("".equals(baseVfModuleId) || "null".equals(baseVfModuleId)) + baseVfModuleId = null; + + if (inputs == null) { + // Create an empty set of inputs + inputs = new HashMap<>(); + LOGGER.debug("inputs == null - setting to empty"); + } else { + this.sendMapToDebug(inputs); + } + + // Check if this is for a "Volume" module + boolean isVolumeRequest = false; + if (requestType.startsWith("VOLUME")) { + isVolumeRequest = true; + } + + LOGGER.debug("requestType = " + requestType + ", volumeGroupStackId = " + volumeGroupId + ", baseStackId = " + baseVfModuleId); + + // Build a default rollback object (no actions performed) + VnfRollback vfRollback = new VnfRollback(); + vfRollback.setCloudSiteId(cloudSiteId); + vfRollback.setTenantId(tenantId); + vfRollback.setMsoRequest(msoRequest); + vfRollback.setRequestType(requestType); + vfRollback.setIsBase(false); // Until we know better + vfRollback.setVolumeGroupHeatStackId(volumeGroupId); + vfRollback.setBaseGroupHeatStackId(baseVfModuleId); + vfRollback.setModelCustomizationUuid(modelCustomizationUuid); + vfRollback.setMode("CFY"); + + rollback.value = vfRollback; // Default rollback - no updates performed + + // Get the VNF/VF Module definition from the Catalog DB first. + // There are three relevant records: VfModule, VfModuleCustomization, VnfResource + + VfModule vfModule = null; + VnfResource vnfResource = null; + VfModuleCustomization vfModuleCust = null; + + try { + vfModuleCust = vfModuleCustomRepo.findByModelCustomizationUUID(modelCustomizationUuid); + + if (vfModuleCust == null) { + String error = "Create vfModule error: Unable to find vfModuleCust with modelCustomizationUuid=" + modelCustomizationUuid; + LOGGER.debug(error); + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, + "VF Module ModelCustomizationUuid", modelCustomizationUuid, "CatalogDb", "", MsoLogger.ErrorCode.DataError, error); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } else { + LOGGER.debug("Found vfModuleCust entry " + vfModuleCust.toString()); + } + + // Get the vfModule and vnfResource records + vfModule = vfModuleCust.getVfModule(); + vnfResource = vfModuleCust.getVfModule().getVnfResources(); + } + catch (Exception e) { + + LOGGER.debug("unhandled exception in create VF - [Query]" + e.getMessage()); + throw new VnfException("Exception during create VF " + e.getMessage()); + } + + // Perform a version check against cloudSite + // Obtain the cloud site information where we will create the VF Module + Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId); + if (!cloudSiteOp.isPresent()) { + throw new VnfException (new MsoCloudSiteNotFound (cloudSiteId)); + } + CloudSite cloudSite = cloudSiteOp.get(); + MavenLikeVersioning aicV = new MavenLikeVersioning(); + aicV.setVersion(cloudSite.getAicVersion()); + + String vnfMin = vnfResource.getAicVersionMin(); + String vnfMax = vnfResource.getAicVersionMax(); + + if ( (vnfMin != null && !(aicV.isMoreRecentThan(vnfMin) || aicV.isTheSameVersion(vnfMin))) || + (vnfMax != null && aicV.isMoreRecentThan(vnfMax))) + { + // ERROR + String error = "VNF Resource type: " + vnfResource.getModelName() + ", ModelUuid=" + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getAicVersion(); + LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - setVersion"); + LOGGER.debug(error); + throw new VnfException(error, MsoExceptionCategory.USERDATA); + } + // End Version check + + + VduInstance vduInstance = null; + CloudInfo cloudInfo = new CloudInfo (cloudSiteId, tenantId, null); + + // Use the VduPlugin. + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + // First, look up to see if the VF already exists. + + long subStartTime1 = System.currentTimeMillis (); + try { + vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "QueryVDU", vfModuleName); + } + catch (VduException me) { + // Failed to query the VDU due to a plugin exception. + String error = "Create VF Module: Query " + vfModuleName + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "Exception - queryVdu", me); + LOGGER.recordMetricEvent (subStartTime1, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu", vfModuleName); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + throw new VnfException (me); + } + + // More precise handling/messaging if the Module already exists + if (vduInstance != null && !(vduInstance.getStatus().getState() == VduStateType.NOTFOUND)) { + VduStateType status = vduInstance.getStatus().getState(); + LOGGER.debug ("Found Existing VDU, status=" + status); + + if (status == VduStateType.INSTANTIATED) { + if (failIfExists != null && failIfExists) { + // fail - it exists + String error = "Create VF: Deployment " + vfModuleName + " already exists in " + cloudSiteId + "/" + tenantId; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } else { + // Found existing deployment and client has not requested "failIfExists". + // Populate the outputs from the existing deployment. + + vnfId.value = vduInstance.getVduInstanceId(); + outputs.value = copyStringOutputs (vduInstance.getOutputs ()); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully create VF Module (found existing)"); + return; + } + } + // Check through various detailed error cases + else if (status == VduStateType.INSTANTIATING || status == VduStateType.DELETING || status == VduStateType.UPDATING) { + // fail - it's in progress - return meaningful error + String error = "Create VF: Deployment " + 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, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + else if (status == VduStateType.FAILED) { + // fail - it exists and is in a FAILED state + String error = "Create VF: Deployment " + vfModuleName + " already exists and is in FAILED state in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in FAILED state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + else if (status == VduStateType.UNKNOWN) { + // fail - it exists and is in a UNKNOWN state + String error = "Create VF: Deployment " + vfModuleName + " already exists and has status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in " + status.toString() + " state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + else { + // Unexpected, since all known status values have been tested for + String error = "Create VF: Deployment " + vfModuleName + " already exists with unexpected status " + status.toString() + " in " + cloudSiteId + "/" + tenantId + "; requires manual intervention."; + LOGGER.error (MessageEnum.RA_VNF_ALREADY_EXIST, vfModuleName, cloudSiteId, tenantId, "VDU", "queryVdu", MsoLogger.ErrorCode.DataError, "VF Module " + vfModuleName + " already exists and is in an unknown state"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error); + throw new VnfAlreadyExists (vfModuleName, cloudSiteId, tenantId, vduInstance.getVduInstanceId()); + } + } + + + // Collect outputs from Base Modules and Volume Modules + Map<String, Object> baseModuleOutputs = null; + Map<String, Object> volumeGroupOutputs = null; + + // If a Volume Group was provided, query its outputs for inclusion in Module input parameters + if (volumeGroupId != null) { + long subStartTime2 = System.currentTimeMillis (); + VduInstance volumeVdu = null; + try { + volumeVdu = vduPlugin.queryVdu (cloudInfo, volumeGroupId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu", volumeGroupId); + } + catch (VduException me) { + // Failed to query the Volume Group VDU due to a plugin exception. + String error = "Create VF Module: Query Volume Group " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(volume)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(volume)", volumeGroupId); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule(QueryVolume)"); + throw new VnfException (me); + } + + if (volumeVdu == null || volumeVdu.getStatus().getState() == VduStateType.NOTFOUND) { + String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, volumeGroupId, cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Attached Volume Group 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 group"); + volumeGroupOutputs = volumeVdu.getOutputs(); + this.sendMapToDebug(volumeGroupOutputs, "volumeGroupOutputs"); + } + } + + // If this is an Add-On Module, query the Base Module outputs + // Note: This will be performed whether or not the current request is for an + // Add-On Volume Group or Add-On VF Module + + if (vfModule.getIsBase()) { + LOGGER.debug("This is a BASE Module request"); + vfRollback.setIsBase(true); + } else { + LOGGER.debug("This is an Add-On Module request"); + + // Add-On Modules should always have a Base, but just treat as a warning if not provided. + // Add-on Volume requests may or may not specify a base. + if (!isVolumeRequest && baseVfModuleId == null) { + LOGGER.debug ("WARNING: Add-on Module request - no Base Module ID provided"); + } + + if (baseVfModuleId != null) { + long subStartTime2 = System.currentTimeMillis (); + VduInstance baseVdu = null; + try { + baseVdu = vduPlugin.queryVdu (cloudInfo, baseVfModuleId); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Success response from VduPlugin", "VDU", "QueryVdu(Base)", baseVfModuleId); + } + catch (MsoException me) { + // Failed to query the Base VF Module due to a Vdu Plugin exception. + String error = "Create VF Module: Query Base " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.DataError, "Exception - queryVdu(Base)", me); + LOGGER.recordMetricEvent (subStartTime2, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVdu(Base)", baseVfModuleId); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + + // Convert to a generic VnfException + me.addContext ("CreateVFModule(QueryBase)"); + throw new VnfException (me); + } + + if (baseVdu == null || baseVdu.getStatus().getState() == VduStateType.NOTFOUND) { + String error = "Create VFModule: Base Module DOES NOT EXIST " + baseVfModuleId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR" ; + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, baseVfModuleId, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)", MsoLogger.ErrorCode.BusinessProcesssError, "Create VFModule: Base Module 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 base module"); + baseModuleOutputs = baseVdu.getOutputs(); + this.sendMapToDebug(baseModuleOutputs, "baseModuleOutputs"); + } + } + } + + + // NOTE: For this section, heatTemplate is used for all template artifacts. + // In final implementation (post-POC), the template object would either be generic or there would + // be a separate DB Table/Object for different sub-orchestrators. + + // NOTE: The template is fixed for the VF Module. The environment is part of the customization. + + HeatTemplate heatTemplate = null; + HeatEnvironment heatEnvironment = null; + if (isVolumeRequest) { + heatTemplate = vfModule.getVolumeHeatTemplate(); + heatEnvironment = vfModuleCust.getVolumeHeatEnv(); + } else { + heatTemplate = vfModule.getModuleHeatTemplate(); + heatEnvironment = vfModuleCust.getHeatEnvironment(); + } + + if (heatTemplate == null) { + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + requestType; + LOGGER.error(MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Template ID", vfModuleType, "VNF", "", 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 { + LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } + + if (heatEnvironment == null) { + String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; + LOGGER.error (MessageEnum.RA_VNF_UNKNOWN_PARAM, "Heat Environment ID", "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.getEnvironment()); + } + + + // Create the combined set of parameters from the incoming request, base-module outputs, + // volume-module outputs. Also, convert all variables to their native object types. + + HashMap<String, Object> goldenInputs = new HashMap<String,Object>(); + List<String> extraInputs = new ArrayList<String>(); + + Boolean skipInputChecks = false; + + if (skipInputChecks) { + goldenInputs = new HashMap<String,Object>(); + for (String key : inputs.keySet()) { + goldenInputs.put(key, inputs.get(key)); + } + } + else { + // Build maps for the parameters (including aliases) to simplify checks + HashMap<String, HeatTemplateParam> params = new HashMap<String, HeatTemplateParam>(); + + Set<HeatTemplateParam> paramSet = heatTemplate.getParameters(); + LOGGER.debug("paramSet has " + paramSet.size() + " entries"); + + for (HeatTemplateParam htp : paramSet) { + params.put(htp.getParamName(), htp); + + // Include aliases. + String alias = htp.getParamAlias(); + if (alias != null && !alias.equals("") && !params.containsKey(alias)) { + params.put(alias, htp); + } + } + + // First, convert all inputs to their "template" type + for (String key : inputs.keySet()) { + if (params.containsKey(key)) { + Object value = convertInputValue(inputs.get(key), params.get(key)); + if (value != null) { + goldenInputs.put(key, value); + } + else { + LOGGER.debug("Failed to convert input " + key + "='" + inputs.get(key) + "' to " + params.get(key).getParamType()); + } + } else { + extraInputs.add(key); + } + } + + if (!extraInputs.isEmpty()) { + LOGGER.debug("Ignoring extra inputs: " + extraInputs); + } + + // Next add in Volume Group Outputs if there are any. Copy directly without conversions. + if (volumeGroupOutputs != null && !volumeGroupOutputs.isEmpty()) { + for (String key : volumeGroupOutputs.keySet()) { + if (params.containsKey(key) && !goldenInputs.containsKey(key)) { + goldenInputs.put(key, volumeGroupOutputs.get(key)); + } + } + } + + // Next add in Base Module Outputs if there are any. Copy directly without conversions. + if (baseModuleOutputs != null && !baseModuleOutputs.isEmpty()) { + for (String key : baseModuleOutputs.keySet()) { + if (params.containsKey(key) && !goldenInputs.containsKey(key)) { + goldenInputs.put(key, baseModuleOutputs.get(key)); + } + } + } + + // TODO: The model should support a mechanism to pre-assign default parameter values + // per "customization" (i.e. usage) of a given module. In HEAT, this is specified by + // an Environment file. There is not a general mechanism in the model to handle this. + // For the general case, any such parameter/values can be added dynamically to the + // inputs (only if not already specified). + + + // Check that required parameters have been supplied from any of the sources + String missingParams = null; + boolean checkRequiredParameters = true; + try { + String propertyString = this.environment.getProperty(MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS); + if ("false".equalsIgnoreCase (propertyString) || "n".equalsIgnoreCase (propertyString)) { + checkRequiredParameters = false; + LOGGER.debug ("CheckRequiredParameters is FALSE. Will still check but then skip blocking..." + + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS); + } + } catch (Exception e) { + // No problem - default is true + LOGGER.debug ("An exception occured trying to get property " + MsoVnfPluginAdapterImpl.CHECK_REQD_PARAMS, e); + } + + // Do the actual parameter checking. + // Include looking at the ENV file as a valid definition of a parameter value. + // TODO: This handling of ENV applies only to Heat. A general mechanism to + // support pre-set parameter/values does not yet exist in the model. + // + StringBuilder sb = new StringBuilder(heatEnvironment.getEnvironment()); + MsoHeatEnvironmentEntry mhee = new MsoHeatEnvironmentEntry (sb); + for (HeatTemplateParam parm : heatTemplate.getParameters ()) { + if (parm.isRequired () && (!goldenInputs.containsKey (parm.getParamName ()))) { + 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 (); + } + } + } + } + + 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, "VDU", "", 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 [" + missingParams + "] - but checkRequiredParameters is false - will not block"); + } + } else { + LOGGER.debug ("No missing parameters found - ok to proceed"); + } + + } // NOTE: END PARAMETER CHECKING + + + // Here we go... ready to deploy the VF Module. + long instantiateVduStartTime = System.currentTimeMillis (); + if (backout == null) backout = true; + + try { + // Construct the VDU Model structure to pass to the targeted VduPlugin + VduModelInfo vduModel = null; + if (! isVolumeRequest) { + vduModel = vduMapper.mapVfModuleCustomizationToVdu(vfModuleCust); + } else { + vduModel = vduMapper.mapVfModuleCustVolumeToVdu(vfModuleCust); + } + + // Invoke the VduPlugin to instantiate the VF Module + vduInstance = vduPlugin.instantiateVdu(cloudInfo, vfModuleName, goldenInputs, vduModel, backout); + + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from VduPlugin", "VDU", "instantiateVdu", vfModuleName); + } + catch (VduException me) { + // Failed to instantiate the VDU. + me.addContext ("CreateVFModule"); + String error = "Create VF Module " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "instantiateVdu", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "MsoException - instantiateVdu", me); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + // Convert to a generic VnfException + throw new VnfException (me); + } + catch (NullPointerException npe) { + String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + npe; + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error, "VDU", "instantiateVdu", vfModuleName); + LOGGER.error (MessageEnum.RA_CREATE_VNF_ERR, vfModuleType, cloudSiteId, tenantId, "VDU", "", MsoLogger.ErrorCode.DataError, "NullPointerException - instantiateVdu", npe); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error); + LOGGER.debug("NULL POINTER EXCEPTION at vduPlugin.instantiateVdu", npe); + throw new VnfException ("NullPointerException during instantiateVdu"); + } + catch (Exception e) { + String error = "Create VFModule " + vfModuleType + " in " + cloudSiteId + "/" + tenantId + ": " + e; + LOGGER.recordMetricEvent (instantiateVduStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error, "VDU", "instantiateVdu", vfModuleName); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, error); + LOGGER.debug("Unhandled exception at vduPlugin.instantiateVdu", e); + throw new VnfException("Exception during instantiateVdu: " + e.getMessage()); + } + + + // Reach this point if create is successful. + // Populate remaining rollback info and response parameters. + vfRollback.setVnfCreated (true); + vfRollback.setVnfId (vduInstance.getVduInstanceId()); + vnfId.value = vduInstance.getVduInstanceId(); + outputs.value = copyStringOutputs (vduInstance.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 vfModuleId, + MsoRequest msoRequest, + Holder <Map <String, String>> outputs) throws VnfException + { + MsoLogger.setLogContext (msoRequest); + MsoLogger.setServiceName ("DeleteVfModule"); + + LOGGER.debug ("Deleting VF Module " + vfModuleId + " in " + cloudSiteId + "/" + tenantId); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + + // Capture the output parameters on a delete, so need to query first + VduInstance vduInstance = null; + CloudInfo cloudInfo = new CloudInfo(cloudSiteId, tenantId, null); + + // Use the VduPlugin. + VduPlugin vduPlugin = getVduPlugin(cloudSiteId); + + try { + vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleId); + LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received VDU Query response", "VDU", "QueryVDU", vfModuleId); + } + catch (VduException e) { + // Failed to query the VDU due to a plugin exception. + // Convert to a generic VnfException + e.addContext ("QueryVFModule"); + String error = "Query VfModule (VDU): " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + e; + LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "VDU", "QueryVNF", vfModuleId); + LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "QueryVFModule", MsoLogger.ErrorCode.DataError, "Exception - queryVDU", e); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error); + throw new VnfException (e); + } + + // call method which handles the conversion from Map<String,Object> to Map<String,String> for our expected Object types + outputs.value = convertMapStringObjectToStringString(vduInstance.getOutputs()); + + // Use the VduPlugin to delete the VDU. + // The possible outcomes of deleteVdu are + // - a vnfInstance object with status of DELETED (success) + // - a vnfInstance object with status of NOTFOUND (VDU did not exist, treat as success) + // - a vnfInstance object with status of FAILED (error) + // Also, VduException could be thrown. + long subStartTime = System.currentTimeMillis (); + try { + // TODO: Get an appropriate timeout value - require access to the model + vduPlugin.deleteVdu(cloudInfo, vfModuleId, 5); + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from deleteVdu", "VDU", "DeleteVdu", vfModuleId); + } catch (VduException me) { + me.addContext ("DeleteVfModule"); + // Convert to a generic VnfException + String error = "Delete VF: " + vfModuleId + " in " + cloudSiteId + "/" + tenantId + ": " + me; + LOGGER.recordMetricEvent (subStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "DeleteVdu", "DeleteVdu", vfModuleId); + LOGGER.error (MessageEnum.RA_DELETE_VNF_ERR, vfModuleId, cloudSiteId, tenantId, "VDU", "DeleteVdu", MsoLogger.ErrorCode.DataError, "Exception - DeleteVdu: " + me.getMessage()); + 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; + } + + // Update VF Module not yet implemented for generic VDU plug-in model. + @Override + public void updateVfModule (String cloudSiteId, + String tenantId, + String vnfType, + String vnfVersion, + String vnfName, + String requestType, + String volumeGroupHeatStackId, + String baseVfHeatStackId, + String vfModuleStackId, + String modelCustomizationUuid, + Map <String, String> inputs, + MsoRequest msoRequest, + Holder <Map <String, String>> outputs, + Holder <VnfRollback> rollback) throws VnfException + { + // This operation is not currently supported for VduPlugin-orchestrated VF Modules. + LOGGER.debug ("Update VF Module command attempted but not supported"); + throw new VnfException ("UpdateVfModule: Unsupported command", MsoExceptionCategory.USERDATA); + } + + /* + * Dynamic selection of a VduPlugin version. For initial tests, base on the "orchestrator" + * defined for the target cloud. Should really be looking at the VNF Model (ochestration_mode) + * but we don't currently have access to that in Query and Delete cases. + */ + private VduPlugin getVduPlugin (String cloudSiteId) { + Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite(cloudSiteId); + if (cloudSiteOp.isPresent()) { + CloudSite cloudSite = cloudSiteOp.get(); + String orchestrator = cloudSite.getOrchestrator(); + + if (orchestrator.equalsIgnoreCase("CLOUDIFY")) { + return cloudifyUtils; + } + else if (orchestrator.equalsIgnoreCase("HEAT")) { + return heatUtils; + } + } + + // Default - return HEAT plugin, though will fail later + return heatUtils; + } +}
\ No newline at end of file diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VfRollback.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VfRollback.java new file mode 100644 index 0000000000..5dca8696ef --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VfRollback.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf; + + + +import org.onap.so.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-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java new file mode 100644 index 0000000000..3e27361ed1 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java @@ -0,0 +1,691 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.vnf; + + +import java.util.Map; + +import javax.inject.Provider; +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.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVfModuleRequest; +import org.onap.so.adapters.vnfrest.CreateVfModuleResponse; +import org.onap.so.adapters.vnfrest.DeleteVfModuleRequest; +import org.onap.so.adapters.vnfrest.DeleteVfModuleResponse; +import org.onap.so.adapters.vnfrest.QueryVfModuleResponse; +import org.onap.so.adapters.vnfrest.RollbackVfModuleRequest; +import org.onap.so.adapters.vnfrest.RollbackVfModuleResponse; +import org.onap.so.adapters.vnfrest.UpdateVfModuleRequest; +import org.onap.so.adapters.vnfrest.UpdateVfModuleResponse; +import org.onap.so.adapters.vnfrest.VfModuleExceptionResponse; +import org.onap.so.adapters.vnfrest.VfModuleRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * 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") +@Api(value = "/v1/vnfs", description = "root of vnf adapters restful web service") +@Transactional +@Component +public class VnfAdapterRest { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, VnfAdapterRest.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private MsoVnfAdapterImpl vnfAdapter; + //TODO Logging, SkipAAI, CREATED flags, Integrate with BPEL, Auth, + + @Autowired + @Qualifier("VnfBpel") + private Provider<BpelRestClient> bpelRestClientProvider; + + + /* + * 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 }) + @ApiOperation(value = "DeleteVfModule", + response = Response.class, + notes = "Delete an existing vnfModule, DeleteVfModuleRequest JSON is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfModule request has been accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfModule failed, examine entity object for details") }) + public Response deleteVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "DeleteVfModuleRequest", required = true) + 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(); + Holder<Map<String, String>> outputs = new Holder <> (); + 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(), outputs); + } + response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE, req.getMessageId(), outputs.value); + } 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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "QueryVfModule", + response = Response.class, + notes = "Query an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfModule failed, examine entity object for details") }) + public Response queryVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "vfModuleName", required = true) + @QueryParam("vfModuleName") String vfModuleName, //RAA? Id in doc + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @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<>(); + Holder<String> vfModuleId = new Holder<>(); + Holder<VnfStatus> status = new Holder<>(); + Holder<Map<String, String>> outputs = new Holder <> (); + 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 }) + @ApiOperation(value = "CreateVfModule", + response = Response.class, + notes = "Create a vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully created"), + @ApiResponse(code = 202, message = "create vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfModule failed, examine entity object for details") }) + public Response createVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "CreateVfModuleRequest", required = true) + 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 <> (); + Holder <Map <String, String>> outputs = new Holder <> (); + Holder <VnfRollback> vnfRollback = new Holder <> (); + 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(), req.getModelCustomizationUuid()); + 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.getModelCustomizationUuid(), + req.getVfModuleParams(), + req.getFailIfExists(), + req.getBackout(), + req.getEnableBridge(), + 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) { + LOGGER.debug("Exception :",e); + eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); + } + if (!req.isSynchronous()) { + BpelRestClient bpelClient = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "UpdateVfModule", + response = Response.class, + notes = "Update an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfModule failed, examine entity object for details") }) + public Response updateVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "UpdateVfModuleRequest", required = true) + 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 <> (); + Holder <Map <String, String>> outputs = new Holder <> (); + Holder <VnfRollback> vnfRollback = new Holder <> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVf - completeVnfVfModuleType=" + completeVnfVfModuleType); + + vnfAdapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleStackId(), + req.getVfModuleStackId(), + req.getModelCustomizationUuid(), + req.getVfModuleParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + + response = new UpdateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), + vfModuleStackId.value, outputs.value, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "RollbackVfModule", + response = Response.class, + notes = "Rollback an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfModule failed, examine entity object for details") }) + public Response rollbackVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "RollbackVfModuleRequest", required = true) + //@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, 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 = bpelRestClientProvider.get(); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("RollbackVfModulesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } +}
\ No newline at end of file diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestUtils.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestUtils.java new file mode 100644 index 0000000000..876aae8a37 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestUtils.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf; + +import java.util.Optional; + +import org.onap.so.cloud.CloudConfig; +import org.onap.so.cloud.CloudSite; +import org.onap.so.logger.MsoLogger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class VnfAdapterRestUtils +{ + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, VnfAdapterRestUtils.class); + + @Autowired + private CloudConfig cloudConfig; + + @Autowired + private MsoVnfCloudifyAdapterImpl cloudifyImpl; + + @Autowired + private MsoVnfAdapterImpl vnfImpl; + + /* + * Choose which implementation of VNF Adapter to use, based on the orchestration mode. + * Currently, the two supported orchestrators are HEAT and CLOUDIFY. + */ + public MsoVnfAdapter getVnfAdapterImpl (String mode, String cloudSiteId) + { + // First, determine the orchestration mode to use. + // If was explicitly provided as a parameter, use that. Else if specified for the + // cloudsite, use that. Otherwise, the default is the (original) HEAT-based impl. + + LOGGER.debug ("Entered GetVnfAdapterImpl: mode=" + mode + ", cloudSite=" + cloudSiteId); + + if (mode == null) { + // Didn't get an explicit mode type requested. + // Use the CloudSite to determine which Impl to use, based on whether the target cloutSite + // has a CloudifyManager assigned to it + Optional<CloudSite> cloudSite = cloudConfig.getCloudSite(cloudSiteId); + if (cloudSite.isPresent()) { + LOGGER.debug("Got CloudSite: " + cloudSite.toString()); + if (cloudConfig.getCloudifyManager(cloudSite.get().getCloudifyId()) != null) { + mode = "CLOUDIFY"; + } else { + mode = "HEAT"; + } + } + } + + LOGGER.debug ("GetVnfAdapterImpl: mode=" + mode); + + MsoVnfAdapter vnfAdapter = null; + + // TODO: Make this more dynamic (e.g. Service Loader) + if ("CLOUDIFY".equalsIgnoreCase(mode)) { + LOGGER.debug ("GetVnfAdapterImpl: Return Cloudify Adapter"); + vnfAdapter = cloudifyImpl; + } + else if ("HEAT".equalsIgnoreCase(mode)) { + LOGGER.debug ("GetVnfAdapterImpl: Return Heat Adapter"); + vnfAdapter = vnfImpl; + } + else { + // Don't expect this, but default is the HEAT adapter + LOGGER.debug ("GetVnfAdapterImpl: Return Default (Heat) Adapter"); + vnfAdapter = vnfImpl; + } + + return vnfAdapter; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java new file mode 100644 index 0000000000..143f169c84 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java @@ -0,0 +1,704 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf; + + +import java.util.Map; + +import javax.inject.Provider; +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.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVfModuleRequest; +import org.onap.so.adapters.vnfrest.CreateVfModuleResponse; +import org.onap.so.adapters.vnfrest.DeleteVfModuleRequest; +import org.onap.so.adapters.vnfrest.DeleteVfModuleResponse; +import org.onap.so.adapters.vnfrest.QueryVfModuleResponse; +import org.onap.so.adapters.vnfrest.RollbackVfModuleRequest; +import org.onap.so.adapters.vnfrest.RollbackVfModuleResponse; +import org.onap.so.adapters.vnfrest.UpdateVfModuleRequest; +import org.onap.so.adapters.vnfrest.UpdateVfModuleResponse; +import org.onap.so.adapters.vnfrest.VfModuleExceptionResponse; +import org.onap.so.adapters.vnfrest.VfModuleRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * This class services calls to the REST interface for VF Modules (http://host:port/vnfs/rest/v2/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___ + * + * V2 incorporates run-time selection of sub-orchestrator implementation (Heat or Cloudify) + * based on the target cloud. + */ +@Path("/v2/vnfs") +@Api(value = "/v2/vnfs", description = "root of vnf adapters restful web service v2") +@Component +public class VnfAdapterRestV2 { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, VnfAdapterRestV2.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private VnfAdapterRestUtils vnfAdapterRestUtils; + + @Autowired + @Qualifier("VnfBpel") + private Provider<BpelRestClient> bpelRestClientProvider; + + /* + * URL:http://localhost:8080/vnfs/rest/v2/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 }) + @ApiOperation(value = "DeleteVfModule", + response = Response.class, + notes = "Delete an existing vnfModule, DeleteVfModuleRequest JSON is required") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfModule request has been accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfModule failed, examine entity object for details") }) + public Response deleteVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "DeleteVfModuleRequest", required = true) + 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, mode); + 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; + private String mode; + + public DeleteVfModuleTask(DeleteVfModuleRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + 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(); + Holder<Map<String, String>> outputs = new Holder <Map <String, String>> (); + if (cloudsite != null && !cloudsite.equals(TESTING_KEYWORD)) { + //vnfAdapter.deleteVnf (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest()); + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsite); + adapter.deleteVfModule (req.getCloudSiteId(), req.getTenantId(), req.getVfModuleStackId(), req.getMsoRequest(), outputs); + } + response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE, req.getMessageId(), outputs.value); + } 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 = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Delete vfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + /* + * URL:http://localhost:8080/vnfs/rest/v2/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 }) + @ApiOperation(value = "QueryVfModule", + response = Response.class, + notes = "Query an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfModule failed, examine entity object for details") }) + public Response queryVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "vfModuleName", required = true) + @QueryParam("vfModuleName") String vfModuleName, //RAA? Id in doc + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode) + { + //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>> (); + + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudSiteId); + adapter.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/v2/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 }) + @ApiOperation(value = "CreateVfModule", + response = Response.class, + notes = "Create a vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully created"), + @ApiResponse(code = 202, message = "create vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfModule failed, examine entity object for details") }) + public Response createVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "CreateVfModuleRequest", required = true) + 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, mode); + 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; + private String mode; + + public CreateVfModuleTask(CreateVfModuleRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + 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 cloudsiteId = req.getCloudSiteId(); + if (cloudsiteId != null && cloudsiteId.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, cloudsiteId, + true, false, new MsoRequest("reqid", "svcid"), + req.getVolumeGroupId(), req.getVolumeGroupId(), req.getRequestType(), req.getModelCustomizationUuid()); + vfModuleStackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; + outputs.value = VolumeAdapterRest.testMap(); + } else { + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsiteId); + adapter.createVfModule(req.getCloudSiteId(), + req.getTenantId(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleStackId(), + req.getModelCustomizationUuid(), + req.getVfModuleParams(), + req.getFailIfExists(), + req.getBackout(), + req.getEnableBridge(), + 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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "UpdateVfModule", + response = Response.class, + notes = "Update an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfModule failed, examine entity object for details") }) + public Response updateVfModule( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "UpdateVfModuleRequest", required = true) + final UpdateVfModuleRequest req) + { + LOGGER.debug("Update VfModule enter: " + req.toJsonString()); + UpdateVfModulesTask task = new UpdateVfModulesTask(req, mode); + 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; + private String mode; + + public UpdateVfModulesTask(UpdateVfModuleRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + 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); + + String cloudsiteId = req.getCloudSiteId(); + + // Support different Adapter Implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsiteId); + adapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVfModuleName(), + req.getRequestType(), + req.getVolumeGroupStackId(), + req.getBaseVfModuleId(), + req.getVfModuleStackId(), + req.getModelCustomizationUuid(), + 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 = bpelRestClientProvider.get(); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("Update VfModule exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + /* + * URL:http://localhost:8080/vnfs/rest/v2/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 }) + @ApiOperation(value = "RollbackVfModule", + response = Response.class, + notes = "Rollback an existing vnfModule") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfModule has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfModule request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfModule failed, examine entity object for details") }) + public Response rollbackVfModule ( + @ApiParam(value = "aaiVnfId", required = true) + @PathParam("aaiVnfId") String aaiVnfId, + @ApiParam(value = "aaiVfModuleId", required = true) + @PathParam("aaiVfModuleId") String aaiVfModuleId, + @ApiParam(value = "RollbackVfModuleRequest", required = true) + //@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, vmr.isVfModuleCreated(), + vmr.getMsoRequest(), null, null, null, null); + + // Support multiple adapter implementations + MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl (vmr.getMode(), vmr.getCloudSiteId()); + adapter.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 = bpelRestClientProvider.get(); + bpelClient.bpelPost (getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("RollbackVfModulesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java new file mode 100644 index 0000000000..b4b5894491 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java @@ -0,0 +1,646 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.onap.so.adapters.vnf; + + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Provider; +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.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.QueryVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupExceptionResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * 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") +@Api(value = "/v1/volume-groups", description = "root of volume-groups adapters restful web service") +@Component +public class VolumeAdapterRest { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, VolumeAdapterRest.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private MsoVnfAdapterImpl vnfAdapter; + + @Autowired + @Qualifier("VnfBpel") + private Provider<BpelRestClient> bpelRestClientProvider; + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateVNFVolumes", + response = Response.class, + notes = "Create a new vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully created"), + @ApiResponse(code = 202, message = "create vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfVolume failed, examine entity object for details") }) + public Response createVNFVolumes( + @ApiParam(value = "CreateVolumeGroupRequest", required = true) + 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<>(); + Holder<Map<String, String>> outputs = new Holder<>(); + Holder<VnfRollback> vnfRollback = new Holder<>(); + 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.getModelCustomizationUuid(), + req.getVolumeGroupParams(), //inputs, + req.getFailIfExists(), //failIfExists, + req.getSuppressBackout(), //backout, + req.getEnableBridge(), + 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) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "DeleteVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfVolume failed, examine entity object for details") }) + public Response deleteVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "DeleteVolumeGroupRequest", required = true) + 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) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "RollbackVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfVolume failed, examine entity object for details") }) + public Response rollbackVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "RollbackVolumeGroupRequest", required = true) + 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, null); + vnfAdapter.rollbackVnf(vrb); + response = new RollbackVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "UpdateVNFVolumes", + response = Response.class, + notes = "Update an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfVolume failed, examine entity object for details") }) + public Response updateVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "UpdateVolumeGroupRequest", required = true) + 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 { + Holder<Map<String, String>> outputs = new Holder<> (); + Holder<VnfRollback> vnfRollback = new Holder<> (); + 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.getModelCustomizationUuid(), + req.getVolumeGroupParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + } + response = new UpdateVolumeGroupResponse( + req.getVolumeGroupId(), req.getVolumeGroupStackId(), + outputs.value, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiVolumeGroupId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryVNFVolumes", + response = Response.class, + notes = "Query an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfVolume failed, examine entity object for details") }) + public Response queryVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "volumeGroupStackId", required = true) + @QueryParam("volumeGroupStackId") String volumeGroupStackId, + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @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<>(); + Holder<String> vfModuleId = new Holder<>(); + Holder<VnfStatus> status = new Holder<>(); + Holder<Map<String, String>> outputs = new Holder<>(); + 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<>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java new file mode 100644 index 0000000000..3f3a312e12 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java @@ -0,0 +1,648 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf; + + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Provider; +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.onap.so.adapters.vnf.exceptions.VnfException; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.CreateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.DeleteVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.QueryVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.RollbackVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupRequest; +import org.onap.so.adapters.vnfrest.UpdateVolumeGroupResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupExceptionResponse; +import org.onap.so.adapters.vnfrest.VolumeGroupRollback; +import org.onap.so.entity.MsoRequest; +import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.MsoLogger; +import org.onap.so.openstack.beans.VnfRollback; +import org.onap.so.openstack.beans.VnfStatus; +import org.onap.so.openstack.exceptions.MsoExceptionCategory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +/** + * 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___ + * + * V2 incorporates run-time selection of sub-orchestrator implementation (Heat or Cloudify) + * based on the target cloud. + */ +@Path("/v2/volume-groups") +@Api(value = "/v2/volume-groups", description = "root of volume-groups adapters restful web service v2") +@Component +public class VolumeAdapterRestV2 { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, VolumeAdapterRestV2.class); + private static final String TESTING_KEYWORD = "___TESTING___"; + + @Autowired + private VnfAdapterRestUtils vnfAdapterRestUtils; + + @Autowired + @Qualifier("VnfBpel") + private Provider<BpelRestClient> bpelRestClientProvider; + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "CreateVNFVolumes", + response = Response.class, + notes = "Create a new vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully created"), + @ApiResponse(code = 202, message = "create vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "create vnfVolume failed, examine entity object for details") }) + public Response createVNFVolumes( + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "CreateVolumeGroupRequest", required = true) + final CreateVolumeGroupRequest req) + { + LOGGER.debug("createVNFVolumes enter: " + req.toJsonString()); + CreateVNFVolumesTask task = new CreateVNFVolumesTask(req, mode); + 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; + private String mode; + + public CreateVNFVolumesTask(CreateVolumeGroupRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + 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<>(); + Holder<Map<String, String>> outputs = new Holder<>(); + Holder<VnfRollback> vnfRollback = new Holder<>(); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in createVfModuleVolumes - completeVnfVfModuleType=" + completeVnfVfModuleType); + + String cloudsiteId = req.getCloudSiteId(); + if (cloudsiteId != null && cloudsiteId.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 { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsiteId); + vnfAdapter.createVfModule( + req.getCloudSiteId(), //cloudSiteId, + req.getTenantId(), //tenantId, + completeVnfVfModuleType, //vnfType, + req.getVnfVersion(), //vnfVersion, + req.getVolumeGroupName(), //vnfName, + "VOLUME", //requestType, + null, //volumeGroupHeatStackId, + null, //baseVfHeatStackId, + req.getModelCustomizationUuid(), + req.getVolumeGroupParams(), //inputs, + req.getFailIfExists(), //failIfExists, + req.getSuppressBackout(), //backout, + req.getEnableBridge(), + req.getMsoRequest(), // msoRequest, + stackId, + outputs, + vnfRollback); + } + + VolumeGroupRollback rb = new VolumeGroupRollback( + req.getVolumeGroupId(), + stackId.value, + vnfRollback.value.getVnfCreated(), + req.getTenantId(), + req.getCloudSiteId(), + req.getMsoRequest(), + req.getMessageId()); + + response = new CreateVolumeGroupResponse( + req.getVolumeGroupId(), + stackId.value, + vnfRollback.value.getVnfCreated(), + outputs.value, + rb, + req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "DeleteVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully deleted"), + @ApiResponse(code = 202, message = "delete vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "delete vnfVolume failed, examine entity object for details") }) + public Response deleteVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "DeleteVolumeGroupRequest", required = true) + 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, mode); + 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; + private String mode; + + public DeleteVNFVolumesTask(DeleteVolumeGroupRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + 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"); + String cloudSiteId = req.getCloudSiteId(); + try { + if (! cloudSiteId.equals(TESTING_KEYWORD)) { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudSiteId); + vnfAdapter.deleteVnf(req.getCloudSiteId(), req.getTenantId(), req.getVolumeGroupStackId(), req.getMsoRequest()); + } + response = new DeleteVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + 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 }) + @ApiOperation(value = "RollbackVNFVolumes", + response = Response.class, + notes = "Delete an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully rolled back"), + @ApiResponse(code = 202, message = "rollback vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "rollback vnfVolume failed, examine entity object for details") }) + public Response rollbackVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "RollbackVolumeGroupRequest", required = true) + 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("RollbackVNFVolumesTask start"); + try { + VolumeGroupRollback vgr = req.getVolumeGroupRollback(); + VnfRollback vrb = new VnfRollback( + vgr.getVolumeGroupStackId(), vgr.getTenantId(), vgr.getCloudSiteId(), true, true, + vgr.getMsoRequest(), null, null, null, null); + + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(vrb.getMode(), vrb.getCloudSiteId()); + vnfAdapter.rollbackVnf(vrb); + response = new RollbackVolumeGroupResponse(true, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("RollbackVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + + } + + @PUT + @Path("{aaiVolumeGroupId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "UpdateVNFVolumes", + response = Response.class, + notes = "Update an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully updated"), + @ApiResponse(code = 202, message = "update vnfVolume request has been successfully accepted (async only)"), + @ApiResponse(code = 500, message = "update vnfVolume failed, examine entity object for details") }) + public Response updateVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode, + @ApiParam(value = "UpdateVolumeGroupRequest", required = true) + 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, mode); + 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; + private String mode; + + public UpdateVNFVolumesTask(UpdateVolumeGroupRequest req, String mode) { + this.req = req; + this.sendxml = true; // can be set with a field or header later + this.mode = mode; + } + 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 { + Holder<Map<String, String>> outputs = new Holder<> (); + Holder<VnfRollback> vnfRollback = new Holder<> (); + String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType(); + LOGGER.debug("in updateVfModuleVolume - completeVnfVfModuleType=" + completeVnfVfModuleType); + + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + outputs.value = testMap(); + } else { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, req.getCloudSiteId()); + vnfAdapter.updateVfModule (req.getCloudSiteId(), + req.getTenantId(), + //req.getVnfType(), + completeVnfVfModuleType, + req.getVnfVersion(), + req.getVolumeGroupStackId(), + "VOLUME", + null, + null, + req.getVolumeGroupStackId(), + req.getModelCustomizationUuid(), + req.getVolumeGroupParams(), + req.getMsoRequest(), + outputs, + vnfRollback); + } + response = new UpdateVolumeGroupResponse( + req.getVolumeGroupId(), req.getVolumeGroupStackId(), + outputs.value, req.getMessageId()); + } catch (VnfException e) { + LOGGER.debug("Exception :",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 = bpelRestClientProvider.get(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateVNFVolumesTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiVolumeGroupId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @ApiOperation(value = "QueryVNFVolumes", + response = Response.class, + notes = "Query an existing vnfVolume") + @ApiResponses({ + @ApiResponse(code = 200, message = "vnfVolume has been successfully queried"), + @ApiResponse(code = 500, message = "query vnfVolume failed, examine entity object for details") }) + public Response queryVNFVolumes( + @ApiParam(value = "aaiVolumeGroupId", required = true) + @PathParam("aaiVolumeGroupId") String aaiVolumeGroupId, + @ApiParam(value = "cloudSiteId", required = true) + @QueryParam("cloudSiteId") String cloudSiteId, + @ApiParam(value = "tenantId", required = true) + @QueryParam("tenantId") String tenantId, + @ApiParam(value = "volumeGroupStackId", required = true) + @QueryParam("volumeGroupStackId") String volumeGroupStackId, + @ApiParam(value = "skipAAI", required = true) + @QueryParam("skipAAI") Boolean skipAAI, + @ApiParam(value = "msoRequest.requestId", required = true) + @QueryParam("msoRequest.requestId") String requestId, + @ApiParam(value = "msoRequest.serviceInstanceId", required = true) + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, + @ApiParam(value = "mode", required = true) + @QueryParam("mode") String mode + ) + { + //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<>(); + Holder<String> vfModuleId = new Holder<>(); + Holder<VnfStatus> status = new Holder<>(); + Holder<Map<String, String>> outputs = new Holder<>(); + 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 { + // Support different Adapter Implementations + MsoVnfAdapter vnfAdapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudSiteId); + 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<>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/CreateVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/CreateVnfNotification.java new file mode 100644 index 0000000000..39bd3ebf61 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/CreateVnfNotification.java @@ -0,0 +1,410 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for createVnfNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="createVnfNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="vnfId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="outputs" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <element name="rollback" type="{http://org.onap.so/vnfNotify}vnfRollback" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "createVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "vnfId", + "outputs", + "rollback" +}) +public class CreateVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected String vnfId; + protected CreateVnfNotification.Outputs outputs; + protected VnfRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the vnfId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVnfId() { + return vnfId; + } + + /** + * Sets the value of the vnfId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVnfId(String value) { + this.vnfId = value; + } + + /** + * Gets the value of the outputs property. + * + * @return + * possible object is + * {@link CreateVnfNotification.Outputs } + * + */ + public CreateVnfNotification.Outputs getOutputs() { + return outputs; + } + + /** + * Sets the value of the outputs property. + * + * @param value + * allowed object is + * {@link CreateVnfNotification.Outputs } + * + */ + public void setOutputs(CreateVnfNotification.Outputs value) { + this.outputs = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link VnfRollback } + * + */ + public VnfRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link VnfRollback } + * + */ + public void setRollback(VnfRollback value) { + this.rollback = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class Outputs { + + protected List<CreateVnfNotification.Outputs.Entry> entry; + + /** + * Gets the value of the entry property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the entry property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getEntry().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link CreateVnfNotification.Outputs.Entry } + * + * + */ + public List<CreateVnfNotification.Outputs.Entry> getEntry() { + if (entry == null) { + entry = new ArrayList<CreateVnfNotification.Outputs.Entry>(); + } + return this.entry; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/DeleteVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/DeleteVnfNotification.java new file mode 100644 index 0000000000..d8c533b041 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/DeleteVnfNotification.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for deleteVnfNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="deleteVnfNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "deleteVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage" +}) +public class DeleteVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoExceptionCategory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoExceptionCategory.java new file mode 100644 index 0000000000..73642a7f44 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoExceptionCategory.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for msoExceptionCategory. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * <p> + * <pre> + * <simpleType name="msoExceptionCategory"> + * <restriction base="{http://www.w3.org/2001/XMLSchema}string"> + * <enumeration value="OPENSTACK"/> + * <enumeration value="IO"/> + * <enumeration value="INTERNAL"/> + * <enumeration value="USERDATA"/> + * </restriction> + * </simpleType> + * </pre> + * + */ +@XmlType(name = "msoExceptionCategory") +@XmlEnum +public enum MsoExceptionCategory { + + OPENSTACK, + IO, + INTERNAL, + USERDATA; + + public String value() { + return name(); + } + + public static MsoExceptionCategory fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoRequest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoRequest.java new file mode 100644 index 0000000000..a4253b0cef --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/MsoRequest.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for msoRequest complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="msoRequest"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="requestId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="serviceInstanceId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "msoRequest", propOrder = { + "requestId", + "serviceInstanceId" +}) +public class MsoRequest { + + protected String requestId; + protected String serviceInstanceId; + + /** + * Gets the value of the requestId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getRequestId() { + return requestId; + } + + /** + * Sets the value of the requestId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRequestId(String value) { + this.requestId = value; + } + + /** + * Gets the value of the serviceInstanceId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getServiceInstanceId() { + return serviceInstanceId; + } + + /** + * Sets the value of the serviceInstanceId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setServiceInstanceId(String value) { + this.serviceInstanceId = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/ObjectFactory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/ObjectFactory.java new file mode 100644 index 0000000000..0ab0fde747 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/ObjectFactory.java @@ -0,0 +1,208 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the org.onap.so.adapters.vnf.async.client package. + * <p>An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _QueryVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "queryVnfNotification"); + private final static QName _RollbackVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "rollbackVnfNotification"); + private final static QName _CreateVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "createVnfNotification"); + private final static QName _DeleteVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "deleteVnfNotification"); + private final static QName _UpdateVnfNotification_QNAME = new QName("http://org.onap.so/vnfNotify", "updateVnfNotification"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.onap.so.adapters.vnf.async.client + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link UpdateVnfNotification } + * + */ + public UpdateVnfNotification createUpdateVnfNotification() { + return new UpdateVnfNotification(); + } + + /** + * Create an instance of {@link UpdateVnfNotification.Outputs } + * + */ + public UpdateVnfNotification.Outputs createUpdateVnfNotificationOutputs() { + return new UpdateVnfNotification.Outputs(); + } + + /** + * Create an instance of {@link CreateVnfNotification } + * + */ + public CreateVnfNotification createCreateVnfNotification() { + return new CreateVnfNotification(); + } + + /** + * Create an instance of {@link CreateVnfNotification.Outputs } + * + */ + public CreateVnfNotification.Outputs createCreateVnfNotificationOutputs() { + return new CreateVnfNotification.Outputs(); + } + + /** + * Create an instance of {@link QueryVnfNotification } + * + */ + public QueryVnfNotification createQueryVnfNotification() { + return new QueryVnfNotification(); + } + + /** + * Create an instance of {@link QueryVnfNotification.Outputs } + * + */ + public QueryVnfNotification.Outputs createQueryVnfNotificationOutputs() { + return new QueryVnfNotification.Outputs(); + } + + /** + * Create an instance of {@link RollbackVnfNotification } + * + */ + public RollbackVnfNotification createRollbackVnfNotification() { + return new RollbackVnfNotification(); + } + + /** + * Create an instance of {@link DeleteVnfNotification } + * + */ + public DeleteVnfNotification createDeleteVnfNotification() { + return new DeleteVnfNotification(); + } + + /** + * Create an instance of {@link MsoRequest } + * + */ + public MsoRequest createMsoRequest() { + return new MsoRequest(); + } + + /** + * Create an instance of {@link VnfRollback } + * + */ + public VnfRollback createVnfRollback() { + return new VnfRollback(); + } + + /** + * Create an instance of {@link UpdateVnfNotification.Outputs.Entry } + * + */ + public UpdateVnfNotification.Outputs.Entry createUpdateVnfNotificationOutputsEntry() { + return new UpdateVnfNotification.Outputs.Entry(); + } + + /** + * Create an instance of {@link CreateVnfNotification.Outputs.Entry } + * + */ + public CreateVnfNotification.Outputs.Entry createCreateVnfNotificationOutputsEntry() { + return new CreateVnfNotification.Outputs.Entry(); + } + + /** + * Create an instance of {@link QueryVnfNotification.Outputs.Entry } + * + */ + public QueryVnfNotification.Outputs.Entry createQueryVnfNotificationOutputsEntry() { + return new QueryVnfNotification.Outputs.Entry(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link QueryVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "queryVnfNotification") + public JAXBElement<QueryVnfNotification> createQueryVnfNotification(QueryVnfNotification value) { + return new JAXBElement<QueryVnfNotification>(_QueryVnfNotification_QNAME, QueryVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link RollbackVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "rollbackVnfNotification") + public JAXBElement<RollbackVnfNotification> createRollbackVnfNotification(RollbackVnfNotification value) { + return new JAXBElement<RollbackVnfNotification>(_RollbackVnfNotification_QNAME, RollbackVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link CreateVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "createVnfNotification") + public JAXBElement<CreateVnfNotification> createCreateVnfNotification(CreateVnfNotification value) { + return new JAXBElement<CreateVnfNotification>(_CreateVnfNotification_QNAME, CreateVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link DeleteVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "deleteVnfNotification") + public JAXBElement<DeleteVnfNotification> createDeleteVnfNotification(DeleteVnfNotification value) { + return new JAXBElement<DeleteVnfNotification>(_DeleteVnfNotification_QNAME, DeleteVnfNotification.class, null, value); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link UpdateVnfNotification }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://org.onap.so/vnfNotify", name = "updateVnfNotification") + public JAXBElement<UpdateVnfNotification> createUpdateVnfNotification(UpdateVnfNotification value) { + return new JAXBElement<UpdateVnfNotification>(_UpdateVnfNotification_QNAME, UpdateVnfNotification.class, null, value); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/QueryVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/QueryVnfNotification.java new file mode 100644 index 0000000000..0fd701d4f6 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/QueryVnfNotification.java @@ -0,0 +1,437 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for queryVnfNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="queryVnfNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="vnfExists" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/> + * <element name="vnfId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="status" type="{http://org.onap.so/vnfNotify}vnfStatus" minOccurs="0"/> + * <element name="outputs" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "queryVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "vnfExists", + "vnfId", + "status", + "outputs" +}) +public class QueryVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected Boolean vnfExists; + protected String vnfId; + protected VnfStatus status; + protected QueryVnfNotification.Outputs outputs; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the vnfExists property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isVnfExists() { + return vnfExists; + } + + /** + * Sets the value of the vnfExists property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setVnfExists(Boolean value) { + this.vnfExists = value; + } + + /** + * Gets the value of the vnfId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVnfId() { + return vnfId; + } + + /** + * Sets the value of the vnfId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVnfId(String value) { + this.vnfId = value; + } + + /** + * Gets the value of the status property. + * + * @return + * possible object is + * {@link VnfStatus } + * + */ + public VnfStatus getStatus() { + return status; + } + + /** + * Sets the value of the status property. + * + * @param value + * allowed object is + * {@link VnfStatus } + * + */ + public void setStatus(VnfStatus value) { + this.status = value; + } + + /** + * Gets the value of the outputs property. + * + * @return + * possible object is + * {@link QueryVnfNotification.Outputs } + * + */ + public QueryVnfNotification.Outputs getOutputs() { + return outputs; + } + + /** + * Sets the value of the outputs property. + * + * @param value + * allowed object is + * {@link QueryVnfNotification.Outputs } + * + */ + public void setOutputs(QueryVnfNotification.Outputs value) { + this.outputs = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class Outputs { + + protected List<QueryVnfNotification.Outputs.Entry> entry; + + /** + * Gets the value of the entry property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the entry property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getEntry().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link QueryVnfNotification.Outputs.Entry } + * + * + */ + public List<QueryVnfNotification.Outputs.Entry> getEntry() { + if (entry == null) { + entry = new ArrayList<QueryVnfNotification.Outputs.Entry>(); + } + return this.entry; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/RollbackVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/RollbackVnfNotification.java new file mode 100644 index 0000000000..05947f5e62 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/RollbackVnfNotification.java @@ -0,0 +1,154 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for rollbackVnfNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="rollbackVnfNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "rollbackVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage" +}) +public class RollbackVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/UpdateVnfNotification.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/UpdateVnfNotification.java new file mode 100644 index 0000000000..13fa8cb0ef --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/UpdateVnfNotification.java @@ -0,0 +1,383 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for updateVnfNotification complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="updateVnfNotification"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="messageId" type="{http://www.w3.org/2001/XMLSchema}string"/> + * <element name="completed" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="exception" type="{http://org.onap.so/vnfNotify}msoExceptionCategory" minOccurs="0"/> + * <element name="errorMessage" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="outputs" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <element name="rollback" type="{http://org.onap.so/vnfNotify}vnfRollback" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "updateVnfNotification", propOrder = { + "messageId", + "completed", + "exception", + "errorMessage", + "outputs", + "rollback" +}) +public class UpdateVnfNotification { + + @XmlElement(required = true) + protected String messageId; + protected boolean completed; + protected MsoExceptionCategory exception; + protected String errorMessage; + protected UpdateVnfNotification.Outputs outputs; + protected VnfRollback rollback; + + /** + * Gets the value of the messageId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessageId() { + return messageId; + } + + /** + * Sets the value of the messageId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessageId(String value) { + this.messageId = value; + } + + /** + * Gets the value of the completed property. + * + */ + public boolean isCompleted() { + return completed; + } + + /** + * Sets the value of the completed property. + * + */ + public void setCompleted(boolean value) { + this.completed = value; + } + + /** + * Gets the value of the exception property. + * + * @return + * possible object is + * {@link MsoExceptionCategory } + * + */ + public MsoExceptionCategory getException() { + return exception; + } + + /** + * Sets the value of the exception property. + * + * @param value + * allowed object is + * {@link MsoExceptionCategory } + * + */ + public void setException(MsoExceptionCategory value) { + this.exception = value; + } + + /** + * Gets the value of the errorMessage property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the value of the errorMessage property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setErrorMessage(String value) { + this.errorMessage = value; + } + + /** + * Gets the value of the outputs property. + * + * @return + * possible object is + * {@link UpdateVnfNotification.Outputs } + * + */ + public UpdateVnfNotification.Outputs getOutputs() { + return outputs; + } + + /** + * Sets the value of the outputs property. + * + * @param value + * allowed object is + * {@link UpdateVnfNotification.Outputs } + * + */ + public void setOutputs(UpdateVnfNotification.Outputs value) { + this.outputs = value; + } + + /** + * Gets the value of the rollback property. + * + * @return + * possible object is + * {@link VnfRollback } + * + */ + public VnfRollback getRollback() { + return rollback; + } + + /** + * Sets the value of the rollback property. + * + * @param value + * allowed object is + * {@link VnfRollback } + * + */ + public void setRollback(VnfRollback value) { + this.rollback = value; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="entry" maxOccurs="unbounded" minOccurs="0"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "entry" + }) + public static class Outputs { + + protected List<UpdateVnfNotification.Outputs.Entry> entry; + + /** + * Gets the value of the entry property. + * + * <p> + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a <CODE>set</CODE> method for the entry property. + * + * <p> + * For example, to add a new item, do as follows: + * <pre> + * getEntry().add(newItem); + * </pre> + * + * + * <p> + * Objects of the following type(s) are allowed in the list + * {@link UpdateVnfNotification.Outputs.Entry } + * + * + */ + public List<UpdateVnfNotification.Outputs.Entry> getEntry() { + if (entry == null) { + entry = new ArrayList<UpdateVnfNotification.Outputs.Entry>(); + } + return this.entry; + } + + + /** + * <p>Java class for anonymous complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="key" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="value" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "key", + "value" + }) + public static class Entry { + + protected String key; + protected String value; + + /** + * Gets the value of the key property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getKey() { + return key; + } + + /** + * Sets the value of the key property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setKey(String value) { + this.key = value; + } + + /** + * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setValue(String value) { + this.value = value; + } + + } + + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify.java new file mode 100644 index 0000000000..24370b4d79 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify.java @@ -0,0 +1,177 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.Action; +import javax.xml.ws.RequestWrapper; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebService(name = "vnfAdapterNotify", targetNamespace = "http://org.onap.so/vnfNotify") +@XmlSeeAlso({ + ObjectFactory.class +}) +public interface VnfAdapterNotify { + + + /** + * + * @param exception + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "rollbackVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.RollbackVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/rollbackVnfNotificationRequest") + public void rollbackVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage); + + /** + * + * @param exception + * @param outputs + * @param errorMessage + * @param vnfExists + * @param messageId + * @param completed + * @param vnfId + * @param status + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "queryVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.QueryVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/queryVnfNotificationRequest") + public void queryVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "vnfExists", targetNamespace = "") + Boolean vnfExists, + @WebParam(name = "vnfId", targetNamespace = "") + String vnfId, + @WebParam(name = "status", targetNamespace = "") + VnfStatus status, + @WebParam(name = "outputs", targetNamespace = "") + org.onap.so.adapters.vnf.async.client.QueryVnfNotification.Outputs outputs); + + /** + * + * @param exception + * @param outputs + * @param rollback + * @param errorMessage + * @param messageId + * @param completed + * @param vnfId + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "createVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.CreateVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/createVnfNotificationRequest") + public void createVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "vnfId", targetNamespace = "") + String vnfId, + @WebParam(name = "outputs", targetNamespace = "") + org.onap.so.adapters.vnf.async.client.CreateVnfNotification.Outputs outputs, + @WebParam(name = "rollback", targetNamespace = "") + VnfRollback rollback); + + /** + * + * @param exception + * @param outputs + * @param rollback + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "updateVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.UpdateVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/updateVnfNotificationRequest") + public void updateVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage, + @WebParam(name = "outputs", targetNamespace = "") + org.onap.so.adapters.vnf.async.client.UpdateVnfNotification.Outputs outputs, + @WebParam(name = "rollback", targetNamespace = "") + VnfRollback rollback); + + /** + * + * @param exception + * @param errorMessage + * @param messageId + * @param completed + */ + @WebMethod + @Oneway + @RequestWrapper(localName = "deleteVnfNotification", targetNamespace = "http://org.onap.so/vnfNotify", className = "org.onap.so.adapters.vnf.async.client.DeleteVnfNotification") + @Action(input = "http://org.onap.so/notify/adapterNotify/deleteVnfNotificationRequest") + public void deleteVnfNotification( + @WebParam(name = "messageId", targetNamespace = "") + String messageId, + @WebParam(name = "completed", targetNamespace = "") + boolean completed, + @WebParam(name = "exception", targetNamespace = "") + MsoExceptionCategory exception, + @WebParam(name = "errorMessage", targetNamespace = "") + String errorMessage); + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify_Service.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify_Service.java new file mode 100644 index 0000000000..4b140b1b30 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfAdapterNotify_Service.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import java.net.URL; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.WebServiceFeature; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.9-b14002 + * Generated source version: 2.2 + * + */ +@WebServiceClient(name = "vnfAdapterNotify", targetNamespace = "http://org.onap.so/vnfNotify", wsdlLocation = "/VnfAdapterNotify.wsdl") +public class VnfAdapterNotify_Service + extends Service +{ + + private final static URL VNFADAPTERNOTIFY_WSDL_LOCATION; + private final static WebServiceException VNFADAPTERNOTIFY_EXCEPTION; + private final static QName VNFADAPTERNOTIFY_QNAME = new QName("http://org.onap.so/vnfNotify", "vnfAdapterNotify"); + + static { + VNFADAPTERNOTIFY_WSDL_LOCATION = org.onap.so.adapters.vnf.async.client.VnfAdapterNotify_Service.class.getResource("/VnfAdapterNotify.wsdl"); + WebServiceException e = null; + if (VNFADAPTERNOTIFY_WSDL_LOCATION == null) { + e = new WebServiceException("Cannot find '/VnfAdapterNotify.wsdl' wsdl. Place the resource correctly in the classpath."); + } + VNFADAPTERNOTIFY_EXCEPTION = e; + } + + public VnfAdapterNotify_Service() { + super(__getWsdlLocation(), VNFADAPTERNOTIFY_QNAME); + } + + public VnfAdapterNotify_Service(WebServiceFeature... features) { + super(__getWsdlLocation(), VNFADAPTERNOTIFY_QNAME, features); + } + + public VnfAdapterNotify_Service(URL wsdlLocation) { + super(wsdlLocation, VNFADAPTERNOTIFY_QNAME); + } + + public VnfAdapterNotify_Service(URL wsdlLocation, WebServiceFeature... features) { + super(wsdlLocation, VNFADAPTERNOTIFY_QNAME, features); + } + + public VnfAdapterNotify_Service(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public VnfAdapterNotify_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { + super(wsdlLocation, serviceName, features); + } + + /** + * + * @return + * returns VnfAdapterNotify + */ + @WebEndpoint(name = "MsoVnfAdapterAsyncImplPort") + public VnfAdapterNotify getMsoVnfAdapterAsyncImplPort() { + return super.getPort(new QName("http://org.onap.so/vnfNotify", "MsoVnfAdapterAsyncImplPort"), VnfAdapterNotify.class); + } + + /** + * + * @param features + * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values. + * @return + * returns VnfAdapterNotify + */ + @WebEndpoint(name = "MsoVnfAdapterAsyncImplPort") + public VnfAdapterNotify getMsoVnfAdapterAsyncImplPort(WebServiceFeature... features) { + return super.getPort(new QName("http://org.onap.so/vnfNotify", "MsoVnfAdapterAsyncImplPort"), VnfAdapterNotify.class, features); + } + + private static URL __getWsdlLocation() { + if (VNFADAPTERNOTIFY_EXCEPTION!= null) { + throw VNFADAPTERNOTIFY_EXCEPTION; + } + return VNFADAPTERNOTIFY_WSDL_LOCATION; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfRollback.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfRollback.java new file mode 100644 index 0000000000..9ad20738d0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfRollback.java @@ -0,0 +1,198 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for vnfRollback complex type. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * + * <pre> + * <complexType name="vnfRollback"> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence> + * <element name="cloudSiteId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="msoRequest" type="{http://org.onap.so/vnfNotify}msoRequest" minOccurs="0"/> + * <element name="tenantCreated" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="tenantId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="vnfCreated" type="{http://www.w3.org/2001/XMLSchema}boolean"/> + * <element name="vnfId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </pre> + * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "vnfRollback", propOrder = { + "cloudSiteId", + "msoRequest", + "tenantCreated", + "tenantId", + "vnfCreated", + "vnfId" +}) +public class VnfRollback { + + protected String cloudSiteId; + protected MsoRequest msoRequest; + protected boolean tenantCreated; + protected String tenantId; + protected boolean vnfCreated; + protected String vnfId; + + /** + * Gets the value of the cloudSiteId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCloudSiteId() { + return cloudSiteId; + } + + /** + * Sets the value of the cloudSiteId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCloudSiteId(String value) { + this.cloudSiteId = value; + } + + /** + * Gets the value of the msoRequest property. + * + * @return + * possible object is + * {@link MsoRequest } + * + */ + public MsoRequest getMsoRequest() { + return msoRequest; + } + + /** + * Sets the value of the msoRequest property. + * + * @param value + * allowed object is + * {@link MsoRequest } + * + */ + public void setMsoRequest(MsoRequest value) { + this.msoRequest = value; + } + + /** + * Gets the value of the tenantCreated property. + * + */ + public boolean isTenantCreated() { + return tenantCreated; + } + + /** + * Sets the value of the tenantCreated property. + * + */ + public void setTenantCreated(boolean value) { + this.tenantCreated = value; + } + + /** + * Gets the value of the tenantId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTenantId() { + return tenantId; + } + + /** + * Sets the value of the tenantId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTenantId(String value) { + this.tenantId = value; + } + + /** + * Gets the value of the vnfCreated property. + * + */ + public boolean isVnfCreated() { + return vnfCreated; + } + + /** + * Sets the value of the vnfCreated property. + * + */ + public void setVnfCreated(boolean value) { + this.vnfCreated = value; + } + + /** + * Gets the value of the vnfId property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getVnfId() { + return vnfId; + } + + /** + * Sets the value of the vnfId property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setVnfId(String value) { + this.vnfId = value; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfStatus.java new file mode 100644 index 0000000000..1998ae0ce9 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/VnfStatus.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.async.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + * <p>Java class for vnfStatus. + * + * <p>The following schema fragment specifies the expected content contained within this class. + * <p> + * <pre> + * <simpleType name="vnfStatus"> + * <restriction base="{http://www.w3.org/2001/XMLSchema}string"> + * <enumeration value="ACTIVE"/> + * <enumeration value="FAILED"/> + * <enumeration value="NOTFOUND"/> + * <enumeration value="UNKNOWN"/> + * </restriction> + * </simpleType> + * </pre> + * + */ +@XmlType(name = "vnfStatus") +@XmlEnum +public enum VnfStatus { + + ACTIVE, + FAILED, + NOTFOUND, + UNKNOWN; + + public String value() { + return name(); + } + + public static VnfStatus fromValue(String v) { + return valueOf(v); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/package-info.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/package-info.java new file mode 100644 index 0000000000..cc4a2a78ec --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/async/client/package-info.java @@ -0,0 +1,21 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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========================================================= + */ +@javax.xml.bind.annotation.XmlSchema(namespace = "http://org.onap.so/vnfNotify") +package org.onap.so.adapters.vnf.async.client; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfAlreadyExists.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfAlreadyExists.java new file mode 100644 index 0000000000..2a7f33a682 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfAlreadyExists.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.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.onap.so.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://org.onap.so/vnf") +public class VnfAlreadyExists extends VnfException { + + private static final long serialVersionUID = 1L; + + public VnfAlreadyExists (String name, String cloudId, String tenantId, String vnfId) { + super("Resource " + name + " already exists in cloud/tenant " + cloudId + "/" + tenantId + " with ID " + vnfId); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfException.java new file mode 100644 index 0000000000..39f48e64dd --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfException.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.onap.so.openstack.exceptions.MsoException; +import org.onap.so.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.onap.so.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://org.onap.so/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-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfExceptionBean.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfExceptionBean.java new file mode 100644 index 0000000000..011afa72ee --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfExceptionBean.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.exceptions; + + +import java.io.Serializable; + +import org.onap.so.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) { + // Create a default category to prevent null pointer exceptions + this(message, MsoExceptionCategory.INTERNAL); + } + + 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-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfNotFound.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfNotFound.java new file mode 100644 index 0000000000..f3fa39cc2d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/exceptions/VnfNotFound.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.adapters.vnf.exceptions; + + +import javax.xml.ws.WebFault; + +/** + * 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.onap.so.adapters.vnf.exceptions.VnfExceptionBean", targetNamespace="http://org.onap.so/vnf") +public class VnfNotFound extends VnfException { + + private static final long serialVersionUID = 1L; + + public VnfNotFound (String cloudId, String tenantId, String vnfName) { + super("Resource " + vnfName + " not found in cloud/tenant " + cloudId + "/" + tenantId); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduBlueprint.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduBlueprint.java new file mode 100644 index 0000000000..cef0371789 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduBlueprint.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.vdu.utils; + +import java.util.Map; + +/* + * This Java bean class describes the template model of a VDU as distributed + * by SDC to SO. It is composed of one or more templates, one of which must be + * the main template, + * + * The structure of this class corresponds to the format in which the templates + * and associated artifacts are represented in the SO Catalog. + * + * The map keys will be the "path" that is used to reference these artifacts within + * the other templates. This may be relevant to how different VDU plugins package + * the files for delivery to the sub-orchestrator. + * + * In the future, it is possible that pre-packaged blueprints (e.g. complete TOSCA CSARs) + * could be stored in the catalog (and added to this structure). + * + * This bean is passed as an input to instantiateVdu and updateVdu. + */ + +public class VduBlueprint { + String vduModelId; + String mainTemplateName; + Map<String,byte[]> templateFiles; + Map<String,byte[]> attachedFiles; + + public String getVduModelId() { + return vduModelId; + } + + public void setVduModelId(String vduModelId) { + this.vduModelId = vduModelId; + } + + public String getMainTemplateName() { + return mainTemplateName; + } + + public void setMainTemplateName(String mainTemplateName) { + this.mainTemplateName = mainTemplateName; + } + + public Map<String, byte[]> getTemplateFiles() { + return templateFiles; + } + + public void setTemplateFiles(Map<String, byte[]> templateFiles) { + this.templateFiles = templateFiles; + } + + public Map<String, byte[]> getAttachedFiles() { + return attachedFiles; + } + + public void setAttachedFiles(Map<String, byte[]> attachedFiles) { + this.attachedFiles = attachedFiles; + } + + @Override + public String toString() { + return "VduInfo {" + + "id='" + vduModelId + '\'' + + "mainTemplateName='" + mainTemplateName + '\'' + + '}'; + } + +} + diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduInfo.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduInfo.java new file mode 100644 index 0000000000..227d513a0b --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduInfo.java @@ -0,0 +1,130 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.vdu.utils; + +import java.util.Map; +import java.util.HashMap; + +/* + * This Java bean class relays VDU status information in a cloud-agnostic format. + * + * This bean is returned by all implementors of the MsoVduUtils interface operations + * (instantiate, query, delete). + */ + +public class VduInfo { + // Set defaults for everything + private String vduInstanceId = ""; + private String vduInstanceName = ""; + private VduStatus status = VduStatus.NOTFOUND; + private Map<String,Object> outputs = new HashMap<>(); + private Map<String,Object> inputs = new HashMap<>(); + private String lastAction; + private String actionStatus; + private String errorMessage; + + public VduInfo () { + } + + // Add more constructors as appropriate + // + + public VduInfo (String id, Map<String,Object> outputs) { + this.vduInstanceId = id; + if (outputs != null) this.outputs = outputs; + } + + public VduInfo (String id) { + this.vduInstanceId = id; + } + + public VduInfo (String id, VduStatus status) { + this.vduInstanceId = id; + this.status = status; + } + + public String getVnfInstanceId() { + return vduInstanceId; + } + + public void setVnfInstanceId (String id) { + this.vduInstanceId = id; + } + + public String getVnfInstanceName() { + return vduInstanceName; + } + + public void setVnfInstanceName (String name) { + this.vduInstanceName = name; + } + + public VduStatus getStatus() { + return status; + } + + public void setStatus (VduStatus status) { + this.status = status; + } + + public Map<String,Object> getOutputs () { + return outputs; + } + + public void setOutputs (Map<String,Object> outputs) { + this.outputs = outputs; + } + + public Map<String,Object> getInputs () { + return inputs; + } + + public void setInputs (Map<String,Object> inputs) { + this.inputs = inputs; + } + + public String getLastAction() { + return lastAction; + } + + public String getActionStatus() { + return actionStatus; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public String toString() { + return "VduInfo {" + + "id='" + vduInstanceId + '\'' + + "name='" + vduInstanceName + '\'' + + ", inputs='" + inputs + '\'' + + ", outputs='" + outputs + '\'' + + ", lastAction='" + lastAction + '\'' + + ", status='" + status + '\'' + + ", errorMessage='" + errorMessage + '\'' + + '}'; + } + +} + diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduPlugin.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduPlugin.java new file mode 100644 index 0000000000..871260a86d --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduPlugin.java @@ -0,0 +1,248 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.vdu.utils; + +/** + * This interface defines a common API for template-based cloud deployments. + * The methods here should be adaptable for Openstack (Heat), Cloudify (TOSCA), + * Aria (TOSCA), Multi-VIM (TBD), and others (e.g. Azure Resource Manager). + * + * The deployed instances are referred to here as Virtual Deployment Units (VDUs). + * The package of templates that define a give VDU is referred to as its blueprint. + * + * Template-based orchestrators all follow a similar template/blueprint model. + * - One main template that is the top level definition + * - Optional nested templates referenced/included by the main template + * - Optional files attached to the template package, typically containing + * configuration files, install scripts, orchestration scripts, etc. + * + * The main template also defines the required inputs for creating a new instance, + * and output values exposed by successfully deployed instances. Inputs and outputs + * may include simple or complex (JSON) data types. + * + * Each implementation of this interface is expected to understand the MSO CloudConfig + * to obtain the credentials for its sub-orchestrator and the targeted cloud. + * The sub-orchestrator may have different credentials from the cloud (e.g. an Aria + * instance in front of an Openstack cloud) or they may be the same (e.g. Heat) + */ +import java.util.Map; + +import org.onap.so.openstack.exceptions.MsoException; + +public interface VduPlugin { + + /** + * The instantiateVdu interface deploys a new VDU instance from a blueprint package. + * The templates and files in the blueprint may be pre-installed where supported + * (e.g. in Cloudify or Aria), or may be passed in directly (e.g. for Heat). These + * files are expressed as byte arrays, though only text files are expected from ASDC. + * + * For some VIMs, this may be a single command (e.g. Heat -> create stack) or may + * require a series of API calls (e.g. Cloudify -> upload blueprint, create deployment, + * execute install workflow). These details are hidden within the implementation. + * The instantiation should be fully completed before returning. On failures, this + * method is expected to back out the attempt, leaving the cloud in its previous state. + * + * It is expected that parameters have been validated and contain at minimum the + * required parameters for the given template with no extra parameters. + * + * The VDU name supplied by the caller will be globally unique, and identify the artifact + * in A&AI. Inventory is managed by the higher levels invoking this function. + * + * @param cloudSiteId The target cloud for the VDU. Maps to a CloudConfig entry. + * @param tenantId The cloud tenant in which to deploy the VDU. The meaning may differ by + * cloud provider, but every cloud supports some sort of tenant partitioning. + * @param vduInstanceName A unique name for the VDU instance to create + * @param vduBlueprint Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param inputs A map of key/value inputs. Values may be strings, numbers, or JSON objects. + * @param environmentFile A file containing default parameter name/value pairs. This is + * primarily for Heat, though ASDC may create a similar file for other orchestrators. + * @param timeoutMinutes Timeout after which the instantiation attempt will be cancelled + * @param suppressBackout Flag to preserve the deployment on install Failure. Should normally + * be False except in troubleshooting/debug cases + * + * @return A VduInfo object + * @throws MsoException Thrown if the sub-orchestrator API calls fail or if a timeout occurs. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo instantiateVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceName, + VduBlueprint vduBlueprint, + Map <String, ?> inputs, + String environmentFile, + int timeoutMinutes, + boolean suppressBackout) + throws MsoException; + + + /** + * Query a deployed VDU instance. This call will return a VduInfo object, or null + * if the deployment does not exist. + * + * Some VIM orchestrators identify deployment instances by string UUIDs, and others + * by integers. In the latter case, the ID will be passed in as a numeric string. + * + * The returned VduInfo object contains the input and output parameter maps, + * as well as other properties of the deployment (name, status, last action, etc.). + * + * @param cloudSiteId The target cloud to query for the VDU. + * @param tenantId The cloud tenant in which to query + * @param vduInstanceId The ID of the deployment to query + * + * @return A VduInfo object + * @throws MsoException Thrown if the VIM/sub-orchestrator API calls fail. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo queryVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceId) + throws MsoException; + + + /** + * Delete a VDU instance by ID. If the VIM sub-orchestrator supports pre-installation + * of blueprints, the blueprint itself may remain installed. This is recommended, since + * other VDU instances may be using it. + * + * Some VIM orchestrators identify deployment instances by string UUIDs, and others + * by integers. In the latter case, the ID will be passed in as a numeric string. + * + * For some VIMs, deletion may be a single command (e.g. Heat -> delete stack) or a + * series of API calls (e.g. Cloudify -> execute uninstall workflow, delete deployment). + * These details are hidden within the implementation. The deletion should be fully + * completed before returning. + * + * The successful return is a VduInfo object which contains the state of the object just prior + * to deletion, with a status of DELETED. If the deployment was not found, the VduInfo object + * should be empty (with a status of NOTFOUND). There is no rollback from a successful deletion. + * + * A deletion failure will result in an undefined deployment state - the components may + * or may not have been all or partially uninstalled, so the resulting deployment must + * be considered invalid. + * + * @param cloudSiteId The target cloud from which to delete the VDU. + * @param tenantId The cloud tenant in which to delete the VDU. + * @param vduInstanceId The unique id of the deployment to delete. + * @param timeoutMinutes Timeout after which the delete action will be cancelled + * @param keepBlueprintLoaded Flag to also delete the blueprint + * + * @return A VduInfo object, representing the state of the instance just prior to deletion. + * + * @throws MsoException Thrown if the API calls fail or if a timeout occurs. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo deleteVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceId, + int timeoutMinutes, + boolean keepBlueprintLoaded) + throws MsoException; + + + /** + * The updateVdu interface attempts to update a VDU in-place, using either new inputs or + * a new model definition (i.e. updated templates/blueprints). This depends on the + * capabilities of the targeted sub-orchestrator, as not all implementations are expected + * to support this ability. It is primary included initially only for Heat. + * + * It is expected that parameters have been validated and contain at minimum the required + * parameters for the given template with no extra parameters. The VDU instance name cannot + * be updated. + * + * The update should be fully completed before returning. The successful return is a + * VduInfo object containing the updated VDU state. + * + * An update failure will result in an undefined deployment state - the components may + * or may not have been all or partially modified, deleted, recreated, etc. So the resulting + * VDU must be considered invalid. + * + * @param cloudSiteId The target cloud for the VDU. Maps to a CloudConfig entry. + * @param tenantId The cloud tenant in which to deploy the VDU. The meaning may differ by + * cloud provider, but every cloud supports some sort of tenant partitioning. + * @param vduInstanceId The unique ID for the VDU instance to update. + * @param vduBlueprint Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param inputs A map of key/value inputs. Values may be strings, numbers, or JSON objects. + * @param environmentFile A file containing default parameter name/value pairs. This is + * primarily for Heat, though ASDC may create a similar file for other orchestrators. + * @param timeoutMinutes Timeout after which the instantiation attempt will be cancelled + * + * @return A VduInfo object + * @throws MsoException Thrown if the sub-orchestrator API calls fail or if a timeout occurs. + * Various subclasses of MsoException may be thrown. + */ + public VduInfo updateVdu ( + String cloudSiteId, + String tenantId, + String vduInstanceId, + VduBlueprint vduBlueprint, + Map <String, ?> inputs, + String environmentFile, + int timeoutMinutes) + throws MsoException; + + + /** + * Check if a blueprint package has been installed in the sub-orchestrator and available + * for use at a targeted cloud site. If the specific sub-orchestrator does not support + * pre-installation, then those implementations should always return False. + * + * @param cloudSiteId The cloud site where the blueprint is needed + * @param vduModelId Unique ID of the VDU model to query + * + * @throws MsoException Thrown if the API call fails. + */ + public boolean isBlueprintLoaded (String cloudSiteId, String vduModelId) + throws MsoException; + + + /** + * Install a blueprint package to the target sub-orchestrator for a cloud site. + * The blueprints currently must be structured as a single directory with all of the + * required files. One of those files is designated the "main file" for the blueprint. + * Files are provided as byte arrays, though expect only text files will be distributed + * from ASDC and stored by MSO. + * + * @param cloudSiteId The cloud site where the blueprint is needed + * @param vduBlueprint Object containing the collection of templates and files that comprise + * the blueprint for this VDU. + * @param failIfExists Flag to return an error if blueprint already exists + * + * @throws MsoException Thrown if the API call fails. + */ + public void uploadBlueprint (String cloudSiteId, + VduBlueprint vduBlueprint, + boolean failIfExists) + throws MsoException; + + /** + * Indicator that this VIM sub-orchestrator implementation supports independent upload + * of blueprint packages. Each implementation should return a constant value. + * + * @returns True if the sub-orchestrator supports blueprint pre-installation (upload). + */ + public boolean blueprintUploadSupported (); + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduStatus.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduStatus.java new file mode 100644 index 0000000000..1412b02da0 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/vdu/utils/VduStatus.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * 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.onap.so.vdu.utils; + + +/* + * Enum status values to capture the state of a generic (cloud-agnostic) VDU. + */ +public enum VduStatus { + NOTFOUND, + INSTANTIATING, + INSTANTIATED, + DELETING, + DELETED, // Note - only returned in success response to deleteVdu call. + UPDATING, + FAILED, + UNKNOWN +} + |