diff options
Diffstat (limited to 'adapters/mso-network-adapter/src/main')
14 files changed, 4634 insertions, 0 deletions
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/BpelRestClient.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/BpelRestClient.java new file mode 100644 index 0000000000..dcd12d24e7 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/BpelRestClient.java @@ -0,0 +1,304 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import java.io.IOException; +import java.util.Set; +import java.util.TreeSet; + +import javax.xml.bind.DatatypeConverter; + +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.properties.MsoJavaProperties; +import org.openecomp.mso.properties.MsoPropertiesException; +import org.openecomp.mso.properties.MsoPropertiesFactory; + +/** + * This is the class that is used to POST replies from the MSO adapters to the BPEL engine. + * It can be configured via property file, or modified using the member methods. + * The properties to use are: + * org.openecomp.mso.adapters.vnf.bpelauth encrypted authorization string to send to BEPL engine + * org.openecomp.mso.adapters.vnf.sockettimeout socket timeout value + * org.openecomp.mso.adapters.vnf.connecttimeout connect timeout value + * org.openecomp.mso.adapters.vnf.retrycount number of times to retry failed connections + * org.openecomp.mso.adapters.vnf.retryinterval interval (in seconds) between retries + * org.openecomp.mso.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code + * 900 means "connection was not established") + */ +public class BpelRestClient { + public static final String MSO_PROP_NETWORK_ADAPTER = "MSO_PROP_NETWORK_ADAPTER"; + private static final String PROPERTY_DOMAIN = "org.openecomp.mso.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); + + /** 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 = ""; + + try { + MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + MsoJavaProperties jp = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_NETWORK_ADAPTER); + socketTimeout = jp.getIntProperty(SOCKET_TIMEOUT_PROPERTY, DEFAULT_SOCKET_TIMEOUT); + connectTimeout = jp.getIntProperty(CONN_TIMEOUT_PROPERTY, DEFAULT_CONNECT_TIMEOUT); + retryCount = jp.getIntProperty(RETRY_COUNT_PROPERTY, DEFAULT_RETRY_COUNT); + retryInterval = jp.getIntProperty(RETRY_INTERVAL_PROPERTY, DEFAULT_RETRY_INTERVAL); + setRetryList(jp.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST)); + credentials = jp.getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY); + } catch (MsoPropertiesException e) { + String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Unable to get properties", e); + } + } + + public int getSocketTimeout() { + return socketTimeout; + } + + public void setSocketTimeout(int socketTimeout) { + this.socketTimeout = socketTimeout; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getRetryCount() { + return retryCount; + } + + public void setRetryCount(int retryCount) { + if (retryCount < 0) + retryCount = DEFAULT_RETRY_COUNT; + this.retryCount = retryCount; + } + + public int getRetryInterval() { + return retryInterval; + } + + public void setRetryInterval(int retryInterval) { + this.retryInterval = retryInterval; + } + + public String getCredentials() { + return credentials; + } + + public void setCredentials(String credentials) { + this.credentials = credentials; + } + + public String getRetryList() { + if (retryList.size() == 0) + return ""; + String t = retryList.toString(); + return t.substring(1, t.length()-1); + } + + public void setRetryList(String retryList) { + Set<Integer> s = new TreeSet<Integer>(); + for (String t : retryList.split("[, ]")) { + try { + s.add(Integer.parseInt(t)); + } catch (NumberFormatException x) { + // ignore + } + } + this.retryList = s; + } + + public int getLastResponseCode() { + return lastResponseCode; + } + + public String getLastResponse() { + return lastResponse; + } + + /** + * Post a response to the URL of the BPEL engine. As long as the response code is one of those in + * the retryList, the post will be retried up to "retrycount" times with an interval (in seconds) + * of "retryInterval". If retryInterval is negative, then each successive retry interval will be + * double the previous one. + * @param toBpelStr the content (XML or JSON) to post + * @param bpelUrl the URL to post to + * @param isxml true if the content is XML, otherwise assumed to be JSON + * @return true if the post succeeded, false if all retries failed + */ + public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml) { + debug("Sending response to BPEL: " + toBpelStr); + int totalretries = 0; + int retryint = retryInterval; + while (true) { + sendOne(toBpelStr, bpelUrl, isxml); + // Note: really should handle response code 415 by switching between content types if needed + if (!retryList.contains(lastResponseCode)) { + debug("Got response code: " + lastResponseCode + ": returning."); + return true; + } + if (totalretries >= retryCount) { + debug("Retried " + totalretries + " times, giving up."); + LOGGER.error(MessageEnum.RA_SEND_VNF_NOTIF_ERR, "Could not deliver response to BPEL after "+totalretries+" tries: "+toBpelStr, "Camunda", "", MsoLogger.ErrorCode.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) { + // ignore + } + } + } + private void debug(String m) { + LOGGER.debug(m); +// System.err.println(m); + } + private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) { + LOGGER.debug("Sending to BPEL server: "+bpelUrl); + LOGGER.debug("Content is: "+toBpelStr); + + //POST + HttpPost post = new HttpPost(bpelUrl); + if (credentials != null && !credentials.isEmpty()) + post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes())); + + //ContentType + ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON; + post.setEntity(new StringEntity(toBpelStr, ctype)); + + //Timeouts + RequestConfig requestConfig = RequestConfig + .custom() + .setSocketTimeout(socketTimeout * 1000) + .setConnectTimeout(connectTimeout * 1000) + .build(); + post.setConfig(requestConfig); + + //Client 4.3+ + //Execute & GetResponse + try (CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = client.execute(post)) { + if (response != null) { + lastResponseCode = response.getStatusLine().getStatusCode(); + HttpEntity entity = response.getEntity(); + lastResponse = (entity != null) ? EntityUtils.toString(entity) : ""; + } else { + lastResponseCode = 900; + lastResponse = ""; + } + } catch (Exception e) { + String error = "Error sending Bpel notification:" + toBpelStr; + LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, error, "Camunda", "", MsoLogger.ErrorCode.AvailabilityError, "Exception sending Bpel notification", e); + lastResponseCode = 900; + lastResponse = ""; + } + LOGGER.debug("Response code from BPEL server: "+lastResponseCode); + LOGGER.debug("Response body is: "+lastResponse); + } + + public static void main(String[] a) throws MsoPropertiesException { + final String bpelengine = "http://mtmac1.research.att.com:8080/catch.jsp"; + final String propfile = "/tmp/mso.vnf.properties"; + // "/Users/eby/src/mso.rest/mso/packages/mso-config-centralized/mso-po-adapter-config/mso.vnf.properties" + final String xml = + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + + "<updateVolumeGroupResponse><volumeGroupId>1464013300723</volumeGroupId><volumeGroupOutputs>" + + "<entry><key>clyde</key><value>10</value></entry>" + + "<entry><key>wayne</key><value>99</value></entry>" + + "<entry><key>mickey</key><value>7</value></entry>" + + "</volumeGroupOutputs></updateVolumeGroupResponse>"; + + MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + msoPropertiesFactory.initializeMsoProperties (MSO_PROP_NETWORK_ADAPTER, propfile); + + BpelRestClient bc = new BpelRestClient(); + System.out.println(bc.getRetryList()); + System.out.println(bc.getCredentials()); // poAvos:Domain2.0! + + bc.bpelPost(xml, bpelengine, true); + System.out.println("respcode = "+bc.getLastResponseCode()); + System.out.println("resp = "+bc.getLastResponse()); + } +} diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRef.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRef.java new file mode 100644 index 0000000000..6e2644db73 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRef.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.exceptions.MsoAdapterException; + +public class ContrailPolicyRef { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + + @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-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRefSeq.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRefSeq.java new file mode 100644 index 0000000000..b5d750288f --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRefSeq.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import org.codehaus.jackson.annotate.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() { + } + + 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-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnet.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnet.java new file mode 100644 index 0000000000..3df1014a90 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnet.java @@ -0,0 +1,196 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + +import java.util.ArrayList; +import java.util.List; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.ObjectMapper; + +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.Pool; +import org.openecomp.mso.openstack.beans.Subnet; +import static org.openecomp.mso.openstack.utils.MsoCommonUtils.isNullOrEmpty; + +public class ContrailSubnet { + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet") + private ContrailSubnetIp subnet = new ContrailSubnetIp(); + + @JsonProperty("network_ipam_refs_data_ipam_subnets_default_gateway") + private String default_gateway; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_name") + private String subnet_name; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_enable_dhcp") + private Boolean enable_dhcp; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_addr_from_start") + private Boolean addr_from_start = true; + + /** future - leave this commented + private String subnet_uuid; + private String dns_server_address; + private List<String> dns_nameservers; + private String dhcp_option_list; + private String host_routes; + **/ + + @JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools") + private List<ContrailSubnetPool> allocation_pools = new ArrayList <ContrailSubnetPool> (); + + public ContrailSubnet() { + super(); + } + + public String getDefault_gateway() { + return default_gateway; + } + + public void setDefault_gateway(String default_gateway) { + this.default_gateway = default_gateway; + } + + public ContrailSubnetIp getSubnet() { + return subnet; + } + + public void setSubnet(ContrailSubnetIp subnet) { + this.subnet = subnet; + } + + public Boolean isEnable_dhcp() { + return enable_dhcp; + } + + public void setEnable_dhcp(Boolean enable_dhcp) { + this.enable_dhcp = enable_dhcp; + } + + public String getSubnet_name() { + return subnet_name; + } + + public void setSubnet_name(String subnet_name) { + this.subnet_name = subnet_name; + } + + public List<ContrailSubnetPool> getAllocation_pools() { + return allocation_pools; + } + + public void setPools(List<ContrailSubnetPool> allocation_pools) { + this.allocation_pools = allocation_pools; + } + + public Boolean isAddr_from_start() { + return addr_from_start; + } + + public void setAddr_from_start(Boolean addr_from_start) { + this.addr_from_start = addr_from_start; + } + + 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:" + subnet_name; + 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:" + subnet_name; + 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 i_subnet) + { + if (i_subnet != null) + { + if (!isNullOrEmpty(i_subnet.getSubnetName())) + subnet_name = i_subnet.getSubnetName(); + else + subnet_name = i_subnet.getSubnetId(); + enable_dhcp = i_subnet.getEnableDHCP(); + default_gateway = i_subnet.getGatewayIp(); + if (!isNullOrEmpty(i_subnet.getCidr()) ) + { + int idx = i_subnet.getCidr().indexOf("/"); + if (idx != -1) + { + subnet.setIp_prefix(i_subnet.getCidr().substring(0, idx)); + subnet.setIp_prefix_len(i_subnet.getCidr().substring(idx+1)); + } + } + if (i_subnet.getAllocationPools() != null) + { + for (Pool pool : i_subnet.getAllocationPools()) + { + if ( !isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()) ) + { + ContrailSubnetPool csp = new ContrailSubnetPool(); + csp.populateWith(pool); + allocation_pools.add (csp); + } + } + } + } + } + + @Override + public String toString() { + + StringBuilder buf = new StringBuilder (); + for (ContrailSubnetPool pool : allocation_pools) + { + buf.append(pool.toString()); + } + return "ContrailSubnet [subnet=" + subnet.toString() + " default_gateway=" + default_gateway + + " enable_dhcp=" + enable_dhcp + " addr_from_start=" + addr_from_start + " subnet_name=" + subnet_name + " allocation_pools=" + buf + " ]"; + } +} diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetIp.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetIp.java new file mode 100644 index 0000000000..c0a5311fec --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetIp.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import org.codehaus.jackson.annotate.JsonProperty; + +public class ContrailSubnetIp { + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix") + private String ip_prefix; + + @JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix_len") + private String ip_prefix_len; + + public ContrailSubnetIp() { + } + + public String getIp_prefix() { + return ip_prefix; + } + + public void setIp_prefix(String ip_prefix) { + this.ip_prefix = ip_prefix; + } + + public String getIp_prefix_len() { + return ip_prefix_len; + } + + public void setIp_prefix_len(String ip_prefix_len) { + this.ip_prefix_len = ip_prefix_len; + } + + @Override + public String toString() { + return "ContrailSubnetIp [ip_prefix=" + ip_prefix + ", ip_prefix_len=" + ip_prefix_len + "]"; + } + +} diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetPool.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetPool.java new file mode 100644 index 0000000000..5b40ba26a6 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetPool.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import org.openecomp.mso.openstack.beans.Pool; +import org.codehaus.jackson.annotate.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() { + } + + 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-network-adapter/src/main/java/org/openecomp/mso/adapters/network/HealthCheckHandler.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/HealthCheckHandler.java new file mode 100644 index 0000000000..2767baffac --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/HealthCheckHandler.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import javax.ws.rs.GET; +import javax.ws.rs.HEAD; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; + +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.HealthCheckUtils; +import org.openecomp.mso.utils.UUIDChecker; + + +@Path("/") + public class HealthCheckHandler { + + private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA); + private static final String MSO_PROP_NETWORK_ADAPTER = "MSO_PROP_NETWORK_ADAPTER"; + + @HEAD + @GET + @Path("/healthcheck") + @Produces("text/html") + public Response healthcheck (@QueryParam("requestId") String requestId) { + long startTime = System.currentTimeMillis (); + MsoLogger.setServiceName ("Healthcheck"); + UUIDChecker.verifyOldUUID(requestId, msoLogger); + HealthCheckUtils healthCheck = new HealthCheckUtils (); + if (!healthCheck.siteStatusCheck(msoLogger, startTime)) { + return HealthCheckUtils.HEALTH_CHECK_NOK_RESPONSE; + } + + if (!healthCheck.configFileCheck(msoLogger, startTime, MSO_PROP_NETWORK_ADAPTER)) { + return HealthCheckUtils.NOT_STARTED_RESPONSE; + } + + if (!healthCheck.catalogDBCheck (msoLogger, startTime)) { + return HealthCheckUtils.NOT_STARTED_RESPONSE; + } + msoLogger.debug("healthcheck - Successful"); + return HealthCheckUtils.HEALTH_CHECK_RESPONSE; + } + + +} diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapter.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapter.java new file mode 100644 index 0000000000..4960877b8a --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapter.java @@ -0,0 +1,216 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.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.openecomp.mso.adapters.network.exceptions.NetworkException; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.openstack.beans.NetworkRollback; +import org.openecomp.mso.openstack.beans.NetworkStatus; +import org.openecomp.mso.openstack.beans.Subnet; + +@WebService (name="NetworkAdapter", targetNamespace="http://com.att.mso/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="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="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="routeTargets") List<String> 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="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="networkId") @XmlElement(required=true) String networkId, + @WebParam(name="networkName") @XmlElement(required=true) String networkName, + @WebParam(name="routeTargets") List<String> 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<String>> 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="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-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsync.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsync.java new file mode 100644 index 0000000000..e79ba125e2 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsync.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import javax.jws.Oneway; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.bind.annotation.XmlElement; + +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.openstack.beans.Subnet; +import org.openecomp.mso.openstack.beans.NetworkRollback; + +import java.util.List; +/** + * 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://com.att.mso/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="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="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="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-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsyncImpl.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsyncImpl.java new file mode 100644 index 0000000000..75cbc636cc --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsyncImpl.java @@ -0,0 +1,679 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jws.WebService; +import javax.xml.bind.DatatypeConverter; +import javax.xml.namespace.QName; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Holder; +import javax.xml.ws.handler.MessageContext; + +import org.openecomp.mso.adapters.network.async.client.CreateNetworkNotification; +import org.openecomp.mso.adapters.network.async.client.MsoExceptionCategory; +import org.openecomp.mso.adapters.network.async.client.NetworkAdapterNotify; +import org.openecomp.mso.adapters.network.async.client.NetworkAdapterNotify_Service; +import org.openecomp.mso.adapters.network.async.client.QueryNetworkNotification; +import org.openecomp.mso.adapters.network.async.client.UpdateNetworkNotification; +import org.openecomp.mso.adapters.network.exceptions.NetworkException; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoAlarmLogger; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.NetworkRollback; +import org.openecomp.mso.openstack.beans.NetworkStatus; +import org.openecomp.mso.openstack.beans.Subnet; +import org.openecomp.mso.properties.MsoPropertiesFactory; + + +@WebService(serviceName = "NetworkAdapterAsync", endpointInterface = "org.openecomp.mso.adapters.network.MsoNetworkAdapterAsync", targetNamespace = "http://com.att.mso/networkA") +public class MsoNetworkAdapterAsyncImpl implements MsoNetworkAdapterAsync { + + MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory(); + + CloudConfigFactory cloudConfigFactory=new CloudConfigFactory(); + + public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER"; + private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + private static final String BPEL_AUTH_PROP = "org.openecomp.mso.adapters.network.bpelauth"; + private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f"; + /** + * Health Check web method. Does nothing but return to show the adapter is deployed. + */ + @Override + public void healthCheckA () { + LOGGER.debug ("Health check call in 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 networkName, + String physicalNetworkName, + List <Integer> vlans, + Boolean failIfExists, + Boolean backout, + List <Subnet> subnets, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + 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 + MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <String> networkId = new Holder <String> (); + Holder <String> neutronNetworkId = new Holder <String> (); + Holder <NetworkRollback> networkRollback = new Holder <NetworkRollback> (); + Holder <Map <String, String>> subnetIdMap = new Holder <Map <String, String>> (); + + try { + networkAdapter.createNetwork (cloudSiteId, + tenantId, + networkType, + 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 networkId, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <Subnet> subnets, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + 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 + MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <NetworkRollback> networkRollback = new Holder <NetworkRollback> (); + Holder <Map <String, String>> subnetIdMap = new Holder <Map <String, String>> (); + + try { + networkAdapter.updateNetwork (cloudSiteId, + tenantId, + networkType, + 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; + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + 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 + MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <Boolean> networkExists = new Holder <Boolean> (); + Holder <String> networkId = new Holder <String> (); + Holder <String> neutronNetworkId = new Holder <String> (); + Holder <NetworkStatus> status = new Holder <NetworkStatus> (); + Holder <List <Integer>> vlans = new Holder <List <Integer>> (); + Holder <Map <String, String>> subnetIdMap = new Holder <Map <String, String>> (); + + 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.openecomp.mso.adapters.network.async.client.NetworkStatus networkS = org.openecomp.mso.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 networkId, + String messageId, + MsoRequest msoRequest, + String notificationUrl) { + String error; + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + 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 + MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + // Synchronous Web Service Outputs + Holder <Boolean> networkDeleted = new Holder <Boolean> (); + + try { + networkAdapter.deleteNetwork (cloudSiteId, tenantId, networkType, 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); + // Will capture execution time for metrics + long startTime = System.currentTimeMillis (); + // 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 + MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory); + + 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.openecomp.mso.adapters.network.async.client.NetworkRollback copyNrb (Holder <NetworkRollback> hNrb) { + org.openecomp.mso.adapters.network.async.client.NetworkRollback cnrb = new org.openecomp.mso.adapters.network.async.client.NetworkRollback (); + + if (hNrb != null && hNrb.value != null) { + org.openecomp.mso.adapters.network.async.client.MsoRequest cmr = new org.openecomp.mso.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://com.att.mso/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); + } + + LOGGER.debug ("Notification Endpoint URL: " + epUrl.toExternalForm ()); + + bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY, epUrl.toExternalForm ()); + + // authentication + try { + Map <String, Object> reqCtx = bp.getRequestContext (); + Map <String, List <String>> headers = new HashMap <String, List <String>> (); + + String userCredentials = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_NETWORK_ADAPTER).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; + } + + 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 <String, String> (); + 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 <String, String> (); + sMap = hMap.value; + UpdateNetworkNotification.SubnetIdMap.Entry entry = new UpdateNetworkNotification.SubnetIdMap.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + 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 <String, String> (); + sMap = hMap.value; + QueryNetworkNotification.SubnetIdMap.Entry entry = new QueryNetworkNotification.SubnetIdMap.Entry (); + + for (String key : sMap.keySet ()) { + entry.setKey (key); + entry.setValue (sMap.get (key)); + subnetIdMap.getEntry ().add (entry); + } + } + return subnetIdMap; + } +} diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterImpl.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterImpl.java new file mode 100644 index 0000000000..97624dae30 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterImpl.java @@ -0,0 +1,2052 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jws.WebParam; +import javax.jws.WebService; +import javax.xml.ws.Holder; + +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.map.ObjectMapper; + +import org.openecomp.mso.adapters.network.exceptions.NetworkException; +import org.openecomp.mso.cloud.CloudConfig; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.cloud.CloudSite; +import org.openecomp.mso.db.catalog.CatalogDatabase; +import org.openecomp.mso.db.catalog.beans.HeatTemplate; +import org.openecomp.mso.db.catalog.beans.NetworkResource; +import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoAlarmLogger; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.HeatStatus; +import org.openecomp.mso.openstack.beans.NetworkInfo; +import org.openecomp.mso.openstack.beans.NetworkRollback; +import org.openecomp.mso.openstack.beans.NetworkStatus; +import org.openecomp.mso.openstack.beans.Pool; +import org.openecomp.mso.openstack.beans.StackInfo; +import org.openecomp.mso.openstack.beans.Subnet; +import org.openecomp.mso.openstack.exceptions.MsoAdapterException; +import org.openecomp.mso.openstack.exceptions.MsoException; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; +import org.openecomp.mso.openstack.utils.MsoCommonUtils; +import org.openecomp.mso.openstack.utils.MsoHeatUtils; +import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate; +import org.openecomp.mso.openstack.utils.MsoNeutronUtils; +import org.openecomp.mso.openstack.utils.MsoNeutronUtils.NetworkType; +import org.openecomp.mso.properties.MsoPropertiesException; +import org.openecomp.mso.properties.MsoPropertiesFactory; + +import static org.openecomp.mso.openstack.utils.MsoCommonUtils.isNullOrEmpty; + +@WebService(serviceName = "NetworkAdapter", endpointInterface = "org.openecomp.mso.adapters.network.MsoNetworkAdapter", targetNamespace = "http://com.att.mso/network") +public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { + + MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory(); + + CloudConfigFactory cloudConfigFactory=new CloudConfigFactory(); + + private static final String AIC3_NW_PROPERTY= "org.openecomp.mso.adapters.network.aic3nw"; + private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork"; + public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER"; + 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 MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger (); + protected CloudConfig cloudConfig; + + /** + * 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() { + } + + /** + * This constructor MUST be used if this class if called with the new operator. + * @param msoPropFactory + + */ + public MsoNetworkAdapterImpl(MsoPropertiesFactory msoPropFactory,CloudConfigFactory cloudConfigFact) { + this.msoPropertiesFactory = msoPropFactory; + this.cloudConfigFactory=cloudConfigFact; + cloudConfig = cloudConfigFactory.getCloudConfig (); + } + + @Override + public void createNetwork (String cloudSiteId, + String tenantId, + String networkType, + 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 <String> (); + createNetwork (cloudSiteId, + tenantId, + networkType, + 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 networkName, + List <String> 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, + 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 networkName, + String physicalNetworkName, + List <Integer> vlans, + List <String> 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); + + // 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. + + cloudConfig = cloudConfigFactory.getCloudConfig (); + CloudSite cloudSite = cloudConfig.getCloudSite (cloudSiteId); + if (cloudSite == null) + { + 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); + } + + try (CatalogDatabase db = getCatalogDb()) { + NetworkResource networkResource = networkCheck (db, + startTime, + networkType, + networkName, + physicalNetworkName, + vlans, + routeTargets, + cloudSite); + String mode = networkResource.getOrchestrationMode (); + NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ()); + + if (NEUTRON_MODE.equals (mode)) { + + // Use an MsoNeutronUtils for all neutron commands + MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory); + + // 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); + String error = "Create Network (neutron): query network " + networkName + + " in " + + cloudSiteId + + "/" + + tenantId + + ": " + + me; + 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)) { + + // Use an MsoHeatUtils for all Heat commands + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ()); + 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; + try { + aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER).getProperty(AIC3_NW_PROPERTY, AIC3_NW); + } catch (MsoPropertiesException e) { + String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Exception - Unable to get properties", e); + } + + 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 <String, String> (); + 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; + String msg = "Found Existing network stack, status=" + heatStack.getStatus () + " for Heat mode"; + 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. + long createStackStartTime = System.currentTimeMillis (); + 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 <String, String> (); + 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 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, + networkId, + networkName, + physicalNetworkName, + vlans, + null, + null, + null, + subnets, + null, + null, + msoRequest, + subnetIdMap, + rollback); + + } + + @Override + public void updateNetworkContrail (String cloudSiteId, + String tenantId, + String networkType, + String networkId, + String networkName, + List <String> 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, + 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 networkId, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <String> 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); + + cloudConfig = cloudConfigFactory.getCloudConfig (); + CloudSite cloudSite = cloudConfig.getCloudSite (cloudSiteId); + if (cloudSite == null) { + 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); + } + + try(CatalogDatabase db = getCatalogDb()) { + NetworkResource networkResource = networkCheck (db, + startTime, + networkType, + networkName, + physicalNetworkName, + vlans, + routeTargets, + cloudSite); + String mode = networkResource.getOrchestrationMode (); + NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ()); + + // Use an MsoNeutronUtils for all Neutron commands + MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory); + + 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)) { + + // Use an MsoHeatUtils for all Heat commands + MsoHeatUtilsWithUpdate heat = new MsoHeatUtilsWithUpdate (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + // 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 <Integer> (); + 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 = db.getHeatTemplate (networkResource.getTemplateId ()); + 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; + try { + aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER).getProperty(AIC3_NW_PROPERTY, AIC3_NW); + } catch (MsoPropertiesException e) { + String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER; + LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Unable to get properties", e); + } + 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 = heat.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 <String, String> (); + 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 ()); + networkRollback.setNeutronNetworkId ((String) outputs.get (NETWORK_ID)); + 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 (CatalogDatabase db, + long startTime, + String networkType, + String networkName, + String physicalNetworkName, + List <Integer> vlans, + List <String> routeTargets, + CloudSite cloudSite) throws NetworkException { + // Retrieve the Network Resource definition + NetworkResource networkResource = db.getNetworkResource (networkType); + if (networkResource == null) { + String error = "CreateNetwork: Unknown Network Type: " + networkType; + LOGGER.error (MessageEnum.RA_UNKOWN_PARAM, "Network Type", networkType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "CreateNetwork: Unknown Network Type"); + + 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.getAic_version()); + 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:" + cloudSite.getId() + + " with AIC_Version:" + cloudSite.getAic_version()); + } + else + { + String error = "Network Type:" + networkType + + " Version_Min:" + networkResource.getAicVersionMin() + + " Version_Max:" + networkResource.getAicVersionMax() + + " not supported on Cloud:" + cloudSite.getId() + + " with AIC_Version:" + cloudSite.getAic_version(); + 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 <String>> 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 <String>> 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 (isNullOrEmpty (cloudSiteId) + || isNullOrEmpty(tenantId) + || 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); + } + + cloudConfig = cloudConfigFactory.getCloudConfig (); + CloudSite cloudSite = cloudConfig.getCloudSite (cloudSiteId); + if (cloudSite == null) + { + 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 + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER,msoPropertiesFactory,cloudConfigFactory); + MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory); + + String mode = null; + String neutronId = null; + // 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 <String, String> (); + 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 <Integer> (); + + 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 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 (); + + try (CatalogDatabase db = getCatalogDb()) { + if (isNullOrEmpty (cloudSiteId) + || isNullOrEmpty(tenantId) + || 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 = db.getNetworkResource (networkType); + if (networkResource == null) { + String error = "Unknown Network Type: " + networkType; + LOGGER.error (MessageEnum.RA_UNKOWN_PARAM, "Network Type", networkType, "Openstack", "", MsoLogger.ErrorCode.DataError, "Unknown Network Type"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ()); + + String mode = networkResource.getOrchestrationMode (); + + if (NEUTRON_MODE.equals (mode)) { + + // Use MsoNeutronUtils for all NEUTRON commands + MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory); + 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 if ("HEAT".equals (mode)) { + long deleteStackStarttime = System.currentTimeMillis (); + // Use MsoHeatUtils for all HEAT commands + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + + 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; + } + + public CatalogDatabase getCatalogDb() { + return new CatalogDatabase(); + } + + /** + * 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 (); + + LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId); + + // rollback may be null (e.g. if network already existed when Create was called) + // Get a handle to the Catalog Database + + try (CatalogDatabase db = getCatalogDb()){ + + // Retrieve the Network Resource definition + NetworkResource networkResource = db.getNetworkResource (networkType); + if (networkResource == null) { + String error = "Rollback Network: Unknown Network Type: " + networkType; + LOGGER.error (MessageEnum.RA_UNKOWN_PARAM, "Network Type", networkType, "Openstack", "", MsoLogger.ErrorCode.DataError, "Rollback Network: Unknown Network Type"); + LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error); + throw new NetworkException (error, MsoExceptionCategory.USERDATA); + } + LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ()); + + String 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 + MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory); + 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 if ("HEAT".equals (mode)) { + // Use MsoHeatUtils for all HEAT commands + MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory); + 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 <String> routeTargets) { + String sep = ""; + StringBuilder missing = new StringBuilder (); + if (isNullOrEmpty(networkName)) { + missing.append ("networkName"); + sep = ","; + } + + if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) { + if (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 <String> routeTargets, + String shared, + String external, + boolean aic3template) { + // Build the common set of HEAT template parameters + Map <String, Object> stackParams = new HashMap <String, Object> (); + 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 && !routeTargets.isEmpty()) { + StringBuilder buf = new StringBuilder (); + String sep = ""; + for (String rt : routeTargets) { + if (!isNullOrEmpty(rt)) + { + if (aic3template) + buf.append (sep).append ("target:" + rt.toString ()); + else + buf.append (sep).append (rt.toString ()); + + sep = ","; + } + } + String csl = buf.toString (); + + stackParams.put ("route_targets", csl); + } + if (isNullOrEmpty(shared)) { + stackParams.put ("shared", "False"); + } else { + stackParams.put ("shared", shared); + } + if (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 <ContrailPolicyRef> (); + int index = 1; + for (String pf : pFqdns) { + if (!isNullOrEmpty(pf)) + { + ContrailPolicyRef pr = new ContrailPolicyRef(); + pr.populate(String.valueOf(index), "0"); + 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 (!isNullOrEmpty(pf)) + { + buf.append (sep).append (pf.toString ()); + 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 (!isNullOrEmpty(rtf)) + { + buf.append (sep).append (rtf.toString ()); + 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 <ContrailSubnet> (); + for (Subnet subnet : subnets) { + ContrailSubnet cs = new ContrailSubnet(); + LOGGER.debug("Input Subnet:" + subnet.toString()); + cs.populateWith(subnet); + 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 (!isNullOrEmpty(pool.getStart()) && !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 <String, String> (); + + 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").getTextValue(); + String uuid = sNode.path("subnet_uuid").getTextValue(); + String aaiId = name; // default + // try to find aaiId for name in input subnetList + if (subnets != null) + { + for (Subnet subnet : subnets) + { + if ( subnet != null && !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-network-adapter/src/main/java/org/openecomp/mso/adapters/network/NetworkAdapterRest.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/NetworkAdapterRest.java new file mode 100644 index 0000000000..c813534212 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/NetworkAdapterRest.java @@ -0,0 +1,595 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network; + + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.GenericEntity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.xml.ws.Holder; + +import org.apache.http.HttpStatus; + +import org.openecomp.mso.adapters.network.exceptions.NetworkException; +import org.openecomp.mso.adapters.nwrest.ContrailNetwork; +import org.openecomp.mso.adapters.nwrest.CreateNetworkError; +import org.openecomp.mso.adapters.nwrest.CreateNetworkRequest; +import org.openecomp.mso.adapters.nwrest.CreateNetworkResponse; +import org.openecomp.mso.adapters.nwrest.DeleteNetworkError; +import org.openecomp.mso.adapters.nwrest.DeleteNetworkRequest; +import org.openecomp.mso.adapters.nwrest.DeleteNetworkResponse; +import org.openecomp.mso.adapters.nwrest.ProviderVlanNetwork; +import org.openecomp.mso.adapters.nwrest.QueryNetworkError; +import org.openecomp.mso.adapters.nwrest.QueryNetworkResponse; +import org.openecomp.mso.adapters.nwrest.RollbackNetworkError; +import org.openecomp.mso.adapters.nwrest.RollbackNetworkRequest; +import org.openecomp.mso.adapters.nwrest.RollbackNetworkResponse; +import org.openecomp.mso.adapters.nwrest.UpdateNetworkError; +import org.openecomp.mso.adapters.nwrest.UpdateNetworkRequest; +import org.openecomp.mso.adapters.nwrest.UpdateNetworkResponse; +import org.openecomp.mso.cloud.CloudConfigFactory; +import org.openecomp.mso.entity.MsoRequest; +import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.openstack.beans.NetworkRollback; +import org.openecomp.mso.openstack.beans.NetworkStatus; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; +import org.openecomp.mso.properties.MsoPropertiesFactory; + +@Path("/v1/networks") +public class NetworkAdapterRest { + private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); + private static final String TESTING_KEYWORD = "___TESTING___"; + private final CloudConfigFactory cloudConfigFactory = new CloudConfigFactory(); + private final MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); + private final MsoNetworkAdapterImpl adapter = new MsoNetworkAdapterImpl(msoPropertiesFactory, cloudConfigFactory); + + @POST + @Path("") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response createNetwork(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<String>(); + Holder<String> neutronNetworkId = new Holder<String>(); + Holder<String> networkFqdn = new Holder<String>(); + Holder<Map<String, String>> subnetIdMap = new Holder<Map<String, String>>(); + Holder<NetworkRollback> rollback = new Holder<NetworkRollback>(); + + 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.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.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) { + eresp = new CreateNetworkError( + e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug ("CreateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @DELETE + @Path("{aaiNetworkId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response deleteNetwork( + @PathParam("aaiNetworkId") String aaiNetworkId, + 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<Boolean>(); + if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { + networkDeleted.value = true; + } else { + adapter.deleteNetwork( + req.getCloudSiteId(), + req.getTenantId(), + req.getNetworkType(), + req.getNetworkStackId(), + req.getMsoRequest(), + networkDeleted); + } + response = new DeleteNetworkResponse(req.getNetworkId(), networkDeleted.value, req.getMessageId()); + } catch (NetworkException 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 = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("DeleteNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @GET + @Path("{aaiNetworkId}") + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response queryNetwork( + @QueryParam("cloudSiteId") String cloudSiteId, + @QueryParam("tenantId") String tenantId, + @QueryParam("networkStackId") String networkStackId, + @QueryParam("skipAAI") String skipAAI, + @QueryParam("msoRequest.requestId") String requestId, + @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, + @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<Boolean>(); + Holder<String> networkId = new Holder<String>(); + Holder<String> neutronNetworkId = new Holder<String>(); + Holder<NetworkStatus> status = new Holder<NetworkStatus>(); + Holder<List<String>> routeTargets = new Holder<List<String>>(); + Holder<Map<String, String>> subnetIdMap = new Holder<Map<String, String>>(); + + 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 }) + public Response rollbackNetwork( + 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) { + eresp = new RollbackNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("RollbackNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + @PUT + @Path("{aaiNetworkId}") + @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + public Response updateNetwork( + @PathParam("aaiNetworkId") String aaiNetworkId, + 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<Map<String, String>>(); + Holder<NetworkRollback> rollback = new Holder<NetworkRollback> (); + + 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.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.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) { + eresp = new UpdateNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); + } + if (!req.isSynchronous()) { + // This is asynch, so POST response back to caller + BpelRestClient bpelClient = new BpelRestClient(); + bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); + } + LOGGER.debug("UpdateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); + } + } + + public static Map<String, String> testMap() { + Map<String, String> m = new HashMap<String, String>(); + m.put("mickey", "7"); + m.put("clyde", "10"); + m.put("wayne", "99"); + return m; + } +} diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkException.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkException.java new file mode 100644 index 0000000000..0fd4d02933 --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkException.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network.exceptions; + + + +import javax.xml.ws.WebFault; + +import org.openecomp.mso.adapters.network.exceptions.NetworkExceptionBean; +import org.openecomp.mso.openstack.exceptions.MsoException; +import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; + +/** + * This class simply extends Exception (without addition additional functionality) + * to provide an identifier for Network related exceptions on create, delete, query. + * + * + */ +@WebFault (name="NetworkException", faultBean="org.openecomp.mso.adapters.network.exceptions.NetworkExceptionBean", targetNamespace="http://com.att.mso/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-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkExceptionBean.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkExceptionBean.java new file mode 100644 index 0000000000..af4e0e386e --- /dev/null +++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkExceptionBean.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - MSO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.mso.adapters.network.exceptions; + + +import java.io.Serializable; + +import org.openecomp.mso.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; + } +} |