OpenDaylight Controller functional modules.
[controller.git] / opendaylight / northbound / switchmanager / src / main / java / org / opendaylight / controller / switchmanager / northbound / SwitchNorthbound.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.switchmanager.northbound;
11
12 import java.util.ArrayList;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
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.MediaType;
27 import javax.ws.rs.core.Response;
28 import org.codehaus.enunciate.jaxrs.ResponseCode;
29 import org.codehaus.enunciate.jaxrs.StatusCodes;
30 import org.codehaus.enunciate.jaxrs.TypeHint;
31 import org.opendaylight.controller.containermanager.IContainerManager;
32 import org.opendaylight.controller.northbound.commons.RestMessages;
33 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
34 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
35 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
36 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
37 import org.opendaylight.controller.sal.core.MacAddress;
38 import org.opendaylight.controller.sal.core.Node;
39 import org.opendaylight.controller.sal.core.NodeConnector;
40 import org.opendaylight.controller.sal.core.Property;
41 import org.opendaylight.controller.sal.utils.GlobalConstants;
42 import org.opendaylight.controller.sal.utils.ServiceHelper;
43 import org.opendaylight.controller.sal.utils.Status;
44 import org.opendaylight.controller.switchmanager.ISwitchManager;
45
46 /**
47  * The class provides Northbound REST APIs to access the nodes, node connectors
48  * and their properties.
49  * 
50  */
51
52 @Path("/")
53 public class SwitchNorthbound {
54
55         private ISwitchManager getIfSwitchManagerService(String containerName) {
56                 IContainerManager containerManager = (IContainerManager) ServiceHelper
57                 .getGlobalInstance(IContainerManager.class, this);
58                 if (containerManager == null) {
59                         throw new ServiceUnavailableException("Container "
60                                         + RestMessages.SERVICEUNAVAILABLE.toString());
61                 }
62
63                 boolean found = false;
64                 List<String> containerNames = containerManager.getContainerNames();
65                 for (String cName : containerNames) {
66                         if (cName.trim().equalsIgnoreCase(containerName.trim())) {
67                                 found = true;
68                         }
69                 }
70
71                 if (found == false) {
72                         throw new ResourceNotFoundException(containerName + " "
73                                         + RestMessages.NOCONTAINER.toString());
74                 }
75
76                 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(
77                                 ISwitchManager.class, containerName, this);
78
79                 if (switchManager == null) {
80                         throw new ServiceUnavailableException("Switch Manager "
81                                         + RestMessages.SERVICEUNAVAILABLE.toString());
82                 }
83
84                 return switchManager;
85         }
86
87         /**
88          * 
89          * Retrieve a list of all the nodes and their properties in the network
90          * 
91          * @param containerName The container for which we want to retrieve the list
92          * @return A list of Pair each pair represents a
93          *         {@link org.opendaylight.controller.sal.core.Node} and Set of
94          *         {@link org.opendaylight.controller.sal.core.Property} attached to
95          *         it.
96          */
97         @Path("/{containerName}/nodes")
98         @GET
99         @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
100         @TypeHint(Nodes.class)
101         @StatusCodes( {
102                 @ResponseCode(code = 200, condition = "Operation successful"),
103                 @ResponseCode(code = 404, condition = "The containerName is not found"),
104                 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
105                 public Nodes getNodes(
106                                 @PathParam("containerName") String containerName) {
107                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
108                 if (switchManager == null) {
109                         throw new ServiceUnavailableException("Switch Manager "
110                                         + RestMessages.SERVICEUNAVAILABLE.toString());
111                 }
112
113                 List<NodeProperties> res = new ArrayList<NodeProperties>();
114                 Set<Node> nodes = switchManager.getNodes();
115                 if (nodes == null) {
116                         return null;
117                 }
118
119                 byte[] controllerMac = switchManager.getControllerMAC();
120                 for (Node node : nodes) {
121                         Map<String, Property> propMap = switchManager.getNodeProps(node);
122                         if (propMap == null) {
123                                 continue;
124                         }
125                         Set<Property> props = new HashSet<Property>(propMap.values());
126                         
127                         byte[] nodeMac = switchManager.getNodeMAC(node);
128                         Property macAddr = new MacAddress(controllerMac, nodeMac);
129                         props.add(macAddr);
130                         
131                         NodeProperties nodeProps = new NodeProperties(node, props);
132                         res.add(nodeProps);
133                 }
134
135                 return new Nodes(res);
136         }
137
138     /**
139      * Add a Name/Tier property to a node
140      *
141      * @param containerName Name of the Container
142      * @param nodeType Type of the node being programmed
143      * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
144      * @param propName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
145      * @param propValue Value of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
146      * @return Response as dictated by the HTTP Response Status code
147      */
148
149     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propName}/{propValue}")
150     @PUT
151     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
152     @TypeHint(Response.class)
153     @StatusCodes( {
154             @ResponseCode(code = 200, condition = "Operation successful"),
155             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
156             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
157     public Response addNodeProperty(@PathParam("containerName") String containerName,
158             @PathParam("nodeType") String nodeType,
159             @PathParam("nodeId") String nodeId,
160             @PathParam("propName") String propName,
161             @PathParam("propValue") String propValue) {
162
163         handleDefaultDisabled(containerName);
164
165                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
166                 if (switchManager == null) {
167                         throw new ServiceUnavailableException("Switch Manager "
168                                         + RestMessages.SERVICEUNAVAILABLE.toString());
169                 }
170
171         handleNodeAvailability(containerName, nodeType, nodeId);
172                 Node node = Node.fromString(nodeId);
173         
174                 Property prop = switchManager.createProperty(propName, propValue);
175                 if (prop == null) {
176                         throw new ResourceNotFoundException(
177                                         RestMessages.INVALIDDATA.toString());
178                 }
179                 
180         switchManager.setNodeProp(node, prop);
181         return Response.status(Response.Status.CREATED).build();
182     }
183
184     /**
185      * Delete a property of a node
186      *
187      * @param containerName Name of the Container
188      * @param nodeType Type of the node being programmed
189      * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
190      * @param propertyName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
191      * @return Response as dictated by the HTTP Response Status code
192      */
193
194     @Path("/{containerName}/node/{nodeType}/{nodeId}/property/{propertyName}")
195     @DELETE
196     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
197     @StatusCodes( {
198             @ResponseCode(code = 200, condition = "Operation successful"),
199             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
200             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
201     public Response deleteNodeProperty(@PathParam("containerName") String containerName,
202             @PathParam("nodeType") String nodeType,
203             @PathParam("nodeId") String nodeId,
204             @PathParam("propertyName") String propertyName) {
205
206         handleDefaultDisabled(containerName);
207
208                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
209                 if (switchManager == null) {
210                         throw new ServiceUnavailableException("Switch Manager "
211                                         + RestMessages.SERVICEUNAVAILABLE.toString());
212                 }
213
214         handleNodeAvailability(containerName, nodeType, nodeId);
215                 Node node = Node.fromString(nodeId);
216         
217         Status ret = switchManager.removeNodeProp(node, propertyName);
218         if (ret.isSuccess()) {
219             return Response.ok().build();
220         }
221         throw new ResourceNotFoundException(ret.getDescription());
222     }
223
224         /**
225          * 
226          * Retrieve a list of all the node connectors and their properties in a given node
227          * 
228          * @param containerName The container for which we want to retrieve the list
229      * @param nodeType Type of the node being programmed
230      * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
231          * @return A List of Pair each pair represents a
232          *         {@link org.opendaylight.controller.sal.core.NodeConnector} and
233          *         its corresponding
234          *         {@link org.opendaylight.controller.sal.core.Property} attached to
235          *         it.
236          */
237         @Path("/{containerName}/node/{nodeType}/{nodeId}")
238         @GET
239         @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
240         @TypeHint(NodeConnectors.class)
241         @StatusCodes( {
242                 @ResponseCode(code = 200, condition = "Operation successful"),
243                 @ResponseCode(code = 404, condition = "The containerName is not found"),
244                 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
245                 public NodeConnectors getNodeConnectors(
246                                 @PathParam("containerName") String containerName,
247                     @PathParam("nodeType") String nodeType,
248                                 @PathParam("nodeId") String nodeId) {
249                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
250                 if (switchManager == null) {
251                         throw new ServiceUnavailableException("Switch Manager "
252                                         + RestMessages.SERVICEUNAVAILABLE.toString());
253                 }
254
255                 handleNodeAvailability(containerName, nodeType,nodeId);
256                 Node node = Node.fromString(nodeId);
257
258                 List<NodeConnectorProperties> res = new ArrayList<NodeConnectorProperties>();
259                 Set<NodeConnector> ncs = switchManager.getNodeConnectors(node);
260                 if (ncs == null) {
261                         return null;
262                 }
263
264                 for (NodeConnector nc : ncs) {
265                         Map<String, Property> propMap = switchManager.getNodeConnectorProps(nc);
266                         if (propMap == null) {
267                                 continue;
268                         }
269                         Set<Property> props = new HashSet<Property>(propMap.values());
270                         NodeConnectorProperties ncProps = new NodeConnectorProperties(nc, props);
271                         res.add(ncProps);
272                 }
273
274                 return new NodeConnectors(res);
275         }
276
277     /**
278      * Add a Name/Bandwidth property to a node connector
279      *
280      * @param containerName Name of the Container 
281      * @param nodeType Type of the node being programmed
282      * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
283      * @param nodeConnectorType Type of the node connector being programmed
284      * @param nodeConnectorId NodeConnector Identifier as specified by {@link org.opendaylight.controller.sal.core.NodeConnector}
285      * @param propName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
286      * @param propValue Value of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
287      * @return Response as dictated by the HTTP Response Status code
288      */
289
290     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propName}/{propValue}")
291     @PUT
292     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
293     @StatusCodes( {
294             @ResponseCode(code = 200, condition = "Operation successful"),
295             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
296             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
297     public Response addNodeConnectorProperty(@PathParam("containerName") String containerName,
298             @PathParam("nodeType") String nodeType,
299             @PathParam("nodeId") String nodeId,
300             @PathParam("nodeConnectorType") String nodeConnectorType,
301             @PathParam("nodeConnectorId") String nodeConnectorId,
302             @PathParam("propName") String propName,
303             @PathParam("propValue") String propValue) {
304
305         handleDefaultDisabled(containerName);
306
307                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
308                 if (switchManager == null) {
309                         throw new ServiceUnavailableException("Switch Manager "
310                                         + RestMessages.SERVICEUNAVAILABLE.toString());
311                 }
312
313                 handleNodeAvailability(containerName, nodeType, nodeId);
314                 Node node = Node.fromString(nodeId);
315
316                 handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
317                 NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorId, node);
318         
319                 Property prop = switchManager.createProperty(propName, propValue);
320                 if (prop == null) {
321                         throw new ResourceNotFoundException(
322                                         RestMessages.INVALIDDATA.toString());
323                 }
324                 
325                 Status ret = switchManager.addNodeConnectorProp(nc, prop);
326         if (ret.isSuccess()) {
327             return Response.status(Response.Status.CREATED).build();
328         }
329         throw new InternalServerErrorException(ret.getDescription());
330     }
331
332     /**
333      * Delete a property of a node connector
334      *
335      * @param containerName Name of the Container
336      * @param nodeType Type of the node being programmed
337      * @param nodeId Node Identifier as specified by {@link org.opendaylight.controller.sal.core.Node}
338      * @param nodeConnectorType Type of the node connector being programmed
339      * @param nodeConnectorId NodeConnector Identifier as specified by {@link org.opendaylight.controller.sal.core.NodeConnector}
340      * @param propertyName Name of the Property specified by {@link org.opendaylight.controller.sal.core.Property} and its extended classes
341      * @return Response as dictated by the HTTP Response Status code
342      */
343
344     @Path("/{containerName}/nodeconnector/{nodeType}/{nodeId}/{nodeConnectorType}/{nodeConnectorId}/property/{propertyName}")
345     @DELETE
346     @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
347     @StatusCodes( {
348             @ResponseCode(code = 200, condition = "Operation successful"),
349             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
350             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
351     public Response deleteNodeConnectorProperty(@PathParam("containerName") String containerName,
352             @PathParam("nodeType") String nodeType,
353             @PathParam("nodeId") String nodeId,
354             @PathParam("nodeConnectorType") String nodeConnectorType,
355             @PathParam("nodeConnectorId") String nodeConnectorId,
356             @PathParam("propertyName") String propertyName) {
357
358         handleDefaultDisabled(containerName);
359
360                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
361                 if (switchManager == null) {
362                         throw new ServiceUnavailableException("Switch Manager "
363                                         + RestMessages.SERVICEUNAVAILABLE.toString());
364                 }
365
366                 handleNodeAvailability(containerName, nodeType, nodeId);
367                 Node node = Node.fromString(nodeId);
368                 
369                 handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
370                 NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorId, node);
371         
372         Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
373         if (ret.isSuccess()) {
374             return Response.ok().build();
375         }
376         throw new ResourceNotFoundException(ret.getDescription());
377     }
378
379 /*    *//**
380      * Retrieve a list of Span ports that were configured previously.
381      *
382      * @param containerName Name of the Container 
383      * @return list of {@link org.opendaylight.controller.switchmanager.SpanConfig} resources
384      *//*
385         @Path("/span-config/{containerName}")
386         @GET
387         @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
388         @StatusCodes( {
389                 @ResponseCode(code = 200, condition = "Operation successful"),
390                 @ResponseCode(code = 404, condition = "The containerName is not found"),
391                 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
392                 public List<SpanConfig> getSpanConfigList(@PathParam("containerName") String containerName) {
393                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
394                 if (switchManager == null) {
395                         throw new ServiceUnavailableException("Switch Manager "
396                                         + RestMessages.SERVICEUNAVAILABLE.toString());
397                 }
398
399                 return switchManager.getSpanConfigList();
400         }
401
402     *//**
403      * Add a span configuration
404      *
405      * @param containerName Name of the Container 
406      * @param config {@link org.opendaylight.controller.switchmanager.SpanConfig} in JSON or XML format
407      * @return Response as dictated by the HTTP Response Status code
408      *//*
409         @Path("/span-config/{containerName}")
410         @PUT
411         @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
412         @StatusCodes( {
413                 @ResponseCode(code = 200, condition = "Operation successful"),
414                 @ResponseCode(code = 404, condition = "The containerName is not found"),
415                 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
416                 public Response addSpanConfig(@PathParam("containerName") String containerName,
417                     @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
418                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
419                 if (switchManager == null) {
420                         throw new ServiceUnavailableException("Switch Manager "
421                                         + RestMessages.SERVICEUNAVAILABLE.toString());
422                 }
423
424                 String ret = switchManager.addSpanConfig(config.getValue());
425         if (ret.equals(ReturnString.SUCCESS.toString())) {
426             return Response.status(Response.Status.CREATED).build();
427         }
428         throw new InternalServerErrorException(ret);
429         }
430
431     *//**
432      * Delete a span configuration
433      *
434      * @param containerName Name of the Container 
435      * @param config {@link org.opendaylight.controller.switchmanager.SpanConfig} in JSON or XML format
436      * @return Response as dictated by the HTTP Response Status code
437      *//*
438         @Path("/span-config/{containerName}")
439         @DELETE
440         @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
441         @StatusCodes( {
442                 @ResponseCode(code = 200, condition = "Operation successful"),
443                 @ResponseCode(code = 404, condition = "The containerName is not found"),
444                 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
445                 public Response deleteSpanConfig(@PathParam("containerName") String containerName,
446                     @TypeHint(SubnetConfig.class) JAXBElement<SpanConfig> config) {
447                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
448                 if (switchManager == null) {
449                         throw new ServiceUnavailableException("Switch Manager "
450                                         + RestMessages.SERVICEUNAVAILABLE.toString());
451                 }
452
453                 String ret = switchManager.removeSpanConfig(config.getValue());
454         if (ret.equals(ReturnString.SUCCESS.toString())) {
455             return Response.ok().build();
456         }
457         throw new ResourceNotFoundException(ret);
458         }
459 */
460     
461     /**
462      * Save the current switch configurations
463      *
464      * @param containerName Name of the Container 
465      * @return Response as dictated by the HTTP Response Status code
466      */
467         @Path("/{containerName}/switch-config")
468         @POST
469         @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
470         @StatusCodes( {
471                 @ResponseCode(code = 200, condition = "Operation successful"),
472                 @ResponseCode(code = 404, condition = "The containerName is not found"),
473                 @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
474                 public Response saveSwitchConfig(@PathParam("containerName") String containerName) {
475                 ISwitchManager switchManager = (ISwitchManager) getIfSwitchManagerService(containerName);
476                 if (switchManager == null) {
477                         throw new ServiceUnavailableException("Switch Manager "
478                                         + RestMessages.SERVICEUNAVAILABLE.toString());
479                 }
480
481                 Status ret = switchManager.saveSwitchConfig();
482         if (ret.isSuccess()) {
483             return Response.ok().build();
484         }
485         throw new InternalServerErrorException(ret.getDescription());
486         }
487
488     private void handleDefaultDisabled(String containerName) {
489         IContainerManager containerManager = (IContainerManager) ServiceHelper
490                 .getGlobalInstance(IContainerManager.class, this);
491         if (containerManager == null) {
492             throw new InternalServerErrorException(RestMessages.INTERNALERROR
493                     .toString());
494         }
495         if (containerName.equals(GlobalConstants.DEFAULT.toString())
496                 && containerManager.hasNonDefaultContainer()) {
497             throw new ResourceConflictException(RestMessages.DEFAULTDISABLED
498                     .toString());
499         }
500     }
501
502     private Node handleNodeAvailability(String containerName, String nodeType,
503                 String nodeId) {
504
505         Node node = Node.fromString(nodeType, nodeId);
506         if (node == null) {
507                 throw new ResourceNotFoundException(nodeId + " : "
508                                 + RestMessages.NONODE.toString());
509         }
510
511         ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
512                         ISwitchManager.class, containerName, this);
513
514         if (sm == null) {
515                 throw new ServiceUnavailableException("Switch Manager "
516                                 + RestMessages.SERVICEUNAVAILABLE.toString());
517         }
518
519         if (!sm.getNodes().contains(node)) {
520                 throw new ResourceNotFoundException(node.toString() + " : "
521                                 + RestMessages.NONODE.toString());
522         }
523         return node;
524     }
525
526         private void handleNodeConnectorAvailability(String containerName,
527                         Node node, String nodeConnectorType, String nodeConnectorId) {
528
529                 NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType,
530                                 nodeConnectorId, node);
531                 if (nc == null) {
532                         throw new ResourceNotFoundException(nc + " : "
533                                         + RestMessages.NORESOURCE.toString());
534                 }
535                 
536                 ISwitchManager sm = (ISwitchManager) ServiceHelper.getInstance(
537                                 ISwitchManager.class, containerName, this);
538
539                 if (sm == null) {
540                         throw new ServiceUnavailableException("Switch Manager "
541                                         + RestMessages.SERVICEUNAVAILABLE.toString());
542                 }
543
544                 if (!sm.getNodeConnectors(node).contains(nc)) {
545                         throw new ResourceNotFoundException(nc.toString() + " : "
546                                         + RestMessages.NORESOURCE.toString());
547                 }
548         }
549 }