/******************************************************************************* * ============LICENSE_START================================================== * * org.onap.dmaap * * =========================================================================== * * Copyright © 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==================================================== * * * * ECOMP is a trademark and service mark of AT&T Intellectual Property. * * ******************************************************************************/ package org.onap.dmaap.datarouter.provisioning; import java.io.IOException; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.json.JSONException; import org.json.JSONObject; import org.onap.dmaap.datarouter.provisioning.beans.Deleteable; import org.onap.dmaap.datarouter.provisioning.beans.EgressRoute; import org.onap.dmaap.datarouter.provisioning.beans.EventLogRecord; import org.onap.dmaap.datarouter.provisioning.beans.IngressRoute; import org.onap.dmaap.datarouter.provisioning.beans.Insertable; import org.onap.dmaap.datarouter.provisioning.beans.NetworkRoute; import org.onap.dmaap.datarouter.provisioning.beans.NodeClass; import static org.onap.dmaap.datarouter.provisioning.utils.HttpServletUtils.sendResponseError; /** *

* This servlet handles requests to URLs under /internal/route/ on the provisioning server. * This part of the URL tree is used to manipulate the Data Router routing tables. * These include: *

*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
URL Path Summary 
URL PathMethodPurpose
/internal/route/GETused to GET a full JSON copy of all three routing tables.
/internal/route/ingress/GETused to GET a full JSON copy of the ingress routing table (IRT).
POSTused to create a new entry in the ingress routing table (IRT).
/internal/route/egress/GETused to GET a full JSON copy of the egress routing table (ERT).
POSTused to create a new entry in the egress routing table (ERT).
/internal/route/network/GETused to GET a full JSON copy of the network routing table (NRT).
POSTused to create a new entry in the network routing table (NRT).
/internal/route/ingress/<feed>/<user>/<subnet>DELETEused to DELETE the ingress route corresponding to feed, user and subnet. * The / in the subnet specified should be replaced with a !, since / cannot be used in a URL.
/internal/route/ingress/<seq>DELETEused to DELETE all ingress routes with the matching seq sequence number.
/internal/route/egress/<sub>DELETEused to DELETE the egress route the matching sub subscriber number.
/internal/route/network/<fromnode>/<tonode>DELETEused to DELETE the network route corresponding to fromnode * and tonode.
*

* Authorization to use these URLs is a little different than for other URLs on the provisioning server. * For the most part, the IP address that the request comes from should be either: *

*
    *
  1. an IP address of a provisioning server, or
  2. *
  3. the IP address of a node, or
  4. *
  5. an IP address from the "special subnet" which is configured with * the PROV_SPECIAL_SUBNET parameter. *
*

* All DELETE/GET/POST requests made to this servlet on the standby server are proxied to the * active server (using the {@link ProxyServlet}) if it is up and reachable. *

* * @author Robert Eby * @version $Id$ */ @SuppressWarnings("serial") public class RouteServlet extends ProxyServlet { /** * DELETE route table entries by deleting part of the route table tree. */ @Override public void doDelete(HttpServletRequest req, HttpServletResponse resp) { EventLogRecord elr = new EventLogRecord(req); if (!isAuthorizedForInternal(req)) { elr.setMessage("Unauthorized."); elr.setResult(HttpServletResponse.SC_FORBIDDEN); eventlogger.info(elr); sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, "Unauthorized.", eventlogger); return; } if (isProxyOK(req) && isProxyServer()) { try { super.doDelete(req, resp); } catch (IOException ioe) { eventlogger.error("IOException" + ioe.getMessage()); } return; } String path = req.getPathInfo(); String[] parts = path.substring(1).split("/"); Deleteable[] d = null; if (parts[0].equals("ingress")) { if (parts.length == 4) { // /internal/route/ingress/// try { int feedid = Integer.parseInt(parts[1]); IngressRoute er = IngressRoute.getIngressRoute(feedid, parts[2], parts[3].replaceAll("!", "/")); if (er == null) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "The specified ingress route does not exist.", eventlogger); return; } d = new Deleteable[] { er }; } catch (NumberFormatException e) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Invalid feed ID in 'delete ingress' command.", eventlogger); return; } } else if (parts.length == 2) { // /internal/route/ingress/ try { int seq = Integer.parseInt(parts[1]); Set set = IngressRoute.getIngressRoutesForSeq(seq); d = set.toArray(new Deleteable[0]); } catch (NumberFormatException e) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Invalid sequence number in 'delete ingress' command.", eventlogger); return; } } else { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Invalid number of arguments in 'delete ingress' command.", eventlogger); return; } } else if (parts[0].equals("egress")) { if (parts.length == 2) { // /internal/route/egress/ try { int subid = Integer.parseInt(parts[1]); EgressRoute er = EgressRoute.getEgressRoute(subid); if (er == null) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "The specified egress route does not exist.", eventlogger); return; } d = new Deleteable[] { er }; } catch (NumberFormatException e) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Invalid sub ID in 'delete egress' command.", eventlogger); return; } } else { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Invalid number of arguments in 'delete egress' command.", eventlogger); return; } } else if (parts[0].equals("network")) { if (parts.length == 3) { // /internal/route/network// try {// NetworkRoute nr = new NetworkRoute( NodeClass.normalizeNodename(parts[1]), NodeClass.normalizeNodename(parts[2]) ); d = new Deleteable[] { nr }; } catch (IllegalArgumentException e) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "The specified network route does not exist.", eventlogger); return; } } else { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Invalid number of arguments in 'delete network' command.", eventlogger); return; } } if (d == null) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Bad URL.", eventlogger); return; } boolean rv = true; for (Deleteable dd : d) { rv &= doDelete(dd); } if (rv) { elr.setResult(HttpServletResponse.SC_OK); eventlogger.info(elr); resp.setStatus(HttpServletResponse.SC_OK); provisioningDataChanged(); provisioningParametersChanged(); } else { // Something went wrong with the DELETE elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); eventlogger.info(elr); sendResponseError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG, eventlogger); } } /** * GET route table entries from the route table tree specified by the URL path. */ @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) { EventLogRecord elr = new EventLogRecord(req); if (!isAuthorizedForInternal(req)) { elr.setMessage("Unauthorized."); elr.setResult(HttpServletResponse.SC_FORBIDDEN); eventlogger.info(elr); sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, "Unauthorized.", eventlogger); return; } if (isProxyOK(req) && isProxyServer()) { try { super.doGet(req, resp); } catch (IOException ioe) { eventlogger.error("IOException" + ioe.getMessage()); } return; } String path = req.getPathInfo(); if (!path.endsWith("/")) path += "/"; if (!path.equals("/") && !path.equals("/ingress/") && !path.equals("/egress/") && !path.equals("/network/")) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Bad URL.", eventlogger); return; } StringBuilder sb = new StringBuilder("{\n"); String px2 = ""; if (path.equals("/") || path.equals("/ingress/")) { String pfx = "\n"; sb.append("\"ingress\": ["); for (IngressRoute in : IngressRoute.getAllIngressRoutes()) { sb.append(pfx); sb.append(in.asJSONObject().toString()); pfx = ",\n"; } sb.append("\n]"); px2 = ",\n"; } if (path.equals("/") || path.equals("/egress/")) { String pfx = "\n"; sb.append(px2); sb.append("\"egress\": {"); for (EgressRoute eg : EgressRoute.getAllEgressRoutes()) { JSONObject jx = eg.asJSONObject(); for (String key : jx.keySet()) { sb.append(pfx); sb.append(" \"").append(key).append("\": "); try { sb.append("\"").append(jx.getString(key)).append("\""); } catch (JSONException je) { eventlogger.error("JSONException" + je.getMessage()); } pfx = ",\n"; } } sb.append("\n}"); px2 = ",\n"; } if (path.equals("/") || path.equals("/network/")) { String pfx = "\n"; sb.append(px2); sb.append("\"routing\": ["); for (NetworkRoute ne : NetworkRoute.getAllNetworkRoutes()) { sb.append(pfx); sb.append(ne.asJSONObject().toString()); pfx = ",\n"; } sb.append("\n]"); } sb.append("}\n"); resp.setStatus(HttpServletResponse.SC_OK); resp.setContentType("application/json"); try { resp.getOutputStream().print(sb.toString()); } catch (IOException ioe) { eventlogger.error("IOException" + ioe.getMessage()); } } /** * PUT on </internal/route/*> -- not supported. */ @Override public void doPut(HttpServletRequest req, HttpServletResponse resp) { EventLogRecord elr = new EventLogRecord(req); if (!isAuthorizedForInternal(req)) { elr.setMessage("Unauthorized."); elr.setResult(HttpServletResponse.SC_FORBIDDEN); eventlogger.info(elr); sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, "Unauthorized.", eventlogger); return; } sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Bad URL.", eventlogger); } /** * POST - modify existing route table entries in the route table tree specified by the URL path. */ @Override public void doPost(HttpServletRequest req, HttpServletResponse resp) { EventLogRecord elr = new EventLogRecord(req); if (!isAuthorizedForInternal(req)) { elr.setMessage("Unauthorized."); elr.setResult(HttpServletResponse.SC_FORBIDDEN); eventlogger.info(elr); sendResponseError(resp, HttpServletResponse.SC_FORBIDDEN, "Unauthorized.", eventlogger); return; } if (isProxyOK(req) && isProxyServer()) { try { super.doPost(req, resp); } catch (IOException ioe) { intlogger.error("IOException" + ioe.getMessage()); } return; } String path = req.getPathInfo(); Insertable[] ins = null; if (path.startsWith("/ingress/")) { // /internal/route/ingress/?feed=%s&user=%s&subnet=%s&nodepatt=%s try { // Although it probably doesn't make sense, you can install two identical routes in the IRT int feedid = Integer.parseInt(req.getParameter("feed")); String user = req.getParameter("user"); if (user == null) user = "-"; String subnet = req.getParameter("subnet"); if (subnet == null) subnet = "-"; String nodepatt = req.getParameter("nodepatt"); String t = req.getParameter("seq"); int seq = (t != null) ? Integer.parseInt(t) : (IngressRoute.getMaxSequence() + 100); ins = new Insertable[] { new IngressRoute(seq, feedid, user, subnet, NodeClass.lookupNodeNames(nodepatt)) }; } catch (Exception e) { intlogger.info(e); sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, "Invalid arguments in 'add ingress' command.", intlogger); return; } } else if (path.startsWith("/egress/")) { // /internal/route/egress/?sub=%s&node=%s try { int subid = Integer.parseInt(req.getParameter("sub")); EgressRoute er = EgressRoute.getEgressRoute(subid); if (er != null) { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, "An egress route already exists for that subscriber.", intlogger); return; } String node = NodeClass.normalizeNodename(req.getParameter("node")); ins = new Insertable[] { new EgressRoute(subid, node) }; } catch (Exception e) { intlogger.info(e); sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, "Invalid arguments in 'add egress' command.", intlogger); return; } } else if (path.startsWith("/network/")) { // /internal/route/network/?from=%s&to=%s&via=%s try { String nfrom = req.getParameter("from"); String nto = req.getParameter("to"); String nvia = req.getParameter("via"); if (nfrom == null || nto == null || nvia == null) { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, "Missing arguments in 'add network' command.", intlogger); return; } nfrom = NodeClass.normalizeNodename(nfrom); nto = NodeClass.normalizeNodename(nto); nvia = NodeClass.normalizeNodename(nvia); NetworkRoute nr = new NetworkRoute(nfrom, nto, nvia); for (NetworkRoute route : NetworkRoute.getAllNetworkRoutes()) { if (route.getFromnode() == nr.getFromnode() && route.getTonode() == nr.getTonode()) { sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, "Network route table already contains a route for " + nfrom + " and " + nto, intlogger); return; } } ins = new Insertable[] { nr }; } catch (IllegalArgumentException e) { intlogger.info(e); sendResponseError(resp, HttpServletResponse.SC_BAD_REQUEST, "Invalid arguments in 'add network' command.", intlogger); return; } } if (ins == null) { sendResponseError(resp, HttpServletResponse.SC_NOT_FOUND, "Bad URL.", intlogger); return; } boolean rv = true; for (Insertable dd : ins) { rv &= doInsert(dd); } if (rv) { elr.setResult(HttpServletResponse.SC_OK); eventlogger.info(elr); resp.setStatus(HttpServletResponse.SC_OK); provisioningDataChanged(); provisioningParametersChanged(); } else { // Something went wrong with the INSERT elr.setResult(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); eventlogger.info(elr); sendResponseError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, DB_PROBLEM_MSG, intlogger); } } }