--- /dev/null
+<?xml version="1.0"?>
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd">
+
+ <services>
+ <rest defaultRestSubcontext="/ovsdb/nb/v2"/>
+ </services>
+
+ <modules>
+ <docs docsDir="rest" title="OVSDB Table operations over REST" includeExampleXml="true" includeExampleJson="true"/>
+ </modules>
+</enunciate>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>commons.ovsdb</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../commons/parent/</relativePath>
+ </parent>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/ovsdb.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/ovsdt.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+ <tag>HEAD</tag>
+ </scm>
+
+ <artifactId>ovsdb.northbound</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.enunciate</groupId>
+ <artifactId>maven-enunciate-plugin</artifactId>
+ <version>${enunciate.version}</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${bundle.plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ </Export-Package>
+ <Import-Package>
+ org.opendaylight.controller.sal.utils,
+ org.opendaylight.controller.northbound.commons,
+ org.opendaylight.controller.northbound.commons.exception,
+ org.opendaylight.controller.northbound.commons.utils,
+ com.sun.jersey.spi.container.servlet,
+ org.opendaylight.controller.sal.core,
+ org.opendaylight.controller.sal.authorization,
+ org.opendaylight.ovsdb.lib.table,
+ org.opendaylight.ovsdb.lib.table.internal,
+ org.opendaylight.ovsdb.plugin,
+ javax.ws.rs,
+ javax.ws.rs.core,
+ javax.xml.bind,
+ javax.xml.bind.annotation,
+ org.slf4j,
+ org.apache.catalina.filters,
+ org.codehaus.jackson.jaxrs,
+ org.codehaus.jackson.annotate,
+ !org.codehaus.enunciate.jaxrs
+ </Import-Package>
+ <Export-Package>
+ </Export-Package>
+ <Web-ContextPath>/ovsdb/nb/v2</Web-ContextPath>
+ <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
+ </instructions>
+ <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.ovsdb</groupId>
+ <artifactId>ovsdb</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.enunciate</groupId>
+ <artifactId>enunciate-core-annotations</artifactId>
+ <version>${enunciate.version}</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.northbound;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.core.UriInfo;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class provides REST APIs to Create, Read, Update and Delete OVSDB Row in any of the ovsdb table
+ * database one at a time.
+ */
+
+@Path("/")
+public class OVSDBNorthbound {
+ protected static final Logger logger = LoggerFactory.getLogger(OVSDBNorthbound.class);
+
+ @Context
+ private UriInfo _uriInfo;
+ private String username;
+
+ @Context
+ public void setSecurityContext(SecurityContext context) {
+ if (context != null && context.getUserPrincipal() != null) {
+ username = context.getUserPrincipal().getName();
+ }
+ }
+
+ protected String getUserName() {
+ return username;
+ }
+
+ private void handleNameMismatch(String name, String nameinURL) {
+ if (name == null || nameinURL == null) {
+ throw new BadRequestException(RestMessages.INVALIDDATA.toString() + " : Name is null");
+ }
+
+ if (name.equalsIgnoreCase(nameinURL)) {
+ return;
+ }
+ throw new ResourceConflictException(RestMessages.INVALIDDATA.toString()
+ + " : Table Name in URL does not match the row name in request body");
+ }
+
+ /**
+ * Create a Row
+ *
+ * @param tableName name of the ovsdb table
+ * @param row the {@link OVSDBRow} Row that is being inserted
+ *
+ * @return Response as dictated by the HTTP Response Status code
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * https://localhost/controller/nb/v2/ovsdb/tables/bridge/rows
+ * </pre>
+ */
+
+ @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows")
+ @POST
+ @StatusCodes({ @ResponseCode(code = 201, condition = "Row Inserted successfully"),
+ @ResponseCode(code = 400, condition = "Invalid data passed"),
+ @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
+ @Consumes({ MediaType.APPLICATION_JSON})
+ public Response addRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
+ @PathParam("tableName") String tableName, @TypeHint(OVSDBRow.class) OVSDBRow row) {
+
+ if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
+ throw new UnauthorizedException("User is not authorized to perform this operation");
+ }
+
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class,
+ this);
+ if (ovsdbTable == null) {
+ throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if (row != null && row.getRow() != null) {
+ handleNameMismatch(tableName, row.getRow().getTableName().getName());
+ Node node = Node.fromString(nodeType, nodeId);
+ Status statusWithUUID = ovsdbTable.insertRow(node, tableName, row.getParent_uuid(), row.getRow());
+
+ if (statusWithUUID.isSuccess()) {
+ return Response.status(Response.Status.CREATED)
+ .header("Location", String.format("%s/%s", _uriInfo.getAbsolutePath().toString(),
+ statusWithUUID.getDescription()))
+ .entity(statusWithUUID.getDescription())
+ .build();
+ } else {
+ return NorthboundUtils.getResponse(statusWithUUID);
+ }
+ }
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
+
+ /**
+ * Update a Row
+ *
+ * @param node OVSDB Node identifier
+ * @param tableName name of the ovsdb table
+ * @param rowUuid UUID of the row being updated
+ * @param row the {@link OVSDBRow} Row that is being inserted
+ *
+ * @return Response as dictated by the HTTP Response Status code
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * https://localhost/controller/nb/v2/ovsdb/tables/bridge/rows
+ * </pre>
+ */
+
+ @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{rowUuid}")
+ @PUT
+ @StatusCodes({ @ResponseCode(code = 200, condition = "Row Updated successfully"),
+ @ResponseCode(code = 400, condition = "Invalid data passed"),
+ @ResponseCode(code = 401, condition = "User not authorized to perform this operation")})
+ @Consumes({ MediaType.APPLICATION_JSON})
+ public Response updateRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
+ @PathParam("tableName") String tableName, @PathParam("rowUuid") String rowUuid,
+ @TypeHint(OVSDBRow.class) OVSDBRow row) {
+
+ if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
+ throw new UnauthorizedException("User is not authorized to perform this operation");
+ }
+
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class,
+ this);
+ if (ovsdbTable == null) {
+ throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+
+ if (row != null && row.getRow() != null) {
+ handleNameMismatch(tableName, row.getRow().getTableName().getName());
+ Node node = Node.fromString(nodeType, nodeId);
+ Status status = ovsdbTable.updateRow(node, rowUuid, row.getRow());
+ return NorthboundUtils.getResponse(status);
+ }
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
+
+ /**
+ * Delete a row
+ *
+ * @param tableName name of the ovsdb table
+ * @param uuid UUID of the Row to be removed
+ * @return Response as dictated by the HTTP Response Status code
+ *
+ * <pre>
+ * Example:
+ *
+ * Request URL:
+ * https://localhost/controller/nb/v2/ovsdb/tables/bridge/rows/41ab15a9-0dab-4675-a579-63019d4bcbec
+ *
+ * </pre>
+ */
+ @Path("/node/{nodeType}/{nodeId}/tables/{tableName}/rows/{uuid}")
+ @DELETE
+ @StatusCodes({ @ResponseCode(code = 204, condition = "User Deleted Successfully"),
+ @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
+ @ResponseCode(code = 404, condition = "The userName passed was not found"),
+ @ResponseCode(code = 500, condition = "Internal Server Error : Removal of user failed"),
+ @ResponseCode(code = 503, condition = "Service unavailable") })
+ public Response removeRow(@PathParam("nodeType") String nodeType, @PathParam("nodeId") String nodeId,
+ @PathParam("tableName") String tableName, @PathParam("uuid") String uuid) {
+ if (!NorthboundUtils.isAuthorized(getUserName(), "default", Privilege.WRITE, this)) {
+ throw new UnauthorizedException("User is not authorized to perform this operation");
+ }
+
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ if (ovsdbTable == null) {
+ throw new ServiceUnavailableException("UserManager " + RestMessages.SERVICEUNAVAILABLE.toString());
+ }
+ Node node = Node.fromString(nodeType, nodeId);
+ Status status = ovsdbTable.deleteRow(node, tableName, uuid);
+ if (status.isSuccess()) {
+ return Response.noContent().build();
+ }
+ return NorthboundUtils.getResponse(status);
+ }
+}
--- /dev/null
+package org.opendaylight.ovsdb.northbound;
+
+import org.codehaus.jackson.annotate.JsonSubTypes;
+import org.codehaus.jackson.annotate.JsonTypeInfo;
+import org.opendaylight.ovsdb.lib.table.Bridge;
+import org.opendaylight.ovsdb.lib.table.Capability;
+import org.opendaylight.ovsdb.lib.table.Controller;
+import org.opendaylight.ovsdb.lib.table.Interface;
+import org.opendaylight.ovsdb.lib.table.Manager;
+import org.opendaylight.ovsdb.lib.table.Mirror;
+import org.opendaylight.ovsdb.lib.table.NetFlow;
+import org.opendaylight.ovsdb.lib.table.Open_vSwitch;
+import org.opendaylight.ovsdb.lib.table.Port;
+import org.opendaylight.ovsdb.lib.table.Qos;
+import org.opendaylight.ovsdb.lib.table.Queue;
+import org.opendaylight.ovsdb.lib.table.SFlow;
+import org.opendaylight.ovsdb.lib.table.SSL;
+import org.opendaylight.ovsdb.lib.table.internal.Table;
+
+public class OVSDBRow {
+ String parent_uuid;
+ /*
+ * MINIMAL_CLASS Directive expects a leading "." character on the class name and is lame.
+ * Hence going with NAME directive even though it calls for SubTypes.
+ * Since we are using fixed table types for the Hydrogen release, this is acceptable.
+ * When we move towards Schema driven table definition, this is anyways not required.
+
+ @JsonTypeInfo(
+ use = JsonTypeInfo.Id.MINIMAL_CLASS,
+ include = JsonTypeInfo.As.PROPERTY,
+ property = "@class")
+ */
+
+ @JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.WRAPPER_OBJECT)
+ @JsonSubTypes({
+ @JsonSubTypes.Type(value=Bridge.class, name="Bridge"),
+ @JsonSubTypes.Type(value=Capability.class, name="Capbility"),
+ @JsonSubTypes.Type(value=Controller.class, name="Controller"),
+ @JsonSubTypes.Type(value=Interface.class, name="Interface"),
+ @JsonSubTypes.Type(value=Manager.class, name="Manager"),
+ @JsonSubTypes.Type(value=Mirror.class, name="Mirror"),
+ @JsonSubTypes.Type(value=NetFlow.class, name="NetFlow"),
+ @JsonSubTypes.Type(value=Open_vSwitch.class, name="Open_vSwitch"),
+ @JsonSubTypes.Type(value=Port.class, name="Port"),
+ @JsonSubTypes.Type(value=Qos.class, name="QoS"),
+ @JsonSubTypes.Type(value=Queue.class, name="Queue"),
+ @JsonSubTypes.Type(value=SFlow.class, name="sFlow"),
+ @JsonSubTypes.Type(value=SSL.class, name="SSL")
+ })
+ Table row;
+
+ public OVSDBRow() {
+ }
+ public String getParent_uuid() {
+ return parent_uuid;
+ }
+ public void setParent_uuid(String parent_uuid) {
+ this.parent_uuid = parent_uuid;
+ }
+ public Table getRow() {
+ return row;
+ }
+ public void setRow(Table row) {
+ this.row = row;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+ <servlet>
+ <servlet-name>OVSDB</servlet-name>
+ <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value> org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
+ </init-param>
+ <init-param>
+ <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>OVSDB</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+ <filter>
+ <filter-name>CorsFilter</filter-name>
+ <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
+ <init-param>
+ <param-name>cors.allowed.origins</param-name>
+ <param-value>*</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.allowed.methods</param-name>
+ <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.allowed.headers</param-name>
+ <param-value>Content-Type,X-Requested-With,accept,authorization, origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.exposed.headers</param-name>
+ <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.support.credentials</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cors.preflight.maxage</param-name>
+ <param-value>10</param-value>
+ </init-param>
+ </filter>
+ <filter-mapping>
+ <filter-name>CorsFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>NB api</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ <http-method>POST</http-method>
+ <http-method>GET</http-method>
+ <http-method>PUT</http-method>
+ <http-method>PATCH</http-method>
+ <http-method>DELETE</http-method>
+ <http-method>HEAD</http-method>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>System-Admin</role-name>
+ <role-name>Network-Admin</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <security-role>
+ <role-name>System-Admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Network-Admin</role-name>
+ </security-role>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>opendaylight</realm-name>
+ </login-config>
+</web-app>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../commons/parent/</relativePath>
</parent>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/ovsdb.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/ovsdt.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+ <tag>HEAD</tag>
+ </scm>
<artifactId>ovsdb</artifactId>
<version>0.5.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<Bundle-Activator>
org.opendaylight.ovsdb.plugin.Activator
</Bundle-Activator>
+ <Export-Package>
+ org.opendaylight.ovsdb.lib.table, org.opendaylight.ovsdb.lib.table.internal, org.opendaylight.ovsdb.plugin
+ </Export-Package>
</instructions>
<manifestLocation>${project.basedir}/META-INF</manifestLocation>
</configuration>
package org.opendaylight.ovsdb.lib.table.internal;
public abstract class Table<E extends Table> {
-
public abstract Name<E> getTableName();
+ @Override
public abstract String toString();
public Column<E> getColumns() {
return null;
import org.apache.felix.dm.Component;
import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
import org.opendaylight.controller.sal.connection.IPluginInConnectionService;
import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
-import org.opendaylight.controller.sal.utils.INodeConnectorFactory;
-import org.opendaylight.controller.sal.utils.INodeFactory;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.INodeConnectorFactory;
+import org.opendaylight.controller.sal.utils.INodeFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* Here it registers the node Type
*
*/
+ @Override
public void init() {
Node.NodeIDType.registerIDType("OVS", String.class);
NodeConnector.NodeConnectorIDType.registerIDType("OVS", String.class, "OVS");
* ComponentActivatorAbstractBase
*
*/
+ @Override
public void destroy() {
Node.NodeIDType.unRegisterIDType("OVS");
NodeConnector.NodeConnectorIDType.unRegisterIDType("OVS");
}
+ @Override
public Object[] getGlobalImplementations() {
Object[] res = { ConnectionService.class, ConfigurationService.class, NodeFactory.class, NodeConnectorFactory.class, InventoryService.class };
return res;
}
+ @Override
public void configureGlobalInstance(Component c, Object imp){
if (imp.equals(ConfigurationService.class)) {
// export the service to be used by SAL
// Set the protocolPluginType property which will be used
// by SAL
props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), "OVS");
- c.setInterface(IPluginInBridgeDomainConfigService.class.getName(), props);
+ c.setInterface(new String[] { IPluginInBridgeDomainConfigService.class.getName(),
+ OVSDBConfigService.class.getName()}, props);
c.add(createServiceDependency()
.setService(IConnectionServiceInternal.class)
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
+import org.opendaylight.controller.sal.connection.ConnectionConstants;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
+import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
import org.opendaylight.ovsdb.lib.database.OVSInstance;
import org.opendaylight.ovsdb.lib.database.OvsdbType;
import org.opendaylight.ovsdb.lib.message.TransactBuilder;
import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.table.Bridge;
+import org.opendaylight.ovsdb.lib.table.Capability;
import org.opendaylight.ovsdb.lib.table.Controller;
import org.opendaylight.ovsdb.lib.table.Interface;
+import org.opendaylight.ovsdb.lib.table.Manager;
+import org.opendaylight.ovsdb.lib.table.Mirror;
+import org.opendaylight.ovsdb.lib.table.NetFlow;
import org.opendaylight.ovsdb.lib.table.Open_vSwitch;
import org.opendaylight.ovsdb.lib.table.Port;
+import org.opendaylight.ovsdb.lib.table.Qos;
+import org.opendaylight.ovsdb.lib.table.Queue;
+import org.opendaylight.ovsdb.lib.table.SFlow;
+import org.opendaylight.ovsdb.lib.table.SSL;
import org.opendaylight.ovsdb.lib.table.internal.Table;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.sal.connection.ConnectionConstants;
-import org.opendaylight.controller.sal.core.Node;
-import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
-import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
-import org.opendaylight.controller.sal.utils.NetUtils;
-import org.opendaylight.controller.sal.utils.Status;
-import org.opendaylight.controller.sal.utils.StatusCode;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import com.google.common.util.concurrent.ListenableFuture;
-public class ConfigurationService implements IPluginInBridgeDomainConfigService, CommandProvider
+public class ConfigurationService implements IPluginInBridgeDomainConfigService, OVSDBConfigService,
+ CommandProvider
{
private static final Logger logger = LoggerFactory
.getLogger(ConfigurationService.class);
TransactBuilder transaction = new TransactBuilder();
transaction.addOperations(new ArrayList<Operation>(
- Arrays.asList(addSwitchRequest, addIntfRequest, addPortRequest, addBridgeRequest, updateCfgVerRequest)));
+ Arrays.asList(addSwitchRequest,
+ addIntfRequest,
+ addPortRequest,
+ addBridgeRequest,
+ updateCfgVerRequest)));
ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
List<OperationResult> tr = transResponse.get();
return true;
}
+ @Override
+ public Status insertRow(Node node, String tableName, String parent_uuid, Table<?> row) {
+ logger.error("tableName : {}, parent_uuid : {} Row : {}", tableName, parent_uuid, row.toString());
+ Status statusWithUUID = null;
+
+ // Schema based Table handling will help fix this static Table handling.
+
+ if (row.getTableName().getName().equalsIgnoreCase("Bridge")) {
+ statusWithUUID = insertBridgeRow(node, parent_uuid, (Bridge)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Capbility")) {
+ statusWithUUID = insertCapabilityRow(node, parent_uuid, (Capability)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Controller")) {
+ statusWithUUID = insertControllerRow(node, parent_uuid, (Controller)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Interface")) {
+ statusWithUUID = insertInterfaceRow(node, parent_uuid, (Interface)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Manager")) {
+ statusWithUUID = insertManagerRow(node, parent_uuid, (Manager)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Mirror")) {
+ statusWithUUID = insertMirrorRow(node, parent_uuid, (Mirror)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("NetFlow")) {
+ statusWithUUID = insertNetFlowRow(node, parent_uuid, (NetFlow)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Open_vSwitch")) {
+ statusWithUUID = insertOpen_vSwitchRow(node, (Open_vSwitch)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Port")) {
+ statusWithUUID = insertPortRow(node, parent_uuid, (Port)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("QoS")) {
+ statusWithUUID = insertQosRow(node, parent_uuid, (Qos)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("Queue")) {
+ statusWithUUID = insertQueueRow(node, parent_uuid, (Queue)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("sFlow")) {
+ statusWithUUID = insertSflowRow(node, parent_uuid, (SFlow)row);
+ }
+ else if (row.getTableName().getName().equalsIgnoreCase("SSL")) {
+ statusWithUUID = insertSSLRow(node, parent_uuid, (SSL)row);
+ }
+ return statusWithUUID;
+ }
+
+ private Status insertBridgeRow(Node node, String open_VSwitch_uuid, Bridge bridgeRow) {
+ try{
+ if (connectionService == null) {
+ logger.error("Couldn't refer to the ConnectionService");
+ return new Status(StatusCode.NOSERVICE);
+ }
+
+ Connection connection = this.getConnection(node);
+ if (connection == null) {
+ return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
+ }
+
+ Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node, Open_vSwitch.NAME.getName());
+
+ if (ovsTable == null) {
+ return new Status(StatusCode.NOTFOUND, "There are no Open_vSwitch instance in the Open_vSwitch table");
+ }
+
+ String newBridge = "new_bridge";
+
+ Operation addSwitchRequest = null;
+
+ String ovsTableUUID = open_VSwitch_uuid;
+ if (ovsTableUUID == null) ovsTableUUID = (String) ovsTable.keySet().toArray()[0];
+ UUID bridgeUuidPair = new UUID(newBridge);
+ Mutation bm = new Mutation("bridges", Mutator.INSERT, bridgeUuidPair);
+ List<Mutation> mutations = new ArrayList<Mutation>();
+ mutations.add(bm);
+
+ UUID uuid = new UUID(ovsTableUUID);
+ Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
+ List<Condition> where = new ArrayList<Condition>();
+ where.add(condition);
+ addSwitchRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where, mutations);
+
+ InsertOperation addBridgeRequest = new InsertOperation(Bridge.NAME.getName(), newBridge, bridgeRow);
+
+ TransactBuilder transaction = new TransactBuilder();
+ transaction.addOperations(new ArrayList<Operation>(
+ Arrays.asList(addSwitchRequest,
+ addBridgeRequest)));
+
+ int bridgeInsertIndex = transaction.getRequests().indexOf(addBridgeRequest);
+
+ ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
+ List<OperationResult> tr = transResponse.get();
+ List<Operation> requests = transaction.getRequests();
+ Status status = new Status(StatusCode.SUCCESS);
+ for (int i = 0; i < tr.size() ; i++) {
+ if (i < requests.size()) requests.get(i).setResult(tr.get(i));
+ if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
+ OperationResult result = tr.get(i);
+ status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+ }
+ }
+
+ if (tr.size() > requests.size()) {
+ OperationResult result = tr.get(tr.size()-1);
+ logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}", bridgeRow.getName(),
+ result.getError(),
+ result.getDetails());
+ status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+ }
+ if (status.isSuccess()) {
+ UUID bridgeUUID = tr.get(bridgeInsertIndex).getUuid();
+ status = new Status(StatusCode.SUCCESS, bridgeUUID.toString());
+ }
+ return status;
+ } catch(Exception e){
+ e.printStackTrace();
+ }
+ return new Status(StatusCode.INTERNALERROR);
+ }
+
+ private Status insertPortRow(Node node, String bridge_uuid, Port portRow) {
+ try{
+ if (connectionService == null) {
+ logger.error("Couldn't refer to the ConnectionService");
+ return new Status(StatusCode.NOSERVICE);
+ }
+ Connection connection = this.getConnection(node);
+ if (connection == null) {
+ return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
+ }
+
+ Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
+ if (brTable == null || brTable.get(bridge_uuid) == null) {
+ return new Status(StatusCode.NOTFOUND, "Bridge with UUID "+bridge_uuid+" Not found");
+ }
+ String newPort = "new_port";
+ UUID portUUID = new UUID(newPort);
+ Mutation bm = new Mutation("ports", Mutator.INSERT, portUUID);
+ List<Mutation> mutations = new ArrayList<Mutation>();
+ mutations.add(bm);
+
+ UUID uuid = new UUID(bridge_uuid);
+ Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
+ List<Condition> where = new ArrayList<Condition>();
+ where.add(condition);
+ Operation addBrMutRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);
+
+ // Default OVS schema is to have 1 or more interface part of Bridge. Hence it is mandatory to
+ // Insert an Interface in a Port add case :-(.
+
+ String newInterface = "new_interface";
+ Interface interfaceRow = new Interface();
+ interfaceRow.setName(portRow.getName());
+ InsertOperation addIntfRequest = new InsertOperation(Interface.NAME.getName(),
+ newInterface, interfaceRow);
+
+ OvsDBSet<UUID> interfaces = new OvsDBSet<UUID>();
+ UUID interfaceid = new UUID(newInterface);
+ interfaces.add(interfaceid);
+ portRow.setInterfaces(interfaces);
+
+ InsertOperation addPortRequest = new InsertOperation(Port.NAME.getName(), newPort, portRow);
+
+ TransactBuilder transaction = new TransactBuilder();
+ transaction.addOperations(new ArrayList<Operation>
+ (Arrays.asList(addBrMutRequest, addPortRequest, addIntfRequest)));
+ int portInsertIndex = transaction.getRequests().indexOf(addPortRequest);
+ ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
+ List<OperationResult> tr = transResponse.get();
+ List<Operation> requests = transaction.getRequests();
+ Status status = new Status(StatusCode.SUCCESS);
+ for (int i = 0; i < tr.size() ; i++) {
+ if (i < requests.size()) requests.get(i).setResult(tr.get(i));
+ if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
+ OperationResult result = tr.get(i);
+ status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+ }
+ }
+
+ if (tr.size() > requests.size()) {
+ OperationResult result = tr.get(tr.size()-1);
+ logger.error("Error creating port : {}\n Error : {}\n Details : {}", portRow.getName(),
+ result.getError(),
+ result.getDetails());
+ status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+ }
+ if (status.isSuccess()) {
+ uuid = tr.get(portInsertIndex).getUuid();
+ status = new Status(StatusCode.SUCCESS, uuid.toString());
+ }
+
+ return status;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return new Status(StatusCode.INTERNALERROR);
+ }
+
+ private Status insertInterfaceRow(Node node, String port_uuid, Interface row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertOpen_vSwitchRow(Node node, Open_vSwitch row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertControllerRow(Node node, String bridge_uuid, Controller row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertSSLRow(Node node, String parent_uuid, SSL row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertSflowRow(Node node, String parent_uuid, SFlow row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertQueueRow(Node node, String parent_uuid, Queue row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertQosRow(Node node, String parent_uuid, Qos row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertNetFlowRow(Node node, String parent_uuid, NetFlow row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertMirrorRow(Node node, String parent_uuid, Mirror row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertManagerRow(Node node, String parent_uuid, Manager row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ private Status insertCapabilityRow(Node node, String parent_uuid, Capability row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+ }
+
+ @Override
+ public Status updateRow(Node node, String rowUUID, Table<?> row) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Update Row functionality is not implemented yet.");
+ }
+
+ @Override
+ public Status deleteRow(Node node, String tableName, String uuid) {
+ return new Status(StatusCode.NOTIMPLEMENTED, "Delete Row functionality is not implemented yet.");
+ }
+
+ @Override
+ public List<Table<?>> getRows(Node node, String tableName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Table<?> getRow(Node node, String tableName, String uuid) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<String> getTables(Node node) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
public void _ovsconnect (CommandInterpreter ci) {
String bridgeName = ci.nextArgument();
if (bridgeName == null) {
--- /dev/null
+package org.opendaylight.ovsdb.plugin;
+
+import java.util.List;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.ovsdb.lib.table.internal.Table;
+
+public interface OVSDBConfigService {
+ public Status insertRow (Node node, String tableName, String parentUUID, Table<?> row);
+ public Status deleteRow (Node node, String tableName, String uuid);
+ public Status updateRow (Node node, String rowUUID, Table<?> row);
+ public Table<?> getRow(Node node, String tableName, String uuid);
+ public List<Table<?>> getRows(Node node, String tableName);
+ public List<String> getTables(Node node);
+}