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