Fix bug 153: change the key container-config to ContainerConfig in the container...
[controller.git] / opendaylight / northbound / containermanager / src / main / java / org / opendaylight / controller / containermanager / northbound / ContainerManagerNorthbound.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
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
8  */
9
10 package org.opendaylight.controller.containermanager.northbound;
11
12 import java.util.ArrayList;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
16
17 import javax.ws.rs.Consumes;
18 import javax.ws.rs.DELETE;
19 import javax.ws.rs.GET;
20 import javax.ws.rs.PUT;
21 import javax.ws.rs.Path;
22 import javax.ws.rs.PathParam;
23 import javax.ws.rs.Produces;
24 import javax.ws.rs.core.Context;
25 import javax.ws.rs.core.MediaType;
26 import javax.ws.rs.core.Response;
27 import javax.ws.rs.core.SecurityContext;
28 import javax.ws.rs.core.UriInfo;
29
30 import org.codehaus.enunciate.jaxrs.ResponseCode;
31 import org.codehaus.enunciate.jaxrs.StatusCodes;
32 import org.codehaus.enunciate.jaxrs.TypeHint;
33 import org.opendaylight.controller.containermanager.ContainerConfig;
34 import org.opendaylight.controller.containermanager.ContainerFlowConfig;
35 import org.opendaylight.controller.containermanager.IContainerAuthorization;
36 import org.opendaylight.controller.containermanager.IContainerManager;
37 import org.opendaylight.controller.northbound.commons.RestMessages;
38 import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
39 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
40 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
41 import org.opendaylight.controller.northbound.commons.exception.ResourceForbiddenException;
42 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
43 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
44 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
45 import org.opendaylight.controller.sal.authorization.Privilege;
46 import org.opendaylight.controller.sal.authorization.UserLevel;
47 import org.opendaylight.controller.sal.utils.GlobalConstants;
48 import org.opendaylight.controller.sal.utils.ServiceHelper;
49 import org.opendaylight.controller.sal.utils.Status;
50 import org.opendaylight.controller.usermanager.IUserManager;
51
52 /**
53  * Container Manager Northbound API
54  *
55  * <br>
56  * <br>
57  * Authentication scheme : <b>HTTP Basic</b><br>
58  * Authentication realm : <b>opendaylight</b><br>
59  * Transport : <b>HTTP and HTTPS</b><br>
60  * <br>
61  * HTTPS Authentication is disabled by default. Administrator can enable it in
62  * tomcat-server.xml after adding a proper keystore / SSL certificate from a
63  * trusted authority.<br>
64  * More info :
65  * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
66  *
67  */
68 @Path("/")
69 public class ContainerManagerNorthbound {
70     private String username;
71
72     @Context
73     public void setSecurityContext(SecurityContext context) {
74         if (context != null && context.getUserPrincipal() != null) {
75             username = context.getUserPrincipal().getName();
76         }
77     }
78
79     protected String getUserName() {
80         return username;
81     }
82
83     private IContainerManager getContainerManager() {
84         IContainerManager containerMgr = (IContainerManager) ServiceHelper.getGlobalInstance(IContainerManager.class, this);
85         if (containerMgr == null) {
86             throw new InternalServerErrorException(RestMessages.INTERNALERROR.toString());
87         }
88         return containerMgr;
89     }
90
91     private void handleNameMismatch(String name, String nameinURL) {
92         if (name == null || nameinURL == null) {
93             throw new BadRequestException(RestMessages.INVALIDJSON.toString());
94         }
95
96         if (name.equalsIgnoreCase(nameinURL)) {
97             return;
98         }
99         throw new BadRequestException(RestMessages.INVALIDJSON.toString());
100     }
101
102
103
104     /**
105      * Get all the containers configured in the system
106      *
107      * @return a List of all {@link org.opendaylight.controller.containermanager.ContainerConfig}
108      *
109      *         <pre>
110      *
111      * Example:
112      *
113      * Request URL:
114      * http://localhost:8080/controller/nb/v2/containermanager/containers
115      *
116      * Response body in XML:
117      * &lt;containerConfig-list&gt;
118      *    &#x20;&#x20;&#x20;&lt;containerConfig&gt;
119      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;container&gt;black&lt;/container&gt;
120      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;staticVlan&gt;10&lt;/staticVlan&gt;
121      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nodeConnectors&gt;OF|1@OF|00:00:00:00:00:00:00:01&lt;/nodeConnectors&gt;
122      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nodeConnectors&gt;OF|23@OF|00:00:00:00:00:00:20:21&lt;/nodeConnectors&gt;
123      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;flowSpecs&gt;
124      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;tcp&lt;/name&gt;
125      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;protocol&gt;TCP&lt;/protocol&gt;
126      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/flowSpecs&gt;
127      *    &#x20;&#x20;&#x20;&#x20;&lt;/containerConfig&gt;
128      *    &#x20;&#x20;&#x20;&#x20;&lt;containerConfig&gt;
129      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;container&gt;red&lt;/container&gt;
130      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;staticVlan&gt;20&lt;/staticVlan&gt;
131      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nodeConnectors&gt;OF|1@OF|00:00:00:00:00:00:00:01&lt;/nodeConnectors&gt;
132      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nodeConnectors&gt;OF|23@OF|00:00:00:00:00:00:20:21&lt;/nodeConnectors&gt;
133      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;flowSpecs&gt;
134      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;udp&lt;/name&gt;
135      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;protocol&gt;UDP&lt;/protocol&gt;
136      *    &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;/flowSpecs&gt;
137      *  &#x20;&#x20;&#x20;&#x20;&lt;/containerConfig&gt;
138      * &lt;/containerConfig-list&gt;
139      *
140      * Response body in JSON:
141      * { "containerConfig" : [
142      *     { "container" : "black",
143      *       "nodeConnectors" : [
144      *          "OF|1@OF|00:00:00:00:00:00:00:01", "OF|23@OF|00:00:00:00:00:00:20:21"
145      *       ],
146      *       "staticVlan" : "10",
147      *       "flowSpecs : [
148      *          { "name": "udp",
149      *            "protocol": "UDP" }
150      *       ]
151      *     },
152      *     { "container" : "red",
153      *       "nodeConnectors" : [
154      *          "OF|1@OF|00:00:00:00:00:00:00:01",
155      *          "OF|23@OF|00:00:00:00:00:00:20:21"
156      *       ],
157      *       "staticVlan" : "20",
158      *       "flowSpecs": [
159      *          { "name": "tcp",
160      *            "protocol": "TCP"
161      *          }
162      *       ]
163      *     }
164      *   ]
165      * }
166      * </pre>
167      */
168     @Path("/containers")
169     @GET
170     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
171     @TypeHint(ContainerConfigs.class)
172     @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
173             @ResponseCode(code = 401, condition = "User is not authorized to perform this operation"),
174             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
175     public ContainerConfigs viewAllContainers() {
176
177         handleNetworkAuthorization(getUserName());
178
179         IContainerManager containerManager = getContainerManager();
180
181         return new ContainerConfigs(containerManager.getContainerConfigList());
182     }
183
184     /**
185      * Get the container configuration for container name requested
186      *
187      * @param container
188      *            name of the Container (eg. blue)
189      * @return a List of {@link org.opendaylight.controller.containermanager.ContainerConfig}
190      *
191      *         <pre>
192      *
193      * Example:
194      *
195      * Request URL:
196      * http://localhost:8080/controller/nb/v2/containermanager/container/blue
197      *
198      * Response body in XML:
199      * &lt;containerConfig&gt;
200      *  &#x20;&#x20;&#x20;&#x20;&lt;container&gt;blue&lt;/container&gt;
201      *  &#x20;&#x20;&#x20;&#x20;&lt;staticVlan&gt;10&lt;/staticVlan&gt;
202      *  &#x20;&#x20;&#x20;&#x20;&lt;nodeConnectors&gt;OF|1@OF|00:00:00:00:00:00:00:01&lt;/nodeConnectors&gt;
203      *  &#x20;&#x20;&#x20;&#x20;&lt;nodeConnectors&gt;OF|23@OF|00:00:00:00:00:00:20:21&lt;/nodeConnectors&gt;
204      * &lt;/containerConfig&gt;
205      *
206      * Response body in JSON:
207      * {
208      *    "containerConfig": [
209      *       {
210      *        "container": "yellow",
211      *        "staticVlan": "10",
212      *        "nodeConnectors": [
213      *           "OF|1@OF|00:00:00:00:00:00:00:01",
214      *           "OF|2@OF|00:00:00:00:00:00:00:02"
215      *        ],
216      *        "flowSpecs": []
217      *       }
218      *    ]
219      * }
220      * </pre>
221      */
222     @Path("/container/{container}")
223     @GET
224     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
225     @TypeHint(ContainerConfig.class)
226     @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
227             @ResponseCode(code = 401, condition = "User is not authorized to perform this operation"),
228             @ResponseCode(code = 403, condition = "Operation forbidden on default"),
229             @ResponseCode(code = 404, condition = "The container is not found") })
230     public ContainerConfigs viewContainer(@PathParam(value = "container") String container) {
231
232         handleContainerAuthorization(container, getUserName());
233         handleForbiddenOnDefault(container);
234
235         handleContainerNotExists(container);
236
237         IContainerManager containerManager = getContainerManager();
238         List<ContainerConfig> containerConfigs = new ArrayList<ContainerConfig>();
239         containerConfigs.add(containerManager.getContainerConfig(container));
240         return new ContainerConfigs(containerConfigs);
241     }
242
243     /**
244      * Create a container
245      *
246      * @param uriInfo
247      * @param container
248      *            name of the Container (eg. yellow)
249      * @param containerConfig
250      *            details of the container as specified by:
251      *            {@link org.opendaylight.controller.containermanager.ContainerConfig}
252      * @return Response as dictated by the HTTP Response Status code
253      *
254      * <pre>
255      *
256      * Example:
257      *
258      * Request URL:
259      * http://localhost:8080/controller/nb/v2/containermanager/container/yellow
260      *
261      * Request body in XML:
262      * &lt;containerConfig&gt;
263      *   &#x20;&#x20;&#x20;&#x20;&lt;container&gt;yellow&lt;/container&gt;
264      *   &#x20;&#x20;&#x20;&#x20;&lt;staticVlan&gt;10&lt;/staticVlan&gt;
265      *   &#x20;&#x20;&#x20;&#x20;&lt;nodeConnectors&gt;&lt;/nodeConnectors&gt;
266      * &lt;/containerConfig&gt;
267      *
268      * Request body in JSON:
269      * {
270      *    "container" : "yellow",
271      *    "nodeConnectors" : [
272      *       "OF|1@OF|00:00:00:00:00:00:00:01",
273      *       "OF|23@OF|00:00:00:00:00:00:20:21"
274      *    ],
275      *    "staticVlan" : "10"
276      * }
277      *
278      * </pre>
279      */
280     @Path("/container/{container}")
281     @PUT
282     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
283     @StatusCodes({ @ResponseCode(code = 201, condition = "Container created successfully"),
284             @ResponseCode(code = 400, condition = "Invalid Container configuration."),
285             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
286             @ResponseCode(code = 403, condition = "Operation forbidden on default"),
287             @ResponseCode(code = 404, condition = "Container Name is not found"),
288             @ResponseCode(code = 409, condition = "Failed to create Container due to Conflicting Name"),
289             @ResponseCode(code = 500, condition = "Failure Reason included in HTTP Error response") })
290     public Response createContainer(@Context UriInfo uriInfo,
291             @PathParam(value = "container") String container,
292             @TypeHint(ContainerConfig.class) ContainerConfig containerConfig) {
293
294         handleAdminAuthorization(getUserName());
295         handleContainerExists(container);
296
297         handleNameMismatch(containerConfig.getContainerName(), container);
298         handleForbiddenOnDefault(container);
299
300         IContainerManager containerManager = getContainerManager();
301         Status status = containerManager.addContainer(containerConfig);
302         if (status.isSuccess()) {
303             NorthboundUtils.auditlog("Container", username, "added", container);
304             return Response.created(uriInfo.getRequestUri()).build();
305         }
306         return NorthboundUtils.getResponse(status);
307     }
308
309     /**
310      * Delete a container
311      *
312      * @param container
313      *            name of the Container (eg. green)
314      * @return Response as dictated by the HTTP Response code
315      *
316      * <pre>
317      *
318      * Example:
319      *
320      * Request URL:
321      * http://localhost:8080/controller/nb/v2/containermanager/container/green
322      *
323      * </pre>
324      */
325     @Path("/container/{container}")
326     @DELETE
327     @StatusCodes({
328             @ResponseCode(code = 204, condition = "Container deleted successfully"),
329             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
330             @ResponseCode(code = 403, condition = "Operation forbidden on default"),
331             @ResponseCode(code = 404, condition = "The container is not found") })
332     public Response removeContainer(@PathParam(value = "container") String container) {
333
334         handleAdminAuthorization(getUserName());
335         handleForbiddenOnDefault(container);
336         handleContainerNotExists(container);
337         IContainerManager containerManager = getContainerManager();
338         Status status = containerManager.removeContainer(container);
339         if (status.isSuccess()) {
340             NorthboundUtils.auditlog("Container", username, "removed", container);
341             return Response.noContent().build();
342         }
343         return NorthboundUtils.getResponse(status);
344     }
345
346     /**
347      * Get flowspec within a given container
348      *
349      * @param container
350      *            name of the Container (eg. green)
351      * @param name
352      *            name of the flowspec (eg. ssh)
353      * @return flowspec detail as specified by:
354      *         {@link org.opendaylight.controller.containermanager.ContainerFlowConfig}
355      *
356      *         <pre>
357      *
358      * Example:
359      *
360      * Request URL:
361      * http://localhost:8080/controller/nb/v2/containermanager/container/green/flowspec/ssh
362      *
363      * Response body in XML:
364      * &lt;flow-spec-config&gt;
365      *  &#x20;&#x20;&#x20;&#x20;&lt;name&gt;ssh&lt;/name&gt;
366      *  &#x20;&#x20;&#x20;&#x20;&lt;dlVlan&gt;52&lt;/dlVlan&gt;
367      *  &#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;10.0.0.101&lt;/nwSrc&gt;
368      *  &#x20;&#x20;&#x20;&#x20;&lt;nwDst&gt;10.0.0.102&lt;/nwDst&gt;
369      *  &#x20;&#x20;&#x20;&#x20;&lt;protocol&gt;IPv4&lt;/protocol&gt;
370      *  &#x20;&#x20;&#x20;&#x20;&lt;tpSrc&gt;80&lt;/tpSrc&gt;
371      *  &#x20;&#x20;&#x20;&#x20;&lt;tpDst&gt;100&lt;/tpDst&gt;
372      * &lt;/flow-spec-config&gt;
373      *
374      * Response body in JSON:
375      * {
376      *    "protocol" : "IPv4",
377      *    "dlVlan" : "52",
378      *    "nwDst" : "10.0.0.102",
379      *    "name" : "ssh",
380      *    "nwSrc" : "10.0.0.101",
381      *    "tpSrc" : "80",
382      *    "tpDst" : "100"
383      * }
384      *
385      * </pre>
386      */
387     @Path("/container/{container}/flowspec/{flowspec}")
388     @GET
389     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
390     @TypeHint(ContainerFlowConfig.class)
391     @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
392             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
393             @ResponseCode(code = 404, condition = "The container is not found"),
394             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
395     public ContainerFlowConfig viewContainerFlowSpec(@PathParam(value = "container") String container,
396             @PathParam(value = "flowspec") String flowspec) {
397
398         handleContainerAuthorization(container, getUserName());
399         handleForbiddenOnDefault(container);
400
401         handleContainerNotExists(container);
402         IContainerManager containerManager = getContainerManager();
403         List<ContainerFlowConfig> flowSpecs = containerManager.getContainerFlows(container);
404
405         for (ContainerFlowConfig containerFlowConfig : flowSpecs) {
406             if (containerFlowConfig.equalsByName(flowspec)) {
407                 return containerFlowConfig;
408             }
409         }
410         throw new ResourceNotFoundException("Flow Spec not found");
411     }
412
413     /**
414      * Get all the flowspec in a given container
415      *
416      * @param container
417      *            name of the Container (eg. red)
418      * @return list of all flowspec configured for a container. Flowspec as
419      *         specified by:
420      *         {@link org.opendaylight.controller.containermanager.ContainerFlowConfig}
421      *
422      *         <pre>
423      *
424      * Example:
425      *
426      * Request URL:
427      * http://localhost:8080/controller/nb/v2/containermanager/container/red/flowspec
428      *
429      * Response body in XML:
430      * &lt;flow-spec-configs&gt;
431      *   &#x20;&#x20;&#x20;&#x20;&lt;flow-spec-config&gt;
432      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;ssh&lt;/name&gt;
433      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;dlVlan&gt;52&lt;/dlVlan&gt;
434      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;10.0.0.101&lt;/nwSrc&gt;
435      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwDst&gt;10.0.0.102&lt;/nwDst&gt;
436      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;protocol&gt;IPv4&lt;/protocol&gt;
437      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;tpSrc&gt;23&lt;/tpSrc&gt;
438      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;tpDst&gt;100&lt;/tpDst&gt;
439      *   &#x20;&#x20;&#x20;&#x20;&lt;/flow-spec-config&gt;
440      *   &#x20;&#x20;&#x20;&#x20;&lt;flow-spec-config&gt;
441      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;name&gt;http2&lt;/name&gt;
442      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;dlVlan&gt;123&lt;/dlVlan&gt;
443      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;10.0.0.201&lt;/nwSrc&gt;
444      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;nwDst&gt;10.0.0.202&lt;/nwDst&gt;
445      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;protocol&gt;&lt;/protocol&gt;
446      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;tpSrc&gt;80&lt;/tpSrc&gt;
447      *     &#x20;&#x20;&#x20;&#x20;&#x20;&#x20;&lt;tpDst&gt;100&lt;/tpDst&gt;
448      *   &#x20;&#x20;&#x20;&#x20;&lt;/flow-spec-config&gt;
449      * &lt;/flow-spec-configs&gt;
450      *
451       * Response body in JSON:
452      * {
453      *   "flow-spec-config": [
454      *     {
455      *       "name": "http",
456      *       "dlVlan" : "52",
457      *       "nwSrc": "10.0.0.201",
458      *       "nwDst": "10.0.0.202",
459      *       "protocol": "",
460      *       "tpSrc": "80",
461      *       "tpDst": "100"
462      *     },
463      *     {
464      *       "name": "ssh",
465      *       "dlVlan" : "123",
466      *       "nwSrc": "10.0.0.101",
467      *       "nwDst": "10.0.0.102",
468      *       "protocol": "IPv4",
469      *       "tpSrc": "23",
470      *       "tpDst": "100"
471      *     }
472      *   ]
473      * }
474      *
475      * </pre>
476      */
477     @Path("/container/{container}/flowspecs")
478     @GET
479     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
480     @TypeHint(FlowSpecConfigs.class)
481     @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
482             @ResponseCode(code = 404, condition = "The container is not found"),
483             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
484     public FlowSpecConfigs viewContainerFlowSpecs(@PathParam(value = "container") String container) {
485
486         handleContainerAuthorization(container, getUserName());
487         handleForbiddenOnDefault(container);
488
489         handleContainerNotExists(container);
490
491         IContainerManager containerManager = getContainerManager();
492
493         return new FlowSpecConfigs(containerManager.getContainerFlows(container));
494     }
495
496     /**
497      * Add flowspec to a container
498      *
499      * @param container
500      *            name of the container (eg. purple)
501      * @param name
502      *            name of the flowspec (eg. http)
503      * @param flowspec
504      *            configuration as specified by:
505      *            {@link org.opendaylight.controller.containermanager.ContainerFlowConfig}
506      *
507      * @return Response as dictated by the HTTP Response code
508      *
509      *         <pre>
510      *
511      * Example:
512      *
513      * Request URL:
514      * http://localhost:8080/controller/nb/v2/containermanager/container/purple/flowspec/http
515      *
516      * Request body in XML:
517      *   &lt;flow-spec-config&gt;
518      *     &#x20;&#x20;&#x20;&#x20;&lt;name&gt;http&lt;/name&gt;
519      *     &#x20;&#x20;&#x20;&#x20;&lt;dlVlan&gt;25&lt;/dlVlan&gt;
520      *     &#x20;&#x20;&#x20;&#x20;&lt;nwSrc&gt;10.0.0.101&lt;/nwSrc&gt;
521      *     &#x20;&#x20;&#x20;&#x20;&lt;nwDst&gt;10.0.0.102&lt;/nwDst&gt;
522      *     &#x20;&#x20;&#x20;&#x20;&lt;protocol&gt;&lt;/protocol&gt;
523      *     &#x20;&#x20;&#x20;&#x20;&lt;tpSrc&gt;80&lt;/tpSrc&gt;
524      *     &#x20;&#x20;&#x20;&#x20;&lt;tpDst&gt;100&lt;/tpDst&gt;
525      *   &lt;/flow-spec-config&gt;
526      *
527      * Request body in JSON:
528      * {
529      *    "name" : "http",
530      *    "dlVlan" : "25",
531      *    "nwSrc" : "10.0.0.101",
532      *    "nwDst" : "10.0.0.102",
533      *    "protocol" : "",
534      *    "tpSrc" : "80",
535      *    "tpDst" : "100"
536      * }
537      *
538      * </pre>
539      */
540     @Path("/container/{container}/flowspec/{flowspec}")
541     @PUT
542     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
543     @StatusCodes({
544             @ResponseCode(code = 201, condition = "FlowSpec created successfully"),
545             @ResponseCode(code = 400, condition = "Invalid flowspec configuration"),
546             @ResponseCode(code = 404, condition = "The container is not found"),
547             @ResponseCode(code = 409, condition = "Container Entry already exists"),
548             @ResponseCode(code = 500, condition = "Failed to create Flow specifications. Failure Reason included in HTTP Error response") })
549     public Response createFlowSpec(@Context UriInfo uriInfo,
550             @PathParam(value = "container") String container,
551             @PathParam(value = "flowspec") String flowspec,
552             @TypeHint(ContainerFlowConfig.class) ContainerFlowConfig containerFlowConfig) {
553
554         handleAdminAuthorization(getUserName());
555         handleForbiddenOnDefault(container);
556
557         handleContainerNotExists(container);
558         handleNameMismatch(containerFlowConfig.getName(), flowspec);
559
560         IContainerManager containerManager = getContainerManager();
561         List<ContainerFlowConfig> list = new ArrayList<ContainerFlowConfig>();
562         list.add(containerFlowConfig);
563         Status status = containerManager.addContainerFlows(container, list);
564         if (status.isSuccess()) {
565             NorthboundUtils.auditlog("Flow Spec", username, "added", containerFlowConfig.getName());
566             return Response.created(uriInfo.getRequestUri()).build();
567         }
568         return NorthboundUtils.getResponse(status);
569     }
570
571     /**
572      * Remove flowspec from a container
573      *
574      * @param name
575      *            name of the flowspec (eg. telnet)
576      * @param container
577      *            name of the Container (eg. black)
578      * @return Response as dictated by the HTTP Response code
579      *
580      * <pre>
581      *
582      * Example:
583      *
584      * Request URL:
585      * http://localhost:8080/controller/nb/v2/containermanager/container/black/flowspec/telnet
586      *
587      * </pre>
588      */
589     @Path("/container/{container}/flowspec/{flowspec}")
590     @DELETE
591     @StatusCodes({
592             @ResponseCode(code = 204, condition = "Flow Spec deleted successfully"),
593             @ResponseCode(code = 400, condition = "Invalid flowspec configuration"),
594             @ResponseCode(code = 404, condition = "Container or Container Entry not found"),
595             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
596             @ResponseCode(code = 500, condition = "Failed to delete Flowspec. Failure Reason included in HTTP Error response"),
597             @ResponseCode(code = 503, condition = "One or more of Controller service is unavailable") })
598     public Response removeFlowSpec(@PathParam(value = "container") String container,
599             @PathParam(value = "flowspec") String flowspec) {
600
601         handleAdminAuthorization(getUserName());
602         handleForbiddenOnDefault(container);
603
604         handleContainerNotExists(container);
605
606         IContainerManager containerManager = getContainerManager();
607         Set<String> set = new HashSet<String>();
608         set.add(flowspec);
609         Status status = containerManager.removeContainerFlows(container, set);
610         if (status.isSuccess()) {
611             NorthboundUtils.auditlog("Flow Spec", username, "added", flowspec);
612             return Response.noContent().build();
613         }
614         return NorthboundUtils.getResponse(status);
615     }
616
617     /**
618      * Add node connectors to a container
619      *
620      * @param container
621      *            name of the container (eg. green)
622      * @param list
623      *            The list of strings each representing a node connector in the form "<Port Type>|<Port id>@<Node Type>|<Node id>", as "OF|1@OF|00:00:00:ab:00:00:00:01"
624      * @return response as dictated by the HTTP Status code
625      *
626      * <pre>
627      *
628      * Example:
629      *
630      * Request URL:
631      * http://localhost:8080/controller/nb/v2/containermanager/container/green/nodeconnector
632      *
633      * Request body in XML:
634      * &lt;nodeConnectors&gt;
635      *     &lt;nodeConnectors&gt;OF|1@OF|00:00:00:00:00:00:00:01&lt;/nodeConnectors&gt;
636      *     &lt;nodeConnectors&gt;OF|2@OF|00:00:00:00:00:00:00:01&lt;/nodeConnectors&gt;
637      *     &lt;nodeConnectors&gt;OF|3@OF|00:00:00:00:00:00:00:22&lt;/nodeConnectors&gt;
638      *     &lt;nodeConnectors&gt;OF|4@OF|00:00:00:00:00:00:00:22&lt;/nodeConnectors&gt;
639      * &lt;/nodeConnectors&gt;
640      *
641      * Request body in JSON:
642      * {
643      *    "nodeConnectors" : [
644      *       "OF|1@OF|00:00:00:00:00:00:00:01",
645      *       "OF|2@OF|00:00:00:00:00:00:00:01",
646      *       "OF|3@OF|00:00:00:00:00:00:00:22",
647      *       "OF|4@OF|00:00:00:00:00:00:00:22"
648      *    ]
649      * }
650      *
651      * </pre>
652      */
653     @Path("/container/{container}/nodeconnector/")
654     @PUT
655     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
656     @TypeHint(Response.class)
657     @StatusCodes({
658             @ResponseCode(code = 200, condition = "NodeConnectors added successfully"),
659             @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
660             @ResponseCode(code = 403, condition = "Operation forbidden on default"),
661             @ResponseCode(code = 404, condition = "The Container is not found"),
662             @ResponseCode(code = 409, condition = "Container Entry already exists"),
663             @ResponseCode(code = 500, condition = "Failed to create nodeconnectors. Failure Reason included in HTTP Error response") })
664     public Response addNodeConnectors(@PathParam(value = "container") String container,
665             @TypeHint(StringList.class) StringList list) {
666
667         handleAdminAuthorization(getUserName());
668         handleForbiddenOnDefault(container);
669         handleContainerNotExists(container);
670
671         IContainerManager containerManager = getContainerManager();
672         Status status = containerManager.addContainerEntry(container, list.getList());
673         if (status.isSuccess()) {
674             NorthboundUtils.auditlog("Node ", username, "added", " Ports:" + list.getList());
675         }
676         return NorthboundUtils.getResponse(status);
677     }
678
679     /**
680      * Remove node connectors from a container
681      *
682      * @param container
683      *            name of the container (eg. red)
684      * @param list
685      *            The list of strings each representing a node connector in the form "<Port Type>|<Port id>@<Node Type>|<Node id>", as "OF|1@OF|00:00:00:ab:00:00:00:01"
686      * @return response as dictated by the HTTP Status code
687      *
688      *         <pre>
689      *
690      * Example:
691      *
692      * Request URL:
693      * http://localhost:8080/controller/nb/v2/containermanager/container/red/nodeconnector
694      *
695      * Request body in XML:
696      * &lt;nodeConnectors&gt;
697      *     &lt;nodeConnectors&gt;OF|1@OF|00:00:00:00:00:00:00:01&lt;/nodeConnectors&gt;
698      *     &lt;nodeConnectors&gt;OF|2@OF|00:00:00:00:00:00:00:01&lt;/nodeConnectors&gt;
699      *     &lt;nodeConnectors&gt;OF|3@OF|00:00:00:00:00:00:00:22&lt;/nodeConnectors&gt;
700      *     &lt;nodeConnectors&gt;OF|4@OF|00:00:00:00:00:00:00:22&lt;/nodeConnectors&gt;
701      * &lt;/nodeConnectors&gt;
702      *
703      * Request body in JSON:
704      * {
705      *    "nodeConnectors" : [
706      *       "OF|1@OF|00:00:00:00:00:00:00:01",
707      *       "OF|2@OF|00:00:00:00:00:00:00:01",
708      *       "OF|3@OF|00:00:00:00:00:00:00:22",
709      *       "OF|4@OF|00:00:00:00:00:00:00:22"
710      *       ]
711      * }
712      *
713      * </pre>
714      */
715     @Path("/container/{container}/nodeconnector/")
716     @DELETE
717     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
718     @StatusCodes({
719             @ResponseCode(code = 204, condition = "Container Entry deleted successfully"),
720             @ResponseCode(code = 400, condition = "Invalid Container Entry configuration"),
721             @ResponseCode(code = 404, condition = "The Container is not found"),
722             @ResponseCode(code = 406, condition = "Cannot operate on Default Container when other Containers are active"),
723             @ResponseCode(code = 500, condition = "Failed to delete node connector. Failure Reason included in HTTP Error response") })
724     public Response removeNodeConnectors(@PathParam(value = "container") String container,
725             @TypeHint(StringList.class) StringList portList) {
726
727         handleAdminAuthorization(getUserName());
728         handleForbiddenOnDefault(container);
729         handleContainerNotExists(container);
730
731         IContainerManager containerManager = getContainerManager();
732         Status status = containerManager.removeContainerEntry(container, portList.getList());
733         if (status.isSuccess()) {
734             NorthboundUtils.auditlog("Node", username, "removed", " Ports:" + portList.getList());
735             return Response.noContent().build();
736         }
737         return NorthboundUtils.getResponse(status);
738     }
739
740     /*
741      * Check If the function is not allowed on default container, Throw a
742      * ResourceForbiddenException exception if forbidden
743      */
744     private void handleForbiddenOnDefault(String container) {
745         if (container.equalsIgnoreCase(GlobalConstants.DEFAULT.toString())) {
746             throw new ResourceForbiddenException(RestMessages.NODEFAULT.toString() + ": " + container);
747         }
748     }
749
750     /*
751      * Check if container exists, Throw a ResourceNotFoundException exception if it
752      * does not exist
753      */
754     private void handleContainerNotExists(String container) {
755         IContainerManager containerManager = getContainerManager();
756         if (!containerManager.doesContainerExist(container)) {
757             throw new ResourceNotFoundException(RestMessages.NOCONTAINER.toString() + ": " + container);
758         }
759     }
760
761     private void handleContainerExists(String container) {
762         IContainerManager containerManager = getContainerManager();
763         if (containerManager.doesContainerExist(container)) {
764             throw new ResourceConflictException(RestMessages.RESOURCECONFLICT.toString() + ": " + container);
765         }
766     }
767
768     private void handleAdminAuthorization(String userName) {
769         IUserManager usrMgr = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
770
771         UserLevel level = usrMgr.getUserLevel(userName);
772         if (level.ordinal() <= UserLevel.NETWORKADMIN.ordinal()) {
773             return;
774         }
775
776         throw new UnauthorizedException("User is not authorized to perform this operation");
777     }
778
779     private void handleNetworkAuthorization(String userName) {
780         IUserManager usrMgr = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
781
782         UserLevel level = usrMgr.getUserLevel(userName);
783         if (level.ordinal() <= UserLevel.NETWORKOPERATOR.ordinal()) {
784             return;
785         }
786         throw new UnauthorizedException("User is not authorized to perform this operation");
787     }
788
789     private void handleContainerAuthorization(String container, String userName) {
790         IContainerAuthorization auth = (IContainerAuthorization) ServiceHelper.getGlobalInstance(
791                 IContainerAuthorization.class, this);
792
793         UserLevel level = auth.getUserLevel(userName);
794         if (level.ordinal() <= UserLevel.NETWORKOPERATOR.ordinal()) {
795             return;
796         }
797
798         Privilege current = (auth == null) ? Privilege.NONE : auth.getResourcePrivilege(userName, container);
799
800         if (current.ordinal() > Privilege.NONE.ordinal()) {
801             return;
802         }
803         throw new UnauthorizedException("User is not authorized to perform this operation");
804     }
805
806 }