+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.forwarding.staticrouting.northbound;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+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.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.ContextResolver;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.forwarding.staticrouting.IForwardingStaticRouting;
+import org.opendaylight.controller.forwarding.staticrouting.StaticRouteConfig;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
+import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.query.QueryContext;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.sal.utils.Status;
+
+/**
+ * <p>Static Routing Northbound API allows for the management of the static
+ * routes.</p>
+ * </br>
+ * An example request/response for retrieving the static routes may look like this: </br>
+ * <pre>
+ * GET http://localhost:8080/controller/nb/v2/staticroute/default HTTP/1.1
+ * Accept: application/json
+ *
+ * HTTP/1.1 200 OK
+ * Content-Type: application/json
+ *
+ * { "staticRoute":[
+ * "name":"route-1",
+ * "prefix":"10.10.1.0/24",
+ * "nextHop":"1.1.1.1"
+ * ]
+ * }
+ *
+ * </pre>
+ *
+ * <br><br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ */
+@Path("/")
+public class StaticRoutingNorthbound {
+
+ private String username;
+ private QueryContext queryContext;
+
+ @Context
+ public void setQueryContext(ContextResolver<QueryContext> queryCtxResolver) {
+ if (queryCtxResolver != null) {
+ queryContext = queryCtxResolver.getContext(QueryContext.class);
+ }
+ }
+
+ @Context
+ public void setSecurityContext(SecurityContext context) {
+ if (context != null && context.getUserPrincipal() != null) username = context.getUserPrincipal().getName();
+ }
+ protected String getUserName() {
+ return username;
+ }
+
+
+
+ private List<StaticRoute> getStaticRoutesInternal(String containerName) {
+
+ IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
+ .getInstance(IForwardingStaticRouting.class, containerName,
+ this);
+
+ if (staticRouting == null) {
+ throw new ResourceNotFoundException(RestMessages.NOCONTAINER
+ .toString());
+ }
+
+ List<StaticRoute> routes = new ArrayList<StaticRoute>();
+
+ for (StaticRouteConfig conf : staticRouting.getStaticRouteConfigs()
+ .values()) {
+ StaticRoute route = new StaticRoute(conf.getName(), conf
+ .getStaticRoute(), conf.getNextHop());
+ routes.add(route);
+ }
+ return routes;
+ }
+
+ /**
+ * Get a list of static routes present on the given container.
+ *
+ * @param containerName Name of the Container. The Container name for the base controller is "default".
+ * @return List of configured static routes on the given container
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/staticroute/default/routes
+ *
+ * Response body in XML:
+ * <list>
+ * <staticRoute>
+ * <name>route-1</name>
+ * <prefix>10.10.1.0/24</prefix>
+ * <nextHop>1.1.1.1</nextHop>
+ * </staticRoute>
+ * </list>
+ *
+ * Response body in JSON:
+ * {
+ * "staticRoute": [
+ * {
+ * "name": "route-1",
+ * "prefix": "10.10.1.0/24",
+ * "nextHop": "1.1.1.1"
+ * }
+ * ]
+ * }
+ * </pre>
+ */
+ @Path("/{containerName}/routes")
+ @GET
+ @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(StaticRoutes.class)
+ @StatusCodes( {
+ @ResponseCode(code = 200, condition = "Operation successful"),
+ @ResponseCode(code = 404, condition = "The containerName passed was not found") })
+ public StaticRoutes getStaticRoutes(
+ @PathParam("containerName") String containerName,
+ @QueryParam("_q") String queryString) {
+
+ if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
+ Privilege.WRITE, this)){
+ throw new
+ UnauthorizedException("User is not authorized to perform this operation on container "
+ + containerName);
+ }
+ StaticRoutes result = new StaticRoutes(getStaticRoutesInternal(containerName));
+ if (queryString != null) {
+ queryContext.createQuery(queryString, StaticRoutes.class)
+ .filter(result, StaticRoute.class);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the static route for the provided configuration name on a given container
+ *
+ * @param containerName Name of the Container. The Container name for the base controller is "default".
+ * @param route Name of the Static Route configuration
+ * @return Static route configured with the supplied Name.
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
+ *
+ * Response body in XML:
+ *
+ * <staticRoute>
+ * <name>route-1</name>
+ * <prefix>10.10.1.0/24</prefix>
+ * <nextHop>1.1.1.1</nextHop>
+ * </staticRoute>
+ *
+ * Response body in JSON:
+ * {
+ * "name":"route-1",
+ * "prefix":"10.10.1.0/24",
+ * "nextHop":"1.1.1.1"
+ * }
+ *
+ * </pre>
+ */
+ @Path("/{containerName}/route/{route}")
+ @GET
+ @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @TypeHint(StaticRoute.class)
+ @StatusCodes( {
+ @ResponseCode(code = 200, condition = "Operation successful"),
+ @ResponseCode(code = 404, condition = "The Container Name or Static Route Configuration name passed was not found") })
+ public StaticRoute getStaticRoute(
+ @PathParam("containerName") String containerName,
+ @PathParam("route") String route) {
+
+ if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
+ Privilege.WRITE, this)){
+ throw new
+ UnauthorizedException("User is not authorized to perform this operation on container "
+ + containerName);
+ }
+ List<StaticRoute> routes = this.getStaticRoutesInternal(containerName);
+ for (StaticRoute r : routes) {
+ if (r.getName().equalsIgnoreCase(route)) {
+ return r;
+ }
+ }
+
+ throw new ResourceNotFoundException(RestMessages.NOSTATICROUTE
+ .toString());
+ }
+
+ /**
+ *
+ * Add a new Static Route. If a route by the given name already exists, this
+ * method will return a non-successful status response.
+ *
+ * @param containerName Name of the Container. The Container name for the base controller is "default".
+ * @param route Name of the Static Route configuration
+ * @return Response as dictated by the HTTP Response code
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
+ *
+ * Request body in XML:
+ * <staticRoute>
+ * <name>route-1</name>
+ * <prefix>10.10.1.0/24</prefix>
+ * <nextHop>1.1.1.1</nextHop>
+ * </staticRoute>
+ * Request body in JSON:
+ * {
+ * "name":"route-1",
+ * "prefix":"10.10.1.0/24",
+ * "nextHop":"1.1.1.1"
+ * }
+ * </pre>
+ */
+ @Path("/{containerName}/route/{route}")
+ @PUT
+ @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @StatusCodes( {
+ @ResponseCode(code = 201, condition = "Created Static Route successfully"),
+ @ResponseCode(code = 404, condition = "The Container Name passed is not found"),
+ @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
+ @ResponseCode(code = 409, condition = "Failed to create Static Route entry due to Conflicting Name or Prefix."), })
+ public Response addStaticRoute(
+ @Context UriInfo uriInfo,
+ @PathParam(value = "containerName") String containerName,
+ @PathParam(value = "route") String route,
+ @TypeHint(StaticRoute.class) StaticRoute staticRouteData) {
+
+
+ if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
+ Privilege.WRITE, this)){
+ throw new
+ UnauthorizedException("User is not authorized to perform this operation on container "
+ + containerName);
+ }
+ handleDefaultDisabled(containerName);
+
+ IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
+ .getInstance(IForwardingStaticRouting.class, containerName,
+ this);
+
+ if (staticRouting == null) {
+ throw new ResourceNotFoundException(RestMessages.NOCONTAINER
+ .toString());
+ }
+
+ StaticRoute sRoute = staticRouteData;
+ StaticRouteConfig cfgObject = new StaticRouteConfig(sRoute.getName(),
+ sRoute.getPrefix(), sRoute.getNextHop());
+ Status response = staticRouting.addStaticRoute(cfgObject);
+ if (response.isSuccess()) {
+ NorthboundUtils.auditlog("Static Route", username, "added", route, containerName);
+ return Response.created(uriInfo.getRequestUri()).build();
+ }
+ throw new ResourceConflictException(response.getDescription());
+ }
+
+ /**
+ *
+ * Delete a Static Route
+ *
+ * @param containerName Name of the Container. The Container name for the base controller is "default".
+ * @param route Name of the Static Route configuration to be removed
+ *
+ * @return Response as dictated by the HTTP Response code
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * DELETE http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
+ *
+ * </pre>
+ */
+ @Path("/{containerName}/route/{route}")
+ @DELETE
+ @StatusCodes( {
+ @ResponseCode(code = 204, condition = "Static route removed successfully"),
+ @ResponseCode(code = 404, condition = "Container Name or Configuration Name not found"),
+ @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active") })
+ public Response removeStaticRoute(
+ @PathParam(value = "containerName") String containerName,
+ @PathParam(value = "route") String route) {
+
+ if(!NorthboundUtils.isAuthorized(getUserName(), containerName,
+ Privilege.WRITE, this)){
+ throw new
+ UnauthorizedException("User is not authorized to perform this operation on container "
+ + containerName);
+ }
+ handleDefaultDisabled(containerName);
+
+ IForwardingStaticRouting staticRouting = (IForwardingStaticRouting) ServiceHelper
+ .getInstance(IForwardingStaticRouting.class, containerName,
+ this);
+
+ if (staticRouting == null) {
+ throw new ResourceNotFoundException(RestMessages.NOCONTAINER
+ .toString());
+ }
+
+ Status status = staticRouting.removeStaticRoute(route);
+ if (status.isSuccess()) {
+ NorthboundUtils.auditlog("Static Route", username, "removed", route, containerName);
+ return Response.noContent().build();
+ }
+ return NorthboundUtils.getResponse(status);
+ }
+
+ private void handleDefaultDisabled(String containerName) {
+ IContainerManager containerManager = (IContainerManager) ServiceHelper
+ .getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ throw new InternalServerErrorException(RestMessages.INTERNALERROR
+ .toString());
+ }
+ if (containerName.equals(GlobalConstants.DEFAULT.toString())
+ && containerManager.hasNonDefaultContainer()) {
+ throw new NotAcceptableException(RestMessages.DEFAULTDISABLED
+ .toString());
+ }
+ }
+}