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