32b9dd32bb41304f5451a26eeeb2260f258bbe43
[controller.git] / opendaylight / northbound / flowprogrammer / src / main / java / org / opendaylight / controller / flowprogrammer / northbound / FlowProgrammerNorthbound.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.flowprogrammer.northbound;
10
11 import java.util.ArrayList;
12 import java.util.List;
13
14 import javax.ws.rs.Consumes;
15 import javax.ws.rs.DELETE;
16 import javax.ws.rs.GET;
17 import javax.ws.rs.POST;
18 import javax.ws.rs.PUT;
19 import javax.ws.rs.Path;
20 import javax.ws.rs.PathParam;
21 import javax.ws.rs.Produces;
22 import javax.ws.rs.core.Context;
23 import javax.ws.rs.core.MediaType;
24 import javax.ws.rs.core.Response;
25 import javax.ws.rs.core.SecurityContext;
26 import javax.xml.bind.JAXBElement;
27
28 import org.codehaus.enunciate.jaxrs.ResponseCode;
29 import org.codehaus.enunciate.jaxrs.StatusCodes;
30 import org.codehaus.enunciate.jaxrs.TypeHint;
31 import org.opendaylight.controller.containermanager.IContainerManager;
32 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
33 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
34 import org.opendaylight.controller.northbound.commons.RestMessages;
35 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
36 import org.opendaylight.controller.northbound.commons.exception.MethodNotAllowedException;
37 import org.opendaylight.controller.northbound.commons.exception.NotAcceptableException;
38 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
39 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
40 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
41 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
42 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
43 import org.opendaylight.controller.sal.authorization.Privilege;
44 import org.opendaylight.controller.sal.core.Node;
45 import org.opendaylight.controller.sal.utils.GlobalConstants;
46 import org.opendaylight.controller.sal.utils.ServiceHelper;
47 import org.opendaylight.controller.sal.utils.Status;
48 import org.opendaylight.controller.switchmanager.ISwitchManager;
49
50 /**
51  * Flow Configuration Northbound API
52  *
53  * <br>
54  * <br>
55  * Authentication scheme : <b>HTTP Basic</b><br>
56  * Authentication realm : <b>opendaylight</b><br>
57  * Transport : <b>HTTP and HTTPS</b><br>
58  * <br>
59  * HTTPS Authentication is disabled by default. Administrator can enable it in
60  * tomcat-server.xml after adding a proper keystore / SSL certificate from a
61  * trusted authority.<br>
62  * More info :
63  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
64  *
65  */
66 @Path("/")
67 public class FlowProgrammerNorthbound {
68
69     private String username;
70
71     @Context
72     public void setSecurityContext(SecurityContext context) {
73         username = context.getUserPrincipal().getName();
74     }
75
76     protected String getUserName() {
77         return username;
78     }
79
80     private IForwardingRulesManager getForwardingRulesManagerService(
81             String containerName) {
82         IContainerManager containerManager = (IContainerManager) ServiceHelper
83                 .getGlobalInstance(IContainerManager.class, this);
84         if (containerManager == null) {
85             throw new ServiceUnavailableException("Container "
86                     + RestMessages.SERVICEUNAVAILABLE.toString());
87         }
88
89         boolean found = false;
90         List<String> containerNames = containerManager.getContainerNames();
91         for (String cName : containerNames) {
92             if (cName.trim().equalsIgnoreCase(containerName.trim())) {
93                 found = true;
94             }
95         }
96
97         if (found == false) {
98             throw new ResourceNotFoundException(containerName + " "
99                     + RestMessages.NOCONTAINER.toString());
100         }
101
102         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper
103                 .getInstance(IForwardingRulesManager.class, containerName, this);
104
105         if (frm == null) {
106             throw new ServiceUnavailableException("Flow Programmer "
107                     + RestMessages.SERVICEUNAVAILABLE.toString());
108         }
109
110         return frm;
111     }
112
113     private List<FlowConfig> getStaticFlowsInternal(String containerName,
114             Node node) {
115         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
116
117         if (frm == null) {
118             throw new ServiceUnavailableException("Flow Programmer "
119                     + RestMessages.SERVICEUNAVAILABLE.toString());
120         }
121
122         List<FlowConfig> flows = new ArrayList<FlowConfig>();
123
124         if (node == null) {
125             for (FlowConfig flow : frm.getStaticFlows()) {
126                 flows.add(flow);
127             }
128         } else {
129             ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
130                     ISwitchManager.class, containerName, this);
131
132             if (sm == null) {
133                 throw new ServiceUnavailableException("Switch Manager "
134                         + RestMessages.SERVICEUNAVAILABLE.toString());
135             }
136
137             if (!sm.getNodes().contains(node)) {
138                 throw new ResourceNotFoundException(node.toString() + " : "
139                         + RestMessages.NONODE.toString());
140             }
141
142             for (FlowConfig flow : frm.getStaticFlows(node)) {
143                 flows.add(flow);
144             }
145         }
146         return flows;
147     }
148
149     /**
150      * Returns a list of Flows configured on the given container
151      *
152      * @param containerName
153      *            Name of the Container (Eg. 'default')
154      * @return List of flows configured on a given container
155      *
156      * <pre>
157      *
158      * Example:
159      *
160      * RequestURL:
161      * http://localhost:8080/controller/nb/v2/flow/default
162      *
163      * Response in XML:
164      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
165      * &lt;list&gt;
166      *     &#x20;&#x20;&#x20;&lt;flowConfig&gt;
167      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
168      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
169      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
170      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
171      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
172      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
173      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
174      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
175      *     &#x20;&#x20;&#x20;&lt;/flowConfig&gt;
176      * &lt;/list&gt;
177      *
178      * Response in JSON:
179      * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
180      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
181      *
182      * </pre>
183      */
184     @Path("/{containerName}")
185     @GET
186     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
187     @TypeHint(FlowConfigs.class)
188     @StatusCodes({
189             @ResponseCode(code = 200, condition = "Operation successful"),
190             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
191             @ResponseCode(code = 404, condition = "The containerName is not found"),
192             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
193     public FlowConfigs getStaticFlows(
194             @PathParam("containerName") String containerName) {
195         if (!NorthboundUtils.isAuthorized(
196                 getUserName(), containerName, Privilege.READ, this)) {
197             throw new UnauthorizedException(
198                     "User is not authorized to perform this operation on container "
199                             + containerName);
200         }
201
202         List<FlowConfig> flowConfigs = getStaticFlowsInternal(containerName,
203                 null);
204         return new FlowConfigs(flowConfigs);
205     }
206
207     /**
208      * Returns a list of Flows configured on a Node in a given container
209      *
210      * @param containerName
211      *            Name of the Container (Eg. 'default')
212      * @param nodeType
213      *            Type of the node being programmed (Eg. 'OF')
214      * @param nodeId
215      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
216      * @return List of flows configured on a Node in a container
217      *
218      * <pre>
219      *
220      * Example:
221      *
222      * RequestURL:
223      * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01
224      *
225      * Response in XML:
226      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
227      * &lt;list&gt;
228      *     &#x20;&#x20;&#x20;&lt;flowConfig&gt;
229      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
230      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
231      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
232      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
233      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
234      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
235      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
236      *         &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
237      *     &#x20;&#x20;&#x20;&lt;/flowConfig&gt;
238      * &lt;/list&gt;
239      *
240      * Response in JSON:
241      * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
242      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
243      *
244      * </pre>
245      */
246     @Path("/{containerName}/node/{nodeType}/{nodeId}")
247     @GET
248     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
249     @TypeHint(FlowConfigs.class)
250     @StatusCodes({
251             @ResponseCode(code = 200, condition = "Operation successful"),
252             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
253             @ResponseCode(code = 404, condition = "The containerName or nodeId is not found"),
254             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
255     public FlowConfigs getStaticFlows(
256             @PathParam("containerName") String containerName,
257             @PathParam("nodeType") String nodeType,
258             @PathParam("nodeId") String nodeId) {
259         if (!NorthboundUtils.isAuthorized(
260                 getUserName(), containerName, Privilege.READ, this)) {
261             throw new UnauthorizedException(
262                     "User is not authorized to perform this operation on container "
263                             + containerName);
264         }
265         Node node = Node.fromString(nodeType, nodeId);
266         if (node == null) {
267             throw new ResourceNotFoundException(nodeId + " : "
268                     + RestMessages.NONODE.toString());
269         }
270         List<FlowConfig> flows = getStaticFlowsInternal(containerName, node);
271         return new FlowConfigs(flows);
272     }
273
274     /**
275      * Returns the flow configuration matching a human-readable name and nodeId
276      * on a given Container.
277      *
278      * @param containerName
279      *            Name of the Container (Eg. 'default')
280      * @param nodeType
281      *            Type of the node being programmed (Eg. 'OF')
282      * @param nodeId
283      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
284      * @param name
285      *            Human-readable name for the configured flow (Eg. 'Flow1')
286      * @return Flow configuration matching the name and nodeId on a Container
287      *
288      * <pre>
289      *
290      * Example:
291      *
292      * RequestURL:
293      * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
294      *
295      * Response in XML:
296      * &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
297      * &lt;flowConfig&gt;
298      *     &#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
299      *     &#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
300      *     &#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
301      *     &#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
302      *     &#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
303      *     &#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
304      *     &#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
305      *     &#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
306      * &lt;/flowConfig&gt;
307      *
308      * Response in JSON:
309      * {"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
310      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
311      *
312      * </pre>
313      */
314     @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
315     @GET
316     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
317     @TypeHint(FlowConfig.class)
318     @StatusCodes({
319             @ResponseCode(code = 200, condition = "Operation successful"),
320             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
321             @ResponseCode(code = 404, condition = "The containerName or NodeId or Configuration name is not found"),
322             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
323     public FlowConfig getStaticFlow(
324             @PathParam("containerName") String containerName,
325             @PathParam("nodeType") String nodeType,
326             @PathParam("nodeId") String nodeId, @PathParam("name") String name) {
327         if (!NorthboundUtils.isAuthorized(
328                 getUserName(), containerName, Privilege.READ, this)) {
329             throw new UnauthorizedException(
330                     "User is not authorized to perform this operation on container "
331                             + containerName);
332         }
333         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
334
335         if (frm == null) {
336             throw new ServiceUnavailableException("Flow Programmer "
337                     + RestMessages.SERVICEUNAVAILABLE.toString());
338         }
339
340         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
341
342         FlowConfig staticFlow = frm.getStaticFlow(name, node);
343         if (staticFlow == null) {
344             throw new ResourceNotFoundException(RestMessages.NOFLOW.toString());
345         }
346
347         return new FlowConfig(staticFlow);
348     }
349
350     /**
351      * Add a flow configuration
352      *
353      * @param containerName
354      *            Name of the Container (Eg. 'default')
355      * @param nodeType
356      *            Type of the node being programmed (Eg. 'OF')
357      * @param nodeId
358      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
359      * @param name
360      *            Name of the Static Flow configuration (Eg. 'Flow2')
361      * @param FlowConfig
362      *            Flow Configuration in JSON or XML format
363      * @return Response as dictated by the HTTP Response Status code
364      *
365      * <pre>
366      *
367      * Example:
368      *
369      * RequestURL:
370      * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
371      *
372      * Request in XML:
373      * &lt;flowConfig&gt;
374      *         &#x20;&#x20;&#x20;&lt;installInHw&gt;true&lt;/installInHw&gt;
375      *         &#x20;&#x20;&#x20;&lt;name&gt;flow1&lt;/name&gt;
376      *         &#x20;&#x20;&#x20;&lt;node id="00:00:00:00:00:00:00:01" type="OF"/&gt;
377      *         &#x20;&#x20;&#x20;&lt;ingressPort&gt;1&lt;/ingressPort&gt;
378      *         &#x20;&#x20;&#x20;&lt;priority&gt;500&lt;/priority&gt;
379      *         &#x20;&#x20;&#x20;&lt;etherType&gt;0x800&lt;/etherType&gt;
380      *         &#x20;&#x20;&#x20;&lt;nwSrc&gt;9.9.1.1&lt;/nwSrc&gt;
381      *         &#x20;&#x20;&#x20;&lt;actions&gt;OUTPUT=2&lt;/actions&gt;
382      * &lt;/flowConfig&gt;
383      *
384      * Request in JSON:
385      * {"installInHw":"true","name":"flow1","node":{"@id":"00:00:00:00:00:00:00:01","@type":"OF"},
386      * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
387      *
388      * </pre>
389      */
390
391     @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
392     @PUT
393     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
394     @StatusCodes({
395             @ResponseCode(code = 201, condition = "Flow Config processed successfully"),
396             @ResponseCode(code = 400, condition = "Failed to create Static Flow entry due to invalid flow configuration"),
397             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
398             @ResponseCode(code = 404, condition = "The Container Name or nodeId is not found"),
399             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
400             @ResponseCode(code = 409, condition = "Failed to create Static Flow entry due to Conflicting Name or configuration"),
401             @ResponseCode(code = 500, condition = "Failed to create Static Flow entry. Failure Reason included in HTTP Error response"),
402             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
403     public Response addFlow(
404             @PathParam(value = "containerName") String containerName,
405             @PathParam(value = "name") String name,
406             @PathParam("nodeType") String nodeType,
407             @PathParam(value = "nodeId") String nodeId,
408             @TypeHint(FlowConfig.class) JAXBElement<FlowConfig> flowConfig) {
409
410         if (!NorthboundUtils.isAuthorized(
411                 getUserName(), containerName, Privilege.WRITE, this)) {
412             throw new UnauthorizedException(
413                     "User is not authorized to perform this operation on container "
414                             + containerName);
415         }
416         handleResourceCongruence(name, flowConfig.getValue().getName());
417         handleResourceCongruence(nodeId, flowConfig.getValue().getNode().getNodeIDString());
418         handleDefaultDisabled(containerName);
419
420         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
421
422         if (frm == null) {
423             throw new ServiceUnavailableException("Flow Programmer "
424                     + RestMessages.SERVICEUNAVAILABLE.toString());
425         }
426
427         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
428
429         FlowConfig staticFlow = frm.getStaticFlow(name, node);
430         if (staticFlow != null) {
431             throw new ResourceConflictException(name + " already exists."
432                     + RestMessages.RESOURCECONFLICT.toString());
433         }
434
435         Status status = frm.addStaticFlow(flowConfig.getValue());
436
437         if (status.isSuccess()) {
438             NorthboundUtils.auditlog("Flow", username, "added", name, containerName);
439             return Response.status(Response.Status.CREATED).entity("Success").build();
440         }
441         return NorthboundUtils.getResponse(status);
442     }
443
444     /**
445      * Delete a Flow configuration
446      *
447      * @param containerName
448      *            Name of the Container (Eg. 'default')
449      * @param nodeType
450      *            Type of the node being programmed (Eg. 'OF')
451      * @param nodeId
452      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
453      * @param name
454      *            Name of the Static Flow configuration (Eg. 'Flow1')
455      * @return Response as dictated by the HTTP Response code
456      *
457      * <pre>
458      *
459      * Example:
460      *
461      * RequestURL:
462      * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
463      *
464      * </pre>
465      */
466
467     @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
468     @DELETE
469     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
470     @StatusCodes({
471             @ResponseCode(code = 200, condition = "Flow Config deleted successfully"),
472             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
473             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
474             @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
475             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
476             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
477     public Response deleteFlow(
478             @PathParam(value = "containerName") String containerName,
479             @PathParam(value = "name") String name,
480             @PathParam("nodeType") String nodeType,
481             @PathParam(value = "nodeId") String nodeId) {
482
483         if (!NorthboundUtils.isAuthorized(
484                 getUserName(), containerName, Privilege.WRITE, this)) {
485             throw new UnauthorizedException(
486                     "User is not authorized to perform this operation on container "
487                             + containerName);
488         }
489         handleDefaultDisabled(containerName);
490
491         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
492
493         if (frm == null) {
494             throw new ServiceUnavailableException("Flow Programmer "
495                     + RestMessages.SERVICEUNAVAILABLE.toString());
496         }
497
498         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
499
500         FlowConfig staticFlow = frm.getStaticFlow(name, node);
501         if (staticFlow == null) {
502             throw new ResourceNotFoundException(name + " : "
503                     + RestMessages.NOFLOW.toString());
504         }
505
506         Status status = frm.removeStaticFlow(name, node);
507         if (status.isSuccess()) {
508             NorthboundUtils.auditlog("Flow", username, "removed", name, containerName);
509         }
510         return NorthboundUtils.getResponse(status);
511     }
512
513     /**
514      * Toggle a Flow configuration
515      *
516      * @param containerName
517      *            Name of the Container (Eg. 'default')
518      * @param nodeType
519      *            Type of the node being programmed (Eg. 'OF')
520      * @param nodeId
521      *            Node Identifier (Eg. '00:00:00:00:00:00:00:01')
522      * @param name
523      *            Name of the Static Flow configuration (Eg. 'Flow1')
524      * @return Response as dictated by the HTTP Response code
525      *
526      * <pre>
527      *
528      * Example:
529      *
530      * RequestURL:
531      * http://localhost:8080/controller/nb/v2/flow/default/node/OF/00:00:00:00:00:00:00:01/static-flow/flow1
532      *
533      * </pre>
534      */
535     @Path("/{containerName}/node/{nodeType}/{nodeId}/static-flow/{name}")
536     @POST
537     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
538     @StatusCodes({
539             @ResponseCode(code = 200, condition = "Flow Config processed successfully"),
540             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
541             @ResponseCode(code = 404, condition = "The Container Name or Node-id or Flow Name passed is not found"),
542             @ResponseCode(code = 406, condition = "Failed to delete Flow config due to invalid operation. Failure details included in HTTP Error response"),
543             @ResponseCode(code = 500, condition = "Failed to delete Flow config. Failure Reason included in HTTP Error response"),
544             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
545     public Response toggleFlow(
546             @PathParam(value = "containerName") String containerName,
547             @PathParam("nodeType") String nodeType,
548             @PathParam(value = "nodeId") String nodeId,
549             @PathParam(value = "name") String name) {
550
551         if (!NorthboundUtils.isAuthorized(
552                 getUserName(), containerName, Privilege.WRITE, this)) {
553             throw new UnauthorizedException(
554                     "User is not authorized to perform this operation on container "
555                             + containerName);
556         }
557
558         handleDefaultDisabled(containerName);
559
560         IForwardingRulesManager frm = getForwardingRulesManagerService(containerName);
561
562         if (frm == null) {
563             throw new ServiceUnavailableException("Flow Programmer "
564                     + RestMessages.SERVICEUNAVAILABLE.toString());
565         }
566
567         Node node = handleNodeAvailability(containerName, nodeType, nodeId);
568
569         FlowConfig staticFlow = frm.getStaticFlow(name, node);
570         if (staticFlow == null) {
571             throw new ResourceNotFoundException(name + " : "
572                     + RestMessages.NOFLOW.toString());
573         }
574
575         Status status = frm.toggleStaticFlowStatus(staticFlow);
576         if (status.isSuccess()) {
577             NorthboundUtils.auditlog("Flow", username, "toggled", name, containerName);
578         }
579         return NorthboundUtils.getResponse(status);
580     }
581
582     private Node handleNodeAvailability(String containerName, String nodeType,
583             String nodeId) {
584
585         Node node = Node.fromString(nodeType, nodeId);
586         if (node == null) {
587             throw new ResourceNotFoundException(nodeId + " : "
588                     + RestMessages.NONODE.toString());
589         }
590
591         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
592                 ISwitchManager.class, containerName, this);
593
594         if (sm == null) {
595             throw new ServiceUnavailableException("Switch Manager "
596                     + RestMessages.SERVICEUNAVAILABLE.toString());
597         }
598
599         if (!sm.getNodes().contains(node)) {
600             throw new ResourceNotFoundException(node.toString() + " : "
601                     + RestMessages.NONODE.toString());
602         }
603         return node;
604     }
605
606     private void handleDefaultDisabled(String containerName) {
607         IContainerManager containerManager = (IContainerManager) ServiceHelper
608                 .getGlobalInstance(IContainerManager.class, this);
609         if (containerManager == null) {
610             throw new InternalServerErrorException(
611                     RestMessages.INTERNALERROR.toString());
612         }
613         if (containerName.equals(GlobalConstants.DEFAULT.toString())
614                 && containerManager.hasNonDefaultContainer()) {
615             throw new NotAcceptableException(
616                     RestMessages.DEFAULTDISABLED.toString());
617         }
618     }
619
620     private void handleResourceCongruence(String resource, String configured) {
621         if (!resource.equals(configured)) {
622             throw new MethodNotAllowedException("Path's resource name conflicts with payload's resource name");
623         }
624     }
625
626 }