2 * Copyright (C) 2014 Red Hat, Inc. and others
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 * Authors : Madhu Venugopal, Brent Salisbury, Dave Tucker
10 package org.opendaylight.ovsdb.northbound;
12 import java.util.List;
15 import javax.ws.rs.Consumes;
16 import javax.ws.rs.DELETE;
17 import javax.ws.rs.GET;
18 import javax.ws.rs.POST;
19 import javax.ws.rs.PUT;
20 import javax.ws.rs.Path;
21 import javax.ws.rs.PathParam;
22 import javax.ws.rs.core.Context;
23 import javax.ws.rs.core.MediaType;
24 import javax.ws.rs.core.Response;
25 import javax.ws.rs.core.SecurityContext;
26 import javax.ws.rs.core.UriInfo;
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.northbound.commons.RestMessages;
32 import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
33 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
34 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
35 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
36 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
37 import org.opendaylight.controller.sal.authorization.Privilege;
38 import org.opendaylight.controller.sal.core.Node;
39 import org.opendaylight.controller.sal.utils.ServiceHelper;
40 import org.opendaylight.controller.sal.utils.Status;
41 import org.opendaylight.controller.sal.utils.StatusCode;
42 import org.opendaylight.ovsdb.lib.notation.UUID;
43 import org.opendaylight.ovsdb.lib.table.Table;
44 import org.opendaylight.ovsdb.lib.table.Tables;
45 import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
46 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
51 * OVSDB Northbound REST API.<br>
52 * This class provides REST APIs to Create, Read, Update and Delete OVSDB Row in any of the ovsdb table
53 * database one at a time. The JSON used to create rows is in the same format as the OVSDB JSON-RPC messages.
54 * This format is documented in the <a href="http://openvswitch.org/ovs-vswitchd.conf.db.5.pdf">OVSDB Schema</a>
55 * and in <a href="http://tools.ietf.org/rfc/rfc7047.txt">RFC 7047</a>.
59 * Authentication scheme : <b>HTTP Basic</b><br>
60 * Authentication realm : <b>opendaylight</b><br>
61 * Transport : <b>HTTP and HTTPS</b><br>
63 * HTTPS Authentication is disabled by default.
67 public class OVSDBNorthbound {
68 protected static final Logger logger = LoggerFactory.getLogger(OVSDBNorthbound.class);
71 private UriInfo _uriInfo;
72 private String username;
75 public void setSecurityContext(SecurityContext context) {
76 if (context != null && context.getUserPrincipal() != null) {
77 username = context.getUserPrincipal().getName();
81 protected String getUserName() {
85 private void handleNameMismatch(String name, String nameinURL) {
86 if (name == null || nameinURL == null) {
87 throw new BadRequestException(RestMessages.INVALIDDATA.toString() + " : Name is null");
90 if (name.equalsIgnoreCase(nameinURL)) {
93 throw new ResourceConflictException(RestMessages.INVALIDDATA.toString()
94 + " : Table Name in URL does not match the row name in request body");
97 private String getOVSTableName(String tableName) {
98 List<Table> tables = Tables.getTables();
99 for (Table table : tables) {
100 if (table.getTableName().getName().equalsIgnoreCase(tableName)) {
101 return table.getTableName().getName();
104 // TODO Auto-generated method stub
111 * @param nodeType type of node e.g OVS
112 * @param nodeId ID of the node
113 * @param tableName name of the OVSDB table
114 * @param row the {@link OVSDBRow} Row that is being inserted
116 * @return Response as dictated by the HTTP Response Status code
121 * Create a Bridge Row:
125 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows
132 * "datapath_type": "OPENFLOW"
143 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows
147 * "parent_uuid": "b01cd26b-9c63-4216-8cf2-55f7087adab1",
153 * "00:00:00:00:00:01"
165 * Create an Interface Row:
169 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows
173 * "parent_uuid": "c7b54c9b-9b25-4801-a81d-d7bc489d4840",
179 * "00:00:bb:bb:00:01"
181 * "admin_state": "up"
192 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows
199 * "ca_cert": "ca_cert",
200 * "bootstrap_ca_cert": true,
201 * "certificate": "pieceofpaper",
202 * "private_key": "private"
209 * Create an sFlow Row:
213 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows
217 * "parent_uuid": "6b3072ba-a120-4db9-82f8-a8ce4eae6942",
238 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows
242 * "parent_uuid": "b109dbcf-47bb-4121-b244-e623b3421d6e",
245 * "type": "linux-htb"
252 * Create a Queue Row:
256 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows
259 * "parent_uuid": "b16eae7d-7e97-46d2-95d1-333d1de4a3d7",
272 * Create a Netflow Row:
276 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows
280 * "parent_uuid": "b01cd26b-9c63-4216-8cf2-55f7087adab1",
286 * "192.168.1.102:9998"
289 * "active_timeout": "0"
296 * Create a Manager Row:
300 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows
304 * "parent_uuid": "8d3fb89b-5fac-4631-a990-f5a4e7f5383a",
307 * "target": "a_string",
308 * "is_connected": true,
316 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows")
318 @StatusCodes({ @ResponseCode(code = 201, condition = "Row Inserted successfully"),
319 @ResponseCode(code = 400, condition = "Invalid data passed"),
320 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
321 @Consumes({ MediaType.APPLICATION_JSON})
322 public Response addRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
323 @PathParam("tableName") String tableName, @TypeHint(OVSDBRow.class) OVSDBRow row) {
325 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
326 throw new UnauthorizedException("User is not authorized to perform this operation");
329 String ovsTableName = getOVSTableName(tableName);
330 if (ovsTableName == null) {
331 Status status = new Status(StatusCode.NOTFOUND, "Table "+tableName+" is not currently supported");
332 return NorthboundUtils.getResponse(status);
335 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class,
337 if (ovsdbTable == null) {
338 throw new ServiceUnavailableException("OVS Configuration Service " + RestMessages.SERVICEUNAVAILABLE.toString());
341 if (row != null && row.getRow() != null) {
342 handleNameMismatch(tableName, row.getRow().getTableName().getName());
343 Node node = Node.fromString(nodeType, nodeId);
344 StatusWithUuid statusWithUUID = ovsdbTable.insertRow(node, ovsTableName, row.getParent_uuid(), row.getRow());
346 if (statusWithUUID.isSuccess()) {
347 UUID uuid = statusWithUUID.getUuid();
348 return Response.status(Response.Status.CREATED)
349 .header("Location", String.format("%s/%s", _uriInfo.getAbsolutePath().toString(),
351 .entity(uuid.toString())
354 return NorthboundUtils.getResponse(statusWithUUID);
357 return Response.status(Response.Status.BAD_REQUEST).build();
363 * @param nodeType type of node e.g OVS
364 * @param nodeId ID of the node
365 * @param tableName name of the ovsdb table
366 * @param rowUuid UUID of the row being read
368 * @return Row corresponding to the UUID.
374 * Get a specific Bridge Row:
375 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows/6f4c602c-026f-4390-beea-d50d6d448100
377 * Get a specific Port Row:
378 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows/6f4c602c-026f-4390-beea-d50d6d448100
380 * Get a specific Interface Row:
381 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows/6f4c602c-026f-4390-beea-d50d6d448100
383 * Get a specific Controller Row:
384 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/controller/rows/6f4c602c-026f-4390-beea-d50d6d448100
386 * Get a specific SSL Row:
387 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows/6f4c602c-026f-4390-beea-d50d6d448100
389 * Get a specific sFlow Row:
390 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
392 * Get a specific QoS Row:
393 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows/6f4c602c-026f-4390-beea-d50d6d448100
395 * Get a specific Queue Row:
396 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows/6f4c602c-026f-4390-beea-d50d6d448100
398 * Get a specific Netflow Row:
399 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
401 * Get a specific Manager Row:
402 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows/6f4c602c-026f-4390-beea-d50d6d448100
406 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{rowUuid}")
408 @StatusCodes({ @ResponseCode(code = 200, condition = "Row Updated successfully"),
409 @ResponseCode(code = 400, condition = "Invalid data passed"),
410 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
411 @Consumes({ MediaType.APPLICATION_JSON})
412 @TypeHint(OVSDBRow.class)
413 public OVSDBRow getRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
414 @PathParam("tableName") String tableName, @PathParam("rowUuid") String rowUuid) {
416 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
417 throw new UnauthorizedException("User is not authorized to perform this operation");
420 String ovsTableName = getOVSTableName(tableName);
421 if (ovsTableName == null) return null;
423 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class,
425 if (ovsdbTable == null) {
426 throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
429 Node node = Node.fromString(nodeType, nodeId);
432 row = ovsdbTable.getRow(node, ovsTableName, rowUuid);
433 } catch (Exception e) {
434 throw new BadRequestException(e.getMessage());
436 return new OVSDBRow(null, row);
440 * Read all Rows of a table
442 * @param nodeType type of node e.g OVS
443 * @param nodeId ID of the node
444 * @param tableName name of the ovsdb table
446 * @return All the Rows of a table
452 * Get all Bridge Rows:
453 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows
456 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows
458 * Get all Interface Rows:
459 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows
461 * Get all Controller Rows:
462 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/controller/rows
465 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows
467 * Get all sFlow Rows:
468 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows
471 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows
473 * Get all Queue Rows:
474 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows
476 * Get all Netflow Rows:
477 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows
479 * Get all Manager Rows:
480 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows
482 * Get all Open vSwitch Rows:
483 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/open_vswitch/rows
487 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows")
489 @StatusCodes({ @ResponseCode(code = 200, condition = "Row Updated successfully"),
490 @ResponseCode(code = 400, condition = "Invalid data passed"),
491 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
492 @Consumes({ MediaType.APPLICATION_JSON})
493 @TypeHint(OVSDBRows.class)
494 public OVSDBRows getAllRows(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
495 @PathParam("tableName") String tableName) {
496 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
497 throw new UnauthorizedException("User is not authorized to perform this operation");
500 String ovsTableName = getOVSTableName(tableName);
501 if (ovsTableName == null) return null;
503 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class,
505 if (ovsdbTable == null) {
506 throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
509 Node node = Node.fromString(nodeType, nodeId);
510 Map<String, Table<?>> rows = null;
512 rows = ovsdbTable.getRows(node, ovsTableName);
513 } catch (Exception e) {
514 throw new BadRequestException(e.getMessage());
516 return new OVSDBRows(rows);
522 * @param nodeType type of node e.g OVS
523 * @param nodeId ID of the node
524 * @param tableName name of the ovsdb table
525 * @param rowUuid UUID of the row being updated
526 * @param row the {@link OVSDBRow} Row that is being updated
528 * @return Response as dictated by the HTTP Response Status code
533 * Update the Bridge row to add a controller
537 * PUT http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows/b01cd26b-9c63-4216-8cf2-55f7087adab1
548 * "a566e8b4-fc38-499b-8623-6087d5b36b72"
558 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{rowUuid}")
560 @StatusCodes({ @ResponseCode(code = 200, condition = "Row Updated successfully"),
561 @ResponseCode(code = 400, condition = "Invalid data passed"),
562 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
563 @Consumes({ MediaType.APPLICATION_JSON})
564 public Response updateRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
565 @PathParam("tableName") String tableName, @PathParam("rowUuid") String rowUuid,
566 @TypeHint(OVSDBRow.class) OVSDBRow row) {
568 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
569 throw new UnauthorizedException("User is not authorized to perform this operation");
572 String ovsTableName = getOVSTableName(tableName);
573 if (ovsTableName == null) {
574 Status status = new Status(StatusCode.NOTFOUND, "Table "+tableName+" is not currently supported");
575 return NorthboundUtils.getResponse(status);
578 OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class,
580 if (ovsdbTable == null) {
581 throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
584 if (row != null && row.getRow() != null) {
585 handleNameMismatch(tableName, row.getRow().getTableName().getName());
586 Node node = Node.fromString(nodeType, nodeId);
587 Status status = ovsdbTable.updateRow(node, ovsTableName, row.getParent_uuid(), rowUuid, row.getRow());
588 return NorthboundUtils.getResponse(status);
590 return Response.status(Response.Status.BAD_REQUEST).build();
596 * @param nodeType type of node e.g OVS
597 * @param nodeId ID of the node
598 * @param tableName name of the ovsdb table
599 * @param uuid UUID of the Row to be removed
601 * @return Response as dictated by the HTTP Response Status code
607 * Delete a specific Bridge Row:
608 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows/6f4c602c-026f-4390-beea-d50d6d448100
610 * Delete a specific Port Row:
611 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows/6f4c602c-026f-4390-beea-d50d6d448100
613 * Delete a specific Interface Row:
614 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows/6f4c602c-026f-4390-beea-d50d6d448100
616 * Delete a specific Controller Row:
617 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/controller/rows/6f4c602c-026f-4390-beea-d50d6d448100
619 * Delete a specific SSL Row:
620 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows/6f4c602c-026f-4390-beea-d50d6d448100
622 * Delete a specific sFlow Row:
623 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
625 * Delete a specific QoS Row:
626 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows/6f4c602c-026f-4390-beea-d50d6d448100
628 * Delete a specific Queue Row:
629 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows/6f4c602c-026f-4390-beea-d50d6d448100
631 * Delete a specific Netflow Row:
632 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
634 * Delete a specific Manager Row:
635 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows/6f4c602c-026f-4390-beea-d50d6d448100
638 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{uuid}")
640 @StatusCodes({ @ResponseCode(code = 204, condition = "User Deleted Successfully"),
641 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
642 @ResponseCode(code = 404, condition = "The userName passed was not found"),
643 @ResponseCode(code = 500, condition = "Internal Server Error : Removal of user failed"),
644 @ResponseCode(code = 503, condition = "Service unavailable") })
645 public Response removeRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
646 @PathParam("tableName") String tableName, @PathParam("uuid") String uuid) {
647 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
648 throw new UnauthorizedException("User is not authorized to perform this operation");
651 String ovsTableName = getOVSTableName(tableName);
652 if (ovsTableName == null) {
653 Status status = new Status(StatusCode.NOTFOUND, "Table "+tableName+" is not currently supported");
654 return NorthboundUtils.getResponse(status);
657 OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
658 if (ovsdbTable == null) {
659 throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
661 Node node = Node.fromString(nodeType, nodeId);
662 Status status = ovsdbTable.deleteRow(node, ovsTableName, uuid);
663 if (status.isSuccess()) {
664 return Response.noContent().build();
666 return NorthboundUtils.getResponse(status);