3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.controller.flowprogrammer.northbound;
12 import java.util.ArrayList;
13 import java.util.List;
15 import javax.ws.rs.Consumes;
16 import javax.ws.rs.DELETE;
17 import javax.ws.rs.GET;
18 import javax.ws.rs.POST;
19 import javax.ws.rs.PUT;
20 import javax.ws.rs.Path;
21 import javax.ws.rs.PathParam;
22 import javax.ws.rs.Produces;
23 import javax.ws.rs.core.MediaType;
24 import javax.ws.rs.core.Response;
25 import javax.xml.bind.JAXBElement;
27 import org.codehaus.enunciate.jaxrs.ResponseCode;
28 import org.codehaus.enunciate.jaxrs.StatusCodes;
29 import org.codehaus.enunciate.jaxrs.TypeHint;
30 import org.opendaylight.controller.containermanager.IContainerManager;
31 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
32 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
33 import org.opendaylight.controller.northbound.commons.RestMessages;
34 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
35 import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException;
36 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
37 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
38 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
39 import org.opendaylight.controller.sal.core.Node;
40 import org.opendaylight.controller.sal.utils.GlobalConstants;
41 import org.opendaylight.controller.sal.utils.ServiceHelper;
42 import org.opendaylight.controller.sal.utils.Status;
43 import org.opendaylight.controller.switchmanager.ISwitchManager;
46 * Flow Configuration Northbound API
49 * Authentication scheme : <b>HTTP Basic</b><br>
50 * Authentication realm : <b>opendaylight</b><br>
51 * Transport : <b>HTTP and HTTPS</b><br>
53 * HTTPS Authentication is disabled by default. Administrator can enable it in tomcat-server.xml after adding
54 * a proper keystore / SSL certificate from a trusted authority.<br>
55 * More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
59 public class FlowProgrammerNorthbound {
61 private IForwardingRulesManager getForwardingRulesManagerService(
62 String containerName) {
63 IContainerManager containerManager = (IContainerManager) ServiceHelper
64 .getGlobalInstance(IContainerManager.class, this);
65 if (containerManager == null) {
66 throw new ServiceUnavailableException("Container "
67 + RestMessages.SERVICEUNAVAILABLE.toString());
70 boolean found = false;
71 List<String> containerNames = containerManager.getContainerNames();
72 for (String cName : containerNames) {
73 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
79 throw new ResourceNotFoundException(containerName + " "
80 + RestMessages.NOCONTAINER.toString());
83 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper
84 .getInstance(IForwardingRulesManager.class, containerName, this);
87 throw new ServiceUnavailableException("Flow Programmer "
88 + RestMessages.SERVICEUNAVAILABLE.toString());
94 private List<FlowConfig> getStaticFlowsInternal(String containerName,
96 IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
99 throw new ServiceUnavailableException("Flow Programmer "
100 + RestMessages.SERVICEUNAVAILABLE.toString());
103 List<FlowConfig> flows = new ArrayList<FlowConfig>();
106 for (FlowConfig flow : frm.getStaticFlows()) {
110 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
111 ISwitchManager.class, containerName, this);
114 throw new ServiceUnavailableException("Switch Manager "
115 + RestMessages.SERVICEUNAVAILABLE.toString());
118 if (!sm.getNodes().contains(node)) {
119 throw new ResourceNotFoundException(node.toString() + " : "
120 + RestMessages.NONODE.toString());
123 for (FlowConfig flow : frm.getStaticFlows(node)) {
131 * Returns a list of Flows configured on the given container
133 * @param containerName Name of the Container. The Container name for the base controller is "default".
134 * @return List of configured flows configured on a given container
136 @Path("/{containerName}")
138 @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
139 @TypeHint(FlowConfigs.class)
141 @ResponseCode(code = 200, condition = "Operation successful"),
142 @ResponseCode(code = 404, condition = "The containerName is not found"),
143 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
144 public FlowConfigs getStaticFlows(
145 @PathParam("containerName") String containerName) {
146 List<FlowConfig> flowConfigs = getStaticFlowsInternal(containerName, null);
147 return new FlowConfigs(flowConfigs);
151 * Returns a list of Flows configured on a Node in a given container
153 * @param containerName Name of the Container. The Container name
154 * for the base controller is "default".
155 * @param nodeType Type of the node being programmed
156 * @param nodeId Node Identifier
157 * @return List of configured flows configured on a Node in a container
159 @Path("/{containerName}/{nodeType}/{nodeId}")
161 @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
162 @TypeHint(FlowConfigs.class)
164 @ResponseCode(code = 200, condition = "Operation successful"),
165 @ResponseCode(code = 404, condition = "The containerName or nodeId is not found"),
166 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
167 public FlowConfigs getStaticFlows(
168 @PathParam("containerName") String containerName,
169 @PathParam("nodeType") String nodeType,
170 @PathParam("nodeId") String nodeId) {
171 Node node = Node.fromString(nodeType, nodeId);
173 throw new ResourceNotFoundException(nodeId + " : "
174 + RestMessages.NONODE.toString());
176 List<FlowConfig> flows = getStaticFlowsInternal(containerName, node);
177 return new FlowConfigs(flows);
181 * Returns the flow configuration matching a human-readable name and nodeId on a
184 * @param containerName Name of the Container. The Container name
185 * for the base controller is "default".
186 * @param nodeType Type of the node being programmed
187 * @param nodeId Node Identifier
188 * @param name Human-readable name for the configured flow.
189 * @return Flow configuration matching the name and nodeId on a Container
191 @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
193 @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
194 @TypeHint(FlowConfig.class)
196 @ResponseCode(code = 200, condition = "Operation successful"),
197 @ResponseCode(code = 404, condition = "The containerName or NodeId or Configuration name is not found"),
198 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
199 public FlowConfig getStaticFlow(
200 @PathParam("containerName") String containerName,
201 @PathParam("nodeType") String nodeType,
202 @PathParam("nodeId") String nodeId,
203 @PathParam("name") String name) {
204 IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
207 throw new ServiceUnavailableException("Flow Programmer "
208 + RestMessages.SERVICEUNAVAILABLE.toString());
211 Node node = handleNodeAvailability(containerName, nodeType, nodeId);
213 FlowConfig staticFlow = frm.getStaticFlow(name, node);
214 if (staticFlow == null) {
215 throw new ResourceNotFoundException(RestMessages.NOFLOW.toString());
218 return new FlowConfig(staticFlow);
222 * Add a flow configuration
224 * @param containerName Name of the Container. The Container name
225 * for the base controller is "default".
226 * @param nodeType Type of the node being programmed
227 * @param nodeId Node Identifier
228 * @param name Name of the Static Flow configuration
229 * @param FlowConfig Flow Configuration in JSON or XML format
230 * @return Response as dictated by the HTTP Response Status code
233 @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
235 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
237 @ResponseCode(code = 201, condition = "Flow Config processed successfully"),
238 @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
239 @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
240 @ResponseCode(code = 409, condition = "Failed to create Static Flow entry due to Conflicting Name"),
241 @ResponseCode(code = 500, condition = "Failed to create Static Flow entry. Failure Reason included in HTTP Error response"),
242 @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
243 public Response addFlow(
244 @PathParam(value = "containerName") String containerName,
245 @PathParam(value = "name") String name,
246 @PathParam("nodeType") String nodeType,
247 @PathParam(value = "nodeId") String nodeId,
248 @TypeHint(FlowConfig.class) JAXBElement<FlowConfig> flowConfig) {
250 handleDefaultDisabled(containerName);
252 IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
255 throw new ServiceUnavailableException("Flow Programmer "
256 + RestMessages.SERVICEUNAVAILABLE.toString());
259 Node node = handleNodeAvailability(containerName, nodeType, nodeId);
261 FlowConfig staticFlow = frm.getStaticFlow(name, node);
262 if (staticFlow != null) {
263 throw new ResourceConflictException(name + " already exists."
264 + RestMessages.RESOURCECONFLICT.toString());
267 Status status = frm.addStaticFlow(flowConfig.getValue(), false);
268 if (status.isSuccess()) {
269 return Response.status(Response.Status.CREATED).build();
271 throw new InternalServerErrorException(status.getDescription());
275 * Delete a Flow configuration
277 * DELETE /flows/{containerName}/{nodeType}/{nodeId}/{name}
279 * @param containerName Name of the Container. The Container name
280 * for the base controller is "default".
281 * @param nodeType Type of the node being programmed
282 * @param nodeId Node Identifier
283 * @param name Name of the Static Flow configuration
284 * @return Response as dictated by the HTTP Response code
287 @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
289 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
291 @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
292 @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
293 @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
294 @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
295 @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
296 public Response deleteFlow(
297 @PathParam(value = "containerName") String containerName,
298 @PathParam(value = "name") String name,
299 @PathParam("nodeType") String nodeType,
300 @PathParam(value = "nodeId") String nodeId) {
302 handleDefaultDisabled(containerName);
304 IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
307 throw new ServiceUnavailableException("Flow Programmer "
308 + RestMessages.SERVICEUNAVAILABLE.toString());
311 Node node = handleNodeAvailability(containerName, nodeType, nodeId);
313 FlowConfig staticFlow = frm.getStaticFlow(name, node);
314 if (staticFlow == null) {
315 throw new ResourceNotFoundException(name + " : "
316 + RestMessages.NOFLOW.toString());
319 Status status = frm.removeStaticFlow(name, node);
320 if (status.isSuccess()) {
321 return Response.ok().build();
323 throw new InternalServerErrorException(status.getDescription());
327 * Toggle a Flow configuration
329 * @param containerName Name of the Container. The Container name
330 * for the base controller is "default".
331 * @param nodeType Type of the node being programmed
332 * @param nodeId Node Identifier
333 * @param name Name of the Static Flow configuration
334 * @return Response as dictated by the HTTP Response code
337 @Path("/{containerName}/{nodeType}/{nodeId}/{name}")
339 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
341 @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
342 @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
343 @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
344 @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
345 @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
346 public Response toggleFlow(
347 @PathParam(value = "containerName") String containerName,
348 @PathParam("nodeType") String nodeType,
349 @PathParam(value = "nodeId") String nodeId,
350 @PathParam(value = "name") String name) {
352 handleDefaultDisabled(containerName);
354 IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
357 throw new ServiceUnavailableException("Flow Programmer "
358 + RestMessages.SERVICEUNAVAILABLE.toString());
361 Node node = handleNodeAvailability(containerName, nodeType, nodeId);
363 FlowConfig staticFlow = frm.getStaticFlow(name, node);
364 if (staticFlow == null) {
365 throw new ResourceNotFoundException(name + " : "
366 + RestMessages.NOFLOW.toString());
369 Status status = frm.toggleStaticFlowStatus(staticFlow);
370 if (status.isSuccess()) {
371 return Response.ok().build();
373 throw new InternalServerErrorException(status.getDescription());
376 private Node handleNodeAvailability(String containerName, String nodeType,
379 Node node = Node.fromString(nodeType, nodeId);
381 throw new ResourceNotFoundException(nodeId + " : "
382 + RestMessages.NONODE.toString());
385 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
386 ISwitchManager.class, containerName, this);
389 throw new ServiceUnavailableException("Switch Manager "
390 + RestMessages.SERVICEUNAVAILABLE.toString());
393 if (!sm.getNodes().contains(node)) {
394 throw new ResourceNotFoundException(node.toString() + " : "
395 + RestMessages.NONODE.toString());
400 private void handleDefaultDisabled(String containerName) {
401 IContainerManager containerManager = (IContainerManager) ServiceHelper
402 .getGlobalInstance(IContainerManager.class, this);
403 if (containerManager == null) {
404 throw new InternalServerErrorException(RestMessages.INTERNALERROR
407 if (containerName.equals(GlobalConstants.DEFAULT.toString())
408 && containerManager.hasNonDefaultContainer()) {
409 throw new NotAcceptableException(RestMessages.DEFAULTDISABLED