2 * Copyright (c) 2014, 2015 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.northbound;
11 import java.io.IOException;
13 import java.util.concurrent.ExecutionException;
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.Produces;
23 import javax.ws.rs.core.Context;
24 import javax.ws.rs.core.MediaType;
25 import javax.ws.rs.core.Response;
26 import javax.ws.rs.core.SecurityContext;
27 import javax.ws.rs.core.UriInfo;
29 import org.codehaus.enunciate.jaxrs.ResponseCode;
30 import org.codehaus.enunciate.jaxrs.StatusCodes;
31 import org.codehaus.enunciate.jaxrs.TypeHint;
32 import org.opendaylight.controller.northbound.commons.RestMessages;
33 import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
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.ovsdb.plugin.api.Status;
39 import org.opendaylight.ovsdb.lib.OvsdbClient;
40 import org.opendaylight.ovsdb.lib.notation.Row;
41 import org.opendaylight.ovsdb.lib.notation.UUID;
42 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
43 import org.opendaylight.ovsdb.plugin.api.OvsVswitchdSchemaConstants;
44 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
45 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
46 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
47 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
50 import com.fasterxml.jackson.databind.JsonNode;
53 * OVSDB Northbound REST API.<br>
54 * This class provides REST APIs to Create, Read, Update and Delete OVSDB Row in any of the ovsdb table
55 * database one at a time. The JSON used to create rows is in the same format as the OVSDB JSON-RPC messages.
56 * This format is documented in the <a href="http://openvswitch.org/ovs-vswitchd.conf.db.5.pdf">OVSDB Schema</a>
57 * and in <a href="http://tools.ietf.org/rfc/rfc7047.txt">RFC 7047</a>.
61 * Authentication scheme : <b>HTTP Basic</b><br>
62 * Authentication realm : <b>opendaylight</b><br>
63 * Transport : <b>HTTP and HTTPS</b><br>
65 * HTTPS Authentication is disabled by default.
70 public class OvsdbNorthboundV2 {
73 private UriInfo _uriInfo;
74 private String username;
77 public void setSecurityContext(SecurityContext context) {
78 if (context != null && context.getUserPrincipal() != null) {
79 username = context.getUserPrincipal().getName();
83 protected String getUserName() {
88 * Create a Row for Open_vSwitch schema
90 * @param nodeType type of node e.g OVS
91 * @param nodeId ID of the node
92 * @param tableName name of the OVSDB table
93 * @param rowJson the {@link OvsdbRow} Row that is being inserted
95 * @return Response as dictated by the HTTP Response Status code
100 * Create a Bridge Row:
104 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows
111 * "datapath_type": "OPENFLOW"
122 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows
126 * "parent_uuid": "b01cd26b-9c63-4216-8cf2-55f7087adab1",
132 * "00:00:00:00:00:01"
144 * Create an Interface Row:
148 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows
152 * "parent_uuid": "c7b54c9b-9b25-4801-a81d-d7bc489d4840",
158 * "00:00:bb:bb:00:01"
160 * "admin_state": "up"
171 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows
178 * "ca_cert": "ca_cert",
179 * "bootstrap_ca_cert": true,
180 * "certificate": "pieceofpaper",
181 * "private_key": "private"
188 * Create an sFlow Row:
192 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows
196 * "parent_uuid": "6b3072ba-a120-4db9-82f8-a8ce4eae6942",
217 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows
221 * "parent_uuid": "b109dbcf-47bb-4121-b244-e623b3421d6e",
224 * "type": "linux-htb"
231 * Create a Queue Row:
235 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows
238 * "parent_uuid": "b16eae7d-7e97-46d2-95d1-333d1de4a3d7",
251 * Create a Netflow Row:
255 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows
259 * "parent_uuid": "b01cd26b-9c63-4216-8cf2-55f7087adab1",
265 * "192.168.1.102:9998"
268 * "active_timeout": "0"
275 * Create a Manager Row:
279 * POST http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows
283 * "parent_uuid": "8d3fb89b-5fac-4631-a990-f5a4e7f5383a",
286 * "target": "a_string",
287 * "is_connected": true,
293 * @throws IOException
294 * @throws ExecutionException
295 * @throws InterruptedException
298 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows")
300 @StatusCodes({ @ResponseCode(code = 201, condition = "Row Inserted successfully"),
301 @ResponseCode(code = 400, condition = "Invalid data passed"),
302 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
303 @Consumes({ MediaType.APPLICATION_JSON})
304 public Response addRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
305 @PathParam("tableName") String tableName, JsonNode rowJson) throws IOException, InterruptedException, ExecutionException {
307 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
308 throw new UnauthorizedException("User is not authorized to perform this operation");
311 OvsdbConfigurationService
312 ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
314 if (ovsdbTable == null) {
315 throw new ServiceUnavailableException("OVS Configuration Service " + RestMessages.SERVICEUNAVAILABLE.toString());
318 OvsdbConnectionService
319 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
320 Node node = connectionService.getNode(nodeId);
322 OvsdbClient client = connectionService.getConnection(node).getClient();
323 OvsdbRow localRow = OvsdbRow.fromJsonNode(client, OvsVswitchdSchemaConstants.DATABASE_NAME, rowJson);
324 String bckCompatibleTableName = this.getBackwardCompatibleTableName(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
326 if (localRow == null) {
327 return Response.status(Response.Status.BAD_REQUEST).build();
331 statusWithUuid = ovsdbTable.insertRow(node, bckCompatibleTableName, localRow.getParentUuid(), localRow.getRow());
333 if (statusWithUuid.isSuccess()) {
334 UUID uuid = statusWithUuid.getUuid();
335 return Response.status(Response.Status.CREATED)
336 .header("Location", String.format("%s/%s", _uriInfo.getAbsolutePath().toString(),
338 .entity(uuid.toString())
341 return NorthboundUtils.getResponse(
342 new org.opendaylight.controller.sal.utils.Status(
343 org.opendaylight.controller.sal.utils.StatusCode.SUCCESS));
349 * @param nodeType type of node e.g OVS
350 * @param nodeId ID of the node
351 * @param tableName name of the ovsdb table
352 * @param rowUuid UUID of the row being read
354 * @return Row corresponding to the UUID.
360 * Get a specific Bridge Row:
361 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows/6f4c602c-026f-4390-beea-d50d6d448100
363 * Get a specific Port Row:
364 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows/6f4c602c-026f-4390-beea-d50d6d448100
366 * Get a specific Interface Row:
367 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows/6f4c602c-026f-4390-beea-d50d6d448100
369 * Get a specific Controller Row:
370 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/controller/rows/6f4c602c-026f-4390-beea-d50d6d448100
372 * Get a specific SSL Row:
373 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows/6f4c602c-026f-4390-beea-d50d6d448100
375 * Get a specific sFlow Row:
376 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
378 * Get a specific QoS Row:
379 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows/6f4c602c-026f-4390-beea-d50d6d448100
381 * Get a specific Queue Row:
382 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows/6f4c602c-026f-4390-beea-d50d6d448100
384 * Get a specific Netflow Row:
385 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
387 * Get a specific Manager Row:
388 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows/6f4c602c-026f-4390-beea-d50d6d448100
392 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{rowUuid}")
394 @StatusCodes({ @ResponseCode(code = 200, condition = "Row Updated successfully"),
395 @ResponseCode(code = 400, condition = "Invalid data passed"),
396 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
397 @Produces({ MediaType.APPLICATION_JSON})
399 public Row getRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
400 @PathParam("tableName") String tableName, @PathParam("rowUuid") String rowUuid) {
402 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
403 throw new UnauthorizedException("User is not authorized to perform this operation");
406 OvsdbConfigurationService
407 ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
409 if (ovsdbTable == null) {
410 throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
413 OvsdbConnectionService
414 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
415 Node node = connectionService.getNode(nodeId);
416 OvsdbClient client = connectionService.getConnection(node).getClient();
417 String bckCompatibleTableName = this.getBackwardCompatibleTableName(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
421 row = ovsdbTable.getRow(node, bckCompatibleTableName, rowUuid);
422 } catch (Exception e) {
423 throw new BadRequestException(e.getMessage());
429 * Read all Rows of a table
431 * @param nodeType type of node e.g OVS
432 * @param nodeId ID of the node
433 * @param tableName name of the ovsdb table
435 * @return All the Rows of a table
441 * Get all Bridge Rows:
442 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows
445 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows
447 * Get all Interface Rows:
448 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows
450 * Get all Controller Rows:
451 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/controller/rows
454 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows
456 * Get all sFlow Rows:
457 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows
460 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows
462 * Get all Queue Rows:
463 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows
465 * Get all Netflow Rows:
466 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows
468 * Get all Manager Rows:
469 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows
471 * Get all Open vSwitch Rows:
472 * GET http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/open_vswitch/rows
476 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows")
478 @StatusCodes({ @ResponseCode(code = 200, condition = "Row Updated successfully"),
479 @ResponseCode(code = 400, condition = "Invalid data passed"),
480 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
481 @Produces({ MediaType.APPLICATION_JSON})
482 @TypeHint(OvsdbRows.class)
483 public OvsdbRows getAllRows(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
484 @PathParam("tableName") String tableName) {
485 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
486 throw new UnauthorizedException("User is not authorized to perform this operation");
489 OvsdbConfigurationService
490 ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
492 if (ovsdbTable == null) {
493 throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
496 OvsdbConnectionService
497 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
498 Node node = connectionService.getNode(nodeId);
499 OvsdbClient client = connectionService.getConnection(node).getClient();
500 String bckCompatibleTableName = this.getBackwardCompatibleTableName(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
501 Map<String, Row> rows;
503 rows = ovsdbTable.getRows(node, bckCompatibleTableName);
504 } catch (Exception e) {
505 throw new BadRequestException(e.getMessage());
507 return new OvsdbRows(rows);
514 * @param nodeType type of node e.g OVS
515 * @param nodeId ID of the node
516 * @param tableName name of the ovsdb table
517 * @param rowUuid UUID of the row being updated
518 * @param row the {@link OVSDBRow} Row that is being updated
520 * @return Response as dictated by the HTTP Response Status code
525 * Update the Bridge row to add a controller
529 * PUT http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows/b01cd26b-9c63-4216-8cf2-55f7087adab1
540 * "a566e8b4-fc38-499b-8623-6087d5b36b72"
550 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{rowUuid}")
552 @StatusCodes({ @ResponseCode(code = 200, condition = "Row Updated successfully"),
553 @ResponseCode(code = 400, condition = "Invalid data passed"),
554 @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
555 @Consumes({ MediaType.APPLICATION_JSON})
556 public Response updateRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
557 @PathParam("tableName") String tableName, @PathParam("rowUuid") String rowUuid,
560 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
561 throw new UnauthorizedException("User is not authorized to perform this operation");
564 OvsdbConfigurationService
565 ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
567 if (ovsdbTable == null) {
568 throw new ServiceUnavailableException("OVS Configuration Service " + RestMessages.SERVICEUNAVAILABLE.toString());
571 OvsdbConnectionService
572 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
573 Node node = connectionService.getNode(nodeId);
574 OvsdbClient client = connectionService.getConnection(node).getClient();
575 String bckCompatibleTableName = this.getBackwardCompatibleTableName(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
576 OvsdbRow localRow = OvsdbRow.fromJsonNode(client, OvsVswitchdSchemaConstants.DATABASE_NAME, rowJson);
578 if (localRow == null) {
579 return Response.status(Response.Status.BAD_REQUEST).build();
582 ovsdbTable.updateRow(node, bckCompatibleTableName, localRow.getParentUuid(), rowUuid, localRow.getRow());
583 return NorthboundUtils.getResponse(
584 new org.opendaylight.controller.sal.utils.Status(
585 org.opendaylight.controller.sal.utils.StatusCode.SUCCESS));
591 * @param nodeType type of node e.g OVS
592 * @param nodeId ID of the node
593 * @param tableName name of the ovsdb table
594 * @param uuid UUID of the Row to be removed
596 * @return Response as dictated by the HTTP Response Status code
602 * Delete a specific Bridge Row:
603 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/bridge/rows/6f4c602c-026f-4390-beea-d50d6d448100
605 * Delete a specific Port Row:
606 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/port/rows/6f4c602c-026f-4390-beea-d50d6d448100
608 * Delete a specific Interface Row:
609 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/interface/rows/6f4c602c-026f-4390-beea-d50d6d448100
611 * Delete a specific Controller Row:
612 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/controller/rows/6f4c602c-026f-4390-beea-d50d6d448100
614 * Delete a specific SSL Row:
615 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/SSL/rows/6f4c602c-026f-4390-beea-d50d6d448100
617 * Delete a specific sFlow Row:
618 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/sflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
620 * Delete a specific QoS Row:
621 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/qos/rows/6f4c602c-026f-4390-beea-d50d6d448100
623 * Delete a specific Queue Row:
624 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/queue/rows/6f4c602c-026f-4390-beea-d50d6d448100
626 * Delete a specific Netflow Row:
627 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/netflow/rows/6f4c602c-026f-4390-beea-d50d6d448100
629 * Delete a specific Manager Row:
630 * DELETE http://localhost:8080/ovsdb/nb/v2/node/OVS/HOST1/tables/manager/rows/6f4c602c-026f-4390-beea-d50d6d448100
634 @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{uuid}")
636 @StatusCodes({ @ResponseCode(code = 204, condition = "User Deleted Successfully"),
637 @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
638 @ResponseCode(code = 404, condition = "The userName passed was not found"),
639 @ResponseCode(code = 500, condition = "Internal Server Error : Removal of user failed"),
640 @ResponseCode(code = 503, condition = "Service unavailable") })
641 public Response removeRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
642 @PathParam("tableName") String tableName, @PathParam("uuid") String uuid) {
643 if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
644 throw new UnauthorizedException("User is not authorized to perform this operation");
647 OvsdbConfigurationService
648 ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
650 if (ovsdbTable == null) {
651 throw new ServiceUnavailableException("OVS Configuration Service " + RestMessages.SERVICEUNAVAILABLE.toString());
654 OvsdbConnectionService
655 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
656 Node node = connectionService.getNode(nodeId);
657 OvsdbClient client = connectionService.getConnection(node).getClient();
658 String bckCompatibleTableName = this.getBackwardCompatibleTableName(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
660 Status status = ovsdbTable.deleteRow(node, bckCompatibleTableName, uuid);
661 if (status.isSuccess()) {
662 return Response.noContent().build();
664 return NorthboundUtils.getResponse(
665 new org.opendaylight.controller.sal.utils.Status(
666 org.opendaylight.controller.sal.utils.StatusCode.SUCCESS));
669 private String getBackwardCompatibleTableName(OvsdbClient client, String databaseName, String tableName) {
670 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
671 if (dbSchema == null || tableName == null) {
674 for (String dbTableName : dbSchema.getTables()) {
675 if (dbTableName.equalsIgnoreCase(tableName)) {