2 * Copyright (C) 2013 Red Hat, Inc.
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, Keith Burns
10 package org.opendaylight.ovsdb.plugin.impl;
12 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.AbstractMap;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
24 import java.util.concurrent.ConcurrentMap;
25 import java.util.concurrent.ExecutionException;
27 import org.eclipse.osgi.framework.console.CommandInterpreter;
28 import org.eclipse.osgi.framework.console.CommandProvider;
29 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
30 import org.opendaylight.controller.sal.connection.ConnectionConstants;
31 import org.opendaylight.controller.sal.core.Node;
32 import org.opendaylight.controller.sal.core.NodeConnector;
33 import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
34 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
35 import org.opendaylight.controller.sal.utils.Status;
36 import org.opendaylight.controller.sal.utils.StatusCode;
37 import org.opendaylight.ovsdb.lib.OvsdbClient;
38 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
39 import org.opendaylight.ovsdb.lib.notation.Column;
40 import org.opendaylight.ovsdb.lib.notation.Mutator;
41 import org.opendaylight.ovsdb.lib.notation.OvsdbSet;
42 import org.opendaylight.ovsdb.lib.notation.ReferencedRow;
43 import org.opendaylight.ovsdb.lib.notation.Row;
44 import org.opendaylight.ovsdb.lib.notation.UUID;
45 import org.opendaylight.ovsdb.lib.operations.Insert;
46 import org.opendaylight.ovsdb.lib.operations.Operation;
47 import org.opendaylight.ovsdb.lib.operations.OperationResult;
48 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
49 import org.opendaylight.ovsdb.lib.schema.BaseType.UuidBaseType;
50 import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
51 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
52 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
53 import org.opendaylight.ovsdb.lib.schema.TableSchema;
54 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
55 import org.opendaylight.ovsdb.plugin.OvsdbConfigService;
56 import org.opendaylight.ovsdb.plugin.api.Connection;
57 import org.opendaylight.ovsdb.plugin.api.OvsVswitchdSchemaConstants;
58 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
59 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
60 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryService;
61 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
62 import org.opendaylight.ovsdb.plugin.error.OvsdbPluginException;
63 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
64 import org.opendaylight.ovsdb.schema.openvswitch.Controller;
65 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
66 import org.opendaylight.ovsdb.schema.openvswitch.Manager;
67 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
68 import org.opendaylight.ovsdb.schema.openvswitch.Port;
69 import org.osgi.framework.BundleContext;
70 import org.osgi.framework.FrameworkUtil;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
74 import com.fasterxml.jackson.databind.node.ObjectNode;
75 import com.google.common.collect.ImmutableSet;
76 import com.google.common.collect.Maps;
77 import com.google.common.util.concurrent.ListenableFuture;
79 public class ConfigurationServiceImpl implements IPluginInBridgeDomainConfigService,
80 OvsdbConfigurationService,
84 private static final Logger logger = LoggerFactory
85 .getLogger(ConfigurationServiceImpl.class);
87 OvsdbConnectionService connectionService;
88 OvsdbInventoryService ovsdbInventoryService;
89 boolean forceConnect = false;
90 protected static final String OPENFLOW_10 = "1.0";
91 protected static final String OPENFLOW_13 = "1.3";
97 * Function called by the dependency manager when at least one dependency
98 * become unsatisfied or when the component is shutting down because for
99 * example bundle is being stopped.
106 * Function called by dependency manager after "init ()" is called and after
107 * the services provided by the class are registered in the service registry
111 registerWithOSGIConsole();
114 private void registerWithOSGIConsole() {
115 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
117 bundleContext.registerService(CommandProvider.class.getName(), this,
122 * Function called by the dependency manager before the services exported by
123 * the component are unregistered, this will be followed by a "destroy ()"
130 public void setConnectionServiceInternal(OvsdbConnectionService connectionService) {
131 this.connectionService = connectionService;
134 public void unsetConnectionServiceInternal(OvsdbConnectionService connectionService) {
135 if (this.connectionService == connectionService) {
136 this.connectionService = null;
140 public void setOvsdbInventoryService(OvsdbInventoryService ovsdbInventoryService) {
141 this.ovsdbInventoryService = ovsdbInventoryService;
144 public void unsetInventoryServiceInternal(OvsdbInventoryService ovsdbInventoryService) {
145 if (this.ovsdbInventoryService == ovsdbInventoryService) {
146 this.ovsdbInventoryService = null;
150 private IClusterGlobalServices clusterServices;
152 public void setClusterServices(IClusterGlobalServices i) {
153 this.clusterServices = i;
156 public void unsetClusterServices(IClusterGlobalServices i) {
157 if (this.clusterServices == i) {
158 this.clusterServices = null;
162 private Connection getConnection (Node node) {
163 Connection connection = connectionService.getConnection(node);
164 if (connection == null || !connection.getClient().isActive()) {
171 * There are a few Open_vSwitch schema specific special case handling to be done for
172 * the older API (such as by inserting a mandatory Interface row automatically upon inserting
175 private void handleSpecialInsertCase(OvsdbClient client, String databaseName,
176 String tableName, String uuid, Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
177 Port port = client.getTypedRowWrapper(Port.class, null);
178 if (databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME) && tableName.equals(port.getSchema().getName())) {
179 port = client.getTypedRowWrapper(Port.class, row);
180 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
181 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
182 ColumnSchema<GenericTableSchema, Set<UUID>> columnSchema = tableSchema.multiValuedColumn("interfaces", UUID.class);
183 String namedUuid = "Special_"+tableName;
184 List<Operation> priorOperations = transactionBuilder.getOperations();
185 Insert portOperation = (Insert)priorOperations.get(0);
186 portOperation.value(columnSchema, new UUID(namedUuid));
188 Column<GenericTableSchema, ?> nameColumn = port.getNameColumn();
189 List<Column<GenericTableSchema, ?>> columns = new ArrayList<Column<GenericTableSchema, ?>>();
190 columns.add(nameColumn);
191 Row<GenericTableSchema> intfRow = new Row<GenericTableSchema>(tableSchema, columns);
192 this.processTypedInsertTransaction(client, databaseName, "Interface", null, null, null, namedUuid, intfRow, transactionBuilder);
197 * A common Transaction that takes in old API style Parent_uuid and inserts a mutation on
198 * the parent table for the newly inserted Child.
199 * Due to some additional special case(s), the Transaction is further amended by handleSpecialInsertCase
201 private void processTypedInsertTransaction(OvsdbClient client, String databaseName, String childTable,
202 String parentTable, String parentUuid, String parentColumn, String namedUuid,
203 Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
204 this.processInsertTransaction(client, databaseName, childTable, parentTable, new UUID(parentUuid), parentColumn,
205 namedUuid, row, transactionBuilder);
207 * There are a few Open_vSwitch schema specific special case handling to be done for
208 * the older API (such as by inserting a mandatory Interface row automatically upon inserting
211 handleSpecialInsertCase(client, databaseName, childTable, namedUuid, row, transactionBuilder);
215 * TODO : Move all the Special Cases out of ConfigurationService and into the Schema specific bundles.
216 * But that makes plugin more reliant on the Typed Bundles more than just API wrapper.
217 * Keeping these Special Handling locally till we introduce the full schema independent APIs in the
220 public String getSpecialCaseParentUUID(Node node, String databaseName, String childTableName) {
221 if (!databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) return null;
222 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(childTableName);
223 if (parentColumn != null && parentColumn[0].equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) {
224 Connection connection = connectionService.getConnection(node);
225 OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
226 ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
227 if (row == null || row.size() == 0) return null;
228 return (String)row.keySet().toArray()[0];
234 * Though this is a New API that takes in Row object, this still is considered a
235 * Deprecated call because of the assumption with a Single Row insertion.
236 * An ideal insertRow must be able to take in multiple Rows, which includes the
237 * Row being inserted in one Table and other Rows that needs mutate in other Tables.
241 public StatusWithUuid insertRow(Node node, String tableName, String parentUuid, Row<GenericTableSchema> row) {
242 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
243 if (parentColumn == null) {
244 parentColumn = new String[]{null, null};
247 Connection connection = connectionService.getConnection(node);
248 OvsdbClient client = connection.getClient();
250 if (parentUuid == null) {
251 parentUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
253 logger.debug("insertRow Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
254 client.getConnectionInfo(), tableName, parentColumn[0], parentColumn[1], parentUuid, row);
256 DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
257 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
259 String namedUuid = "Transaction_"+ tableName;
260 this.processTypedInsertTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
261 parentColumn[0], parentUuid, parentColumn[1], namedUuid,
262 row, transactionBuilder);
264 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
265 List<OperationResult> operationResults;
267 operationResults = results.get();
268 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
269 return new StatusWithUuid(StatusCode.INTERNALERROR);
271 for (OperationResult result : operationResults) {
272 if (result.getError() != null) {
273 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
276 UUID uuid = operationResults.get(0).getUuid();
277 return new StatusWithUuid(StatusCode.SUCCESS, uuid);
278 } catch (InterruptedException | ExecutionException e) {
279 // TODO Auto-generated catch block
280 return new StatusWithUuid(StatusCode.INTERNALERROR, e.getLocalizedMessage());
287 public Status updateRow (Node node, String tableName, String parentUUID, String rowUUID, Row row) {
288 String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
289 Row<GenericTableSchema> updatedRow = this.updateRow(node, databaseName, tableName, new UUID(rowUUID), row, true);
290 return new StatusWithUuid(StatusCode.SUCCESS);
293 private void processDeleteTransaction(OvsdbClient client, String databaseName, String childTable,
294 String parentTable, String parentColumn, String uuid, TransactionBuilder transactionBuilder) {
295 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
296 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
298 if (parentColumn != null) {
299 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
300 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
302 .add(op.mutate(parentTableSchema)
303 .addMutation(parentColumnSchema, Mutator.DELETE, new UUID(uuid))
304 .where(parentColumnSchema.opIncludes(new UUID(uuid)))
308 ColumnSchema<GenericTableSchema, UUID> _uuid = childTableSchema.column("_uuid", UUID.class);
309 transactionBuilder.add(op.delete(childTableSchema)
310 .where(_uuid.opEqual(new UUID(uuid)))
316 public Status deleteRow(Node node, String tableName, String uuid) {
317 String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
318 Connection connection = connectionService.getConnection(node);
319 OvsdbClient client = connection.getClient();
321 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
322 if (parentColumn == null) {
323 parentColumn = new String[]{null, null};
326 logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
327 client.getConnectionInfo(), databaseName, tableName, uuid, parentColumn[0], parentColumn[1]);
329 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
330 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
331 this.processDeleteTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
332 parentColumn[0], parentColumn[1], uuid, transactionBuilder);
334 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
335 List<OperationResult> operationResults;
337 operationResults = results.get();
338 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
339 return new StatusWithUuid(StatusCode.INTERNALERROR);
341 for (OperationResult result : operationResults) {
342 if (result.getError() != null) {
343 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
346 } catch (InterruptedException | ExecutionException e) {
347 // TODO Auto-generated catch block
351 return new Status(StatusCode.SUCCESS);
356 public ConcurrentMap<String, Row> getRows(Node node, String tableName) {
357 ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
363 public Row getRow(Node node, String tableName, String uuid) {
364 Map<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
365 if (ovsTable == null) return null;
366 return ovsTable.get(uuid);
371 public List<String> getTables(Node node) {
372 return this.getTables(node, OvsVswitchdSchemaConstants.DATABASE_NAME);
375 private List<InetAddress> getControllerIPAddresses(Connection connection) {
376 List<InetAddress> controllers = null;
377 InetAddress controllerIP = null;
379 controllers = new ArrayList<InetAddress>();
380 String addressString = System.getProperty("ovsdb.controller.address");
382 if (addressString != null) {
384 controllerIP = InetAddress.getByName(addressString);
385 if (controllerIP != null) {
386 controllers.add(controllerIP);
389 } catch (UnknownHostException e) {
390 logger.error("Host {} is invalid", addressString);
394 if (clusterServices != null) {
395 controllers = clusterServices.getClusteredControllers();
396 if (controllers != null && controllers.size() > 0) {
397 if (controllers.size() == 1) {
398 InetAddress controller = controllers.get(0);
399 if (!controller.equals(InetAddress.getLoopbackAddress())) {
408 addressString = System.getProperty("of.address");
410 if (addressString != null) {
412 controllerIP = InetAddress.getByName(addressString);
413 if (controllerIP != null) {
414 controllers.add(controllerIP);
417 } catch (UnknownHostException e) {
418 logger.error("Host {} is invalid", addressString);
423 controllerIP = connection.getClient().getConnectionInfo().getLocalAddress();
424 controllers.add(controllerIP);
426 } catch (Exception e) {
427 logger.debug("Invalid connection provided to getControllerIPAddresses", e);
432 private short getControllerOFPort() {
433 Short defaultOpenFlowPort = 6633;
434 Short openFlowPort = defaultOpenFlowPort;
435 String portString = System.getProperty("of.listenPort");
436 if (portString != null) {
438 openFlowPort = Short.decode(portString).shortValue();
439 } catch (NumberFormatException e) {
440 logger.warn("Invalid port:{}, use default({})", portString,
448 public Boolean setOFController(Node node, String bridgeUUID) throws InterruptedException, ExecutionException {
449 Connection connection = this.getConnection(node);
450 if (connection == null) {
454 Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
456 Status updateOperationStatus = null;
458 OvsdbSet<String> protocols = new OvsdbSet<String>();
460 String ofVersion = System.getProperty("ovsdb.of.version", OPENFLOW_10);
463 protocols.add("OpenFlow13");
468 protocols.add("OpenFlow10");
471 bridge.setProtocols(protocols);
472 updateOperationStatus = this.updateRow(node, bridge.getSchema().getName(),
473 null, bridgeUUID, bridge.getRow());
474 logger.debug("Bridge {} updated to {} with Status {}", bridgeUUID,
475 protocols.toArray()[0],updateOperationStatus);
477 } catch (SchemaVersionMismatchException e){
478 logger.debug(e.toString());
481 // If we fail to update the protocols
482 if (updateOperationStatus != null && !updateOperationStatus.isSuccess()) {
483 return updateOperationStatus.isSuccess();
486 Status status = null;
487 List<InetAddress> ofControllerAddrs = this.getControllerIPAddresses(connection);
488 short ofControllerPort = getControllerOFPort();
489 for (InetAddress ofControllerAddress : ofControllerAddrs) {
490 String newController = "tcp:"+ofControllerAddress.getHostAddress()+":"+ofControllerPort;
491 Controller controllerRow = connection.getClient().createTypedRowWrapper(Controller.class);
492 controllerRow.setTarget(newController);
493 //ToDo: Status gets overwritten on each iteration. If any operation other than the last fails it's ignored.
494 status = this.insertRow(node, controllerRow.getSchema().getName(), bridgeUUID, controllerRow.getRow());
497 if (status != null) {
498 return status.isSuccess();
505 public Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
506 if (connectionService == null) {
507 logger.error("Couldn't refer to the ConnectionService");
512 Connection connection = connectionService.getConnection(node);
513 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
515 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
516 for (String uuid : brTableCache.keySet()) {
517 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
518 if (bridge.getName().contains(bridgeIdentifier)) {
519 return setOFController(node, uuid);
522 } catch(Exception e) {
523 logger.error("Error in setBridgeOFController()",e);
529 public <T extends TypedBaseTable<?>> String getTableName(Node node, Class<T> typedClass) {
530 Connection connection = connectionService.getConnection(node);
531 if (connection == null) return null;
532 OvsdbClient client = connection.getClient();
533 TypedBaseTable<?> typedTable = client.getTypedRowWrapper(typedClass, null);
534 if (typedTable == null) return null;
535 return typedTable.getSchema().getName();
539 public <T extends TypedBaseTable<?>> T getTypedRow(Node node, Class<T> typedClass, Row row) {
540 Connection connection = connectionService.getConnection(node);
541 if (connection == null) return null;
542 OvsdbClient client = connection.getClient();
543 return (T)client.getTypedRowWrapper(typedClass, row);
547 public <T extends TypedBaseTable<?>> T createTypedRow(Node node, Class<T> typedClass) {
548 Connection connection = connectionService.getConnection(node);
549 if (connection == null) return null;
550 OvsdbClient client = connection.getClient();
551 return client.createTypedRowWrapper(typedClass);
554 public void _ovsconnect (CommandInterpreter ci) {
555 String bridgeName = ci.nextArgument();
556 if (bridgeName == null) {
557 ci.println("Please enter Bridge Name");
561 String ovsdbserver = ci.nextArgument();
562 if (ovsdbserver == null) {
563 ci.println("Please enter valid IP-Address");
567 InetAddress.getByName(ovsdbserver);
568 } catch (UnknownHostException e) {
569 logger.error("Unable to resolve " + ovsdbserver, e);
570 ci.println("Please enter valid IP-Address");
573 String port = ci.nextArgument();
578 ci.println("connecting to ovsdb server : "+ovsdbserver+":"+port+" ... ");
579 Map<ConnectionConstants, String> params = new HashMap<ConnectionConstants, String>();
580 params.put(ConnectionConstants.ADDRESS, ovsdbserver);
581 params.put(ConnectionConstants.PORT, port);
582 Node node = connectionService.connect(bridgeName, params);
583 if (node != null) ci.println("Node Name: "+node.toString());
584 else ci.println("Could not connect to Node");
587 public void _addBridge (CommandInterpreter ci) {
588 String nodeName = ci.nextArgument();
589 if (nodeName == null) {
590 ci.println("Please enter Node Name");
593 String bridgeName = ci.nextArgument();
594 if (bridgeName == null) {
595 ci.println("Please enter Bridge Name");
600 Node node = Node.fromString(nodeName);
602 ci.println("Invalid Node");
605 status = this.createBridgeDomain(node, bridgeName, null);
606 ci.println("Bridge creation status : "+status.toString());
609 public void _getBridgeDomains (CommandInterpreter ci) {
610 String nodeName = ci.nextArgument();
611 if (nodeName == null) {
612 ci.println("Please enter Node Name");
616 List<String> brlist = new ArrayList<String>();
617 Node node = Node.fromString(nodeName);
618 brlist = this.getBridgeDomains(node);
620 ci.println("Invalid Node");
623 ci.println("Existing Bridges: "+brlist.toString());
626 public void _deleteBridgeDomain (CommandInterpreter ci) {
627 String nodeName = ci.nextArgument();
628 if (nodeName == null) {
629 ci.println("Please enter Node Name");
632 String bridgeName = ci.nextArgument();
633 if (bridgeName == null) {
634 ci.println("Please enter Bridge Name");
638 Node node = Node.fromString(nodeName);
640 ci.println("Invalid Node");
643 status = this.deleteBridgeDomain(node, bridgeName);
644 ci.println("Bridge deletion status : "+status.toString());
647 public void _addPort (CommandInterpreter ci) {
648 String nodeName = ci.nextArgument();
649 if (nodeName == null) {
650 ci.println("Please enter Node Name");
654 String bridgeName = ci.nextArgument();
655 if (bridgeName == null) {
656 ci.println("Please enter Bridge Name");
660 String portName = ci.nextArgument();
661 if (portName == null) {
662 ci.println("Please enter Port Name");
666 String type = ci.nextArgument();
668 Map<String, String> configs = new HashMap<String, String>();
670 String configKey = ci.nextArgument();
671 if (configKey == null) break;
672 String configValue = ci.nextArgument();
673 if (configValue == null) break;
674 configs.put(configKey, configValue);
677 Map<ConfigConstants, Object> customConfigs = null;
679 customConfigs = new HashMap<ConfigConstants, Object>();
680 customConfigs.put(ConfigConstants.TYPE, type);
683 if (configs.size() > 0) {
684 if (customConfigs == null) customConfigs = new HashMap<ConfigConstants, Object>();
685 customConfigs.put(ConfigConstants.CUSTOM, configs);
686 ci.println(customConfigs.toString());
689 Node node = Node.fromString(nodeName);
691 ci.println("Invalid Node");
694 status = this.addPort(node, bridgeName, portName, customConfigs);
695 ci.println("Port creation status : "+status.toString());
698 public void _deletePort (CommandInterpreter ci) {
699 String nodeName = ci.nextArgument();
700 if (nodeName == null) {
701 ci.println("Please enter Node Name");
705 String bridgeName = ci.nextArgument();
706 if (bridgeName == null) {
707 ci.println("Please enter Bridge Name");
711 String portName = ci.nextArgument();
712 if (portName == null) {
713 ci.println("Please enter Port Name");
718 Node node = Node.fromString(nodeName);
720 ci.println("Invalid Node");
723 status = this.deletePort(node, bridgeName, portName);
724 ci.println("Port deletion status : "+status.toString());
727 public void _addPortVlan (CommandInterpreter ci) {
728 String nodeName = ci.nextArgument();
729 if (nodeName == null) {
730 ci.println("Please enter Node Name");
734 String bridgeName = ci.nextArgument();
735 if (bridgeName == null) {
736 ci.println("Please enter Bridge Name");
740 String portName = ci.nextArgument();
741 if (portName == null) {
742 ci.println("Please enter Port Name");
746 String vlan = ci.nextArgument();
748 ci.println("Please enter Valid Vlan");
752 Integer.parseInt(vlan);
753 } catch (NumberFormatException e) {
754 ci.println("Please enter Valid Vlan");
759 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
760 configs.put(ConfigConstants.TYPE, "VLAN");
761 configs.put(ConfigConstants.VLAN, vlan);
764 Node node = Node.fromString(nodeName);
766 ci.println("Invalid Node");
769 status = this.addPort(node, bridgeName, portName, configs);
770 ci.println("Port creation status : "+status.toString());
773 public void _addTunnel (CommandInterpreter ci) {
774 String nodeName = ci.nextArgument();
775 if (nodeName == null) {
776 ci.println("Please enter Node Name");
780 String bridgeName = ci.nextArgument();
781 if (bridgeName == null) {
782 ci.println("Please enter Bridge Name");
786 String portName = ci.nextArgument();
787 if (portName == null) {
788 ci.println("Please enter Port Name");
792 String tunnelType = ci.nextArgument();
793 if (tunnelType == null) {
794 ci.println("Please enter Tunnel Type");
798 String remoteIp = ci.nextArgument();
799 if (remoteIp == null) {
800 ci.println("Please enter valid Remote IP Address");
805 InetAddress.getByName(remoteIp);
806 } catch (Exception e) {
807 logger.error("Unable to resolve " + remoteIp, e);
808 ci.println("Please enter valid Remote IP Address");
812 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
813 configs.put(ConfigConstants.TYPE, "TUNNEL");
814 configs.put(ConfigConstants.TUNNEL_TYPE, tunnelType);
815 configs.put(ConfigConstants.DEST_IP, remoteIp);
818 Node node = Node.fromString(nodeName);
820 ci.println("Invalid Node");
823 status = this.addPort(node, bridgeName, portName, configs);
824 ci.println("Port creation status : "+status.toString());
827 public void _printCache (CommandInterpreter ci) {
828 String nodeName = ci.nextArgument();
829 if (nodeName == null) {
830 ci.println("Please enter Node Name");
833 Node node = Node.fromString(nodeName);
835 ci.println("Invalid Node");
838 ovsdbInventoryService.printCache(node);
841 public void _forceConnect (CommandInterpreter ci) {
842 String force = ci.nextArgument();
843 if (force.equalsIgnoreCase("YES")) {
846 else if (force.equalsIgnoreCase("NO")) {
847 forceConnect = false;
850 ci.println("Please enter YES or NO.");
852 ci.println("Current ForceConnect State : "+forceConnect);
856 public String getHelp() {
857 StringBuilder help = new StringBuilder();
858 help.append("---OVSDB CLI---\n");
859 help.append("\t ovsconnect <ConnectionName> <ip-address> - Connect to OVSDB\n");
860 help.append("\t addBridge <Node> <BridgeName> - Add Bridge\n");
861 help.append("\t getBridgeDomains <Node> - Get Bridges\n");
862 help.append("\t deleteBridgeDomain <Node> <BridgeName> - Delete a Bridge\n");
863 help.append("\t addPort <Node> <BridgeName> <PortName> <type> <options pairs> - Add Port\n");
864 help.append("\t deletePort <Node> <BridgeName> <PortName> - Delete Port\n");
865 help.append("\t addPortVlan <Node> <BridgeName> <PortName> <vlan> - Add Port, Vlan\n");
866 help.append("\t addTunnel <Node> <Bridge> <Port> <tunnel-type> <remote-ip> - Add Tunnel\n");
867 help.append("\t printCache <Node> - Prints Table Cache");
868 return help.toString();
874 * @param node Node serving this configuration service
875 * @param bridgeIdentifier String representation of a Bridge Connector
876 * @return Bridge Connector configurations
880 public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> configs) {
881 Connection connection = connectionService.getConnection(node);
882 OvsdbClient client = connection.getClient();
883 Bridge bridge = client.createTypedRowWrapper(Bridge.class);
884 bridge.setName(bridgeIdentifier);
886 String ovsTableUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
887 return this.insertRow(node, bridge.getSchema().getName(), ovsTableUuid, bridge.getRow());
891 * Create a Port Attached to a Bridge
892 * Ex. ovs-vsctl add-port br0 vif0
893 * @param node Node serving this configuration service
894 * @param bridgeIdentifier String representation of a Bridge Domain
895 * @param portIdentifier String representation of a user defined Port Name
899 public Status addPort(Node node, String bridgeIdentifier, String portIdentifier,
900 Map<ConfigConstants, Object> configs) {
901 Connection connection = connectionService.getConnection(node);
902 OvsdbClient client = connection.getClient();
904 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
905 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
906 if (rows == null || rows.size() == 0) {
907 return new Status(StatusCode.NOTFOUND);
909 for (String bridgeUuid : rows.keySet()) {
910 Row bridgeRow = rows.get(bridgeUuid);
911 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
912 if (bridge.getName().equals(bridgeIdentifier)) break;
914 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
915 return new Status(StatusCode.NOTFOUND);
918 Map<String, String> options = null;
920 Set<Long> tags = null;
921 if (configs != null) {
922 type = (String) configs.get(ConfigConstants.TYPE);
923 Map<String, String> customConfigs = (Map<String, String>) configs.get(ConfigConstants.CUSTOM);
924 if (customConfigs != null) {
925 options = new HashMap<String, String>();
926 for (String customConfig : customConfigs.keySet()) {
927 options.put(customConfig, customConfigs.get(customConfig));
933 logger.debug("Port type : " + type);
934 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.VLAN.name())) {
935 tags = new HashSet<Long>();
936 tags.add(Long.parseLong((String)configs.get(ConfigConstants.VLAN)));
940 Port port = client.createTypedRowWrapper(Port.class);
941 port.setName(portIdentifier);
942 if (tags != null) port.setTag(tags);
943 StatusWithUuid portStatus = this.insertRow(node, port.getSchema().getName(), bridge.getUuid().toString(), port.getRow());
945 if (!portStatus.isSuccess()) return portStatus;
946 // Ugly hack by adding a sleep for the Monitor Update to catch up.
947 // TODO : Remove this once the Select operation is in place.
948 // We are currently relying on the local Cache for any GET operation and that might fail if we try to
949 // fetch the last installed entry. Hence we need the Select operation to work.
953 } catch (InterruptedException e) {
954 // TODO Auto-generated catch block
958 Interface interfaceRow = client.createTypedRowWrapper(Interface.class);
959 ConcurrentMap<String, Row> intfRows = this.getRows(node, interfaceRow.getSchema().getName());
960 if (intfRows == null || intfRows.size() == 0) {
961 return new Status(StatusCode.NOTFOUND);
963 for (String intfUuid : intfRows.keySet()) {
964 Row intfRow = intfRows.get(intfUuid);
965 interfaceRow = client.getTypedRowWrapper(Interface.class, intfRow);
966 if (interfaceRow == null || interfaceRow.getName() == null) continue;
967 if (interfaceRow.getName().equals(portIdentifier)) break;
969 if (interfaceRow.getName() == null || !interfaceRow.getName().equals(portIdentifier)) {
970 return new Status(StatusCode.NOTFOUND);
972 Interface updateInterface = client.createTypedRowWrapper(Interface.class);
974 logger.debug("Interface type : " + type);
975 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.TUNNEL.name())) {
976 updateInterface.setType((String)configs.get(ConfigConstants.TUNNEL_TYPE));
977 if (options == null) options = new HashMap<String, String>();
978 options.put("remote_ip", (String)configs.get(ConfigConstants.DEST_IP));
979 } else if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.PATCH.name()) ||
980 type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.INTERNAL.name())) {
981 updateInterface.setType(type.toLowerCase());
984 if (options != null) {
985 updateInterface.setOptions(options);
988 Status intfStatus = null;
989 intfStatus = this.updateRow(node, interfaceRow.getSchema().getName(), portStatus.getUuid().toString(),
990 interfaceRow.getUuid().toString(), updateInterface.getRow());
992 if (intfStatus.isSuccess()) return portStatus;
997 * Implements the OVS Connection for Managers
999 * @param node Node serving this configuration service
1000 * @param managerip String Representing IP and connection types
1002 @SuppressWarnings("unchecked")
1004 public boolean setManager(Node node, String managerip) {
1005 Connection connection = connectionService.getConnection(node);
1006 OvsdbClient client = connection.getClient();
1007 Manager manager = client.createTypedRowWrapper(Manager.class);
1008 manager.setTarget(ImmutableSet.of(managerip));
1010 OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
1011 ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
1012 if (row == null || row.size() == 0) {
1015 String ovsTableUuid = (String)row.keySet().toArray()[0];
1017 Status status = this.insertRow(node, manager.getSchema().getName(), ovsTableUuid, manager.getRow());
1018 return status.isSuccess();
1023 public Status addBridgeDomainConfig(Node node, String bridgeIdentfier,
1024 Map<ConfigConstants, Object> configs) {
1025 String mgmt = (String)configs.get(ConfigConstants.MGMT);
1027 if (setManager(node, mgmt)) return new Status(StatusCode.SUCCESS);
1029 return new Status(StatusCode.BADREQUEST);
1034 public Status deletePort(Node node, String bridgeIdentifier, String portIdentifier) {
1035 Connection connection = connectionService.getConnection(node);
1036 OvsdbClient client = connection.getClient();
1038 Port port = client.getTypedRowWrapper(Port.class, null);
1039 ConcurrentMap<String, Row> rows = this.getRows(node, port.getSchema().getName());
1040 if (rows == null || rows.size() == 0) {
1041 return new Status(StatusCode.NOTFOUND);
1043 for (String portUuid : rows.keySet()) {
1044 Row portRow = rows.get(portUuid);
1045 port = client.getTypedRowWrapper(Port.class, portRow);
1046 if (port.getName().equals(portIdentifier)) break;
1048 if (port.getName() == null || !port.getName().equals(portIdentifier)) {
1049 return new Status(StatusCode.NOTFOUND);
1051 return this.deleteRow(node, port.getSchema().getName(), port.getUuid().toString());
1056 public Status deleteBridgeDomain(Node node, String bridgeIdentifier) {
1057 Connection connection = connectionService.getConnection(node);
1058 OvsdbClient client = connection.getClient();
1060 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
1061 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
1062 if (rows == null || rows.size() == 0) {
1063 return new Status(StatusCode.NOTFOUND);
1065 for (String bridgeUuid : rows.keySet()) {
1066 Row bridgeRow = rows.get(bridgeUuid);
1067 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
1068 if (bridge.getName().equals(bridgeIdentifier)) break;
1070 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
1071 return new Status(StatusCode.NOTFOUND);
1073 return this.deleteRow(node, bridge.getSchema().getName(), bridge.getUuid().toString());
1077 public List<String> getBridgeDomains(Node node) {
1078 if (connectionService == null) {
1079 logger.error("Couldn't refer to the ConnectionService");
1083 Connection connection = connectionService.getConnection(node);
1084 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
1085 List<String> brlist = new ArrayList<String>();
1086 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
1087 if(brTableCache != null){
1088 for (String uuid : brTableCache.keySet()) {
1089 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
1090 brlist.add(bridge.getName());
1097 public NodeConnector getNodeConnector(Node arg0, String arg1, String arg2) {
1103 public Status addPortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1104 Map<ConfigConstants, Object> configs) {
1105 // TODO Auto-generated method stub
1111 public Node getBridgeDomainNode(Node node, String bridgeIdentifier) {
1112 // TODO Auto-generated method stub
1118 public Map<ConfigConstants, Object> getPortConfigs(Node node, String bridgeIdentifier,
1119 String portIdentifier) {
1120 // TODO Auto-generated method stub
1126 public Status removeBridgeDomainConfig(Node node, String bridgeIdentifier,
1127 Map<ConfigConstants, Object> configs) {
1128 // TODO Auto-generated method stub
1134 public Status removePortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1135 Map<ConfigConstants, Object> configs) {
1136 // TODO Auto-generated method stub
1142 public Map<ConfigConstants, Object> getBridgeDomainConfigs(Node node, String bridgeIdentifier) {
1143 // TODO Auto-generated method stub
1148 // SCHEMA-INDEPENDENT Configuration Service APIs
1150 private String getTableNameForRowUuid(Node node, String databaseName, UUID rowUuid) {
1151 ConcurrentMap<String, ConcurrentMap<String, Row>> cache = ovsdbInventoryService.getCache(node, databaseName);
1152 if (cache == null) return null;
1153 for (String tableName : cache.keySet()) {
1154 ConcurrentMap<String, Row> rows = cache.get(tableName);
1155 if (rows.get(rowUuid.toString()) != null) {
1162 private String getReferencingColumn (TableSchema<?> parentTableSchema, String childTableName) throws OvsdbPluginException {
1163 Map<String, ColumnSchema> columnSchemas = parentTableSchema.getColumnSchemas();
1164 String refColumn = null;
1165 for (String columnName : columnSchemas.keySet()) {
1166 ColumnSchema columnSchema = columnSchemas.get(columnName);
1167 if (columnSchema.getType().getBaseType().getClass().equals(UuidBaseType.class)) {
1168 UuidBaseType refType = (UuidBaseType)columnSchema.getType().getBaseType();
1169 if (refType.getRefTable() != null && refType.getRefTable().equalsIgnoreCase(childTableName)) {
1170 if (refColumn == null) {
1171 refColumn = columnName;
1173 throw new OvsdbPluginException("Multiple Referencing Columns for "+ childTableName +" on "+ parentTableSchema.getName());
1178 if (refColumn != null) {
1181 throw new OvsdbPluginException("No Referencing Column for "+childTableName+" on "+parentTableSchema.getName());
1184 * A common Insert Transaction convenience method that populates the TransactionBuilder with insert operation
1185 * for a Child Row and also mutates the parent row with the UUID of the inserted Child.
1187 private void processInsertTransaction(OvsdbClient client, String databaseName, String childTable,
1188 String parentTable, UUID parentUuid, String parentColumn, String namedUuid,
1189 Row<GenericTableSchema> row,
1190 TransactionBuilder transactionBuilder) {
1191 // Insert the row as the first transaction entry
1192 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1193 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
1194 transactionBuilder.add(op.insert(childTableSchema, row)
1195 .withId(namedUuid));
1197 // Followed by the Mutation
1198 if (parentColumn != null) {
1199 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1200 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
1201 ColumnSchema<GenericTableSchema, UUID> _uuid = parentTableSchema.column("_uuid", UUID.class);
1204 .add(op.mutate(parentTableSchema)
1205 .addMutation(parentColumnSchema, Mutator.INSERT, new UUID(namedUuid))
1206 .where(_uuid.opEqual(parentUuid))
1212 * insert a Row in a Table of a specified Database Schema.
1214 * This method can insert just a single Row specified in the row parameter.
1215 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1216 * can insert a hierarchy of rows with parent-child relationship.
1218 * @param node OVSDB Node
1219 * @param databaseName Database Name that represents the Schema supported by the node.
1220 * @param tableName Table on which the row is inserted
1221 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1222 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1223 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1224 * @param row Row of table Content to be inserted
1225 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1226 * @return UUID of the inserted Row
1229 public UUID insertRow(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1230 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1231 Connection connection = connectionService.getConnection(node);
1232 OvsdbClient client = connection.getClient();
1233 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1234 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1236 Row<GenericTableSchema> processedRow = this.insertTree(node, databaseName, tableName, parentTable, parentUuid, parentColumn, row);
1238 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
1239 Column<GenericTableSchema, UUID> uuid = processedRow.getColumn(_uuid);
1240 return uuid.getData();
1244 * insert a Row in a Table of a specified Database Schema. This is a convenience method on top of
1245 * {@link insertRow(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertRow}
1246 * which assumes that OVSDB schema implementation that corresponds to the databaseName will provide
1247 * the necessary service to populate the Parent Table Name and Parent Column Name.
1249 * This method can insert just a single Row specified in the row parameter.
1250 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1251 * can insert a hierarchy of rows with parent-child relationship.
1253 * @param node OVSDB Node
1254 * @param databaseName Database Name that represents the Schema supported by the node.
1255 * @param tableName Table on which the row is inserted
1256 * @param parentUuid UUID of the parent table to which this operation will result in attaching/mutating.
1257 * @param row Row of table Content to be inserted
1258 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1259 * @return UUID of the inserted Row
1262 public UUID insertRow(Node node, String databaseName, String tableName,
1263 UUID parentRowUuid, Row<GenericTableSchema> row)
1264 throws OvsdbPluginException {
1265 return this.insertRow(node, databaseName, tableName, null, parentRowUuid, null, row);
1269 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct
1271 * @param node OVSDB Node
1272 * @param databaseName Database Name that represents the Schema supported by the node.
1273 * @param tableName Table on which the row is inserted
1274 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1275 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1276 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1277 * @param row Row Tree with parent-child relationships via column of type refTable.
1278 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1279 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1282 public Row<GenericTableSchema> insertTree(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1283 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1284 Connection connection = connectionService.getConnection(node);
1285 OvsdbClient client = connection.getClient();
1287 if (databaseName == null || tableName == null) {
1288 throw new OvsdbPluginException("databaseName, tableName and parentUuid are Mandatory Parameters");
1291 if (parentTable == null && parentUuid != null) {
1292 parentTable = this.getTableNameForRowUuid(node, databaseName, parentUuid);
1295 if (parentColumn == null && parentTable != null) {
1296 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1297 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1298 parentColumn = this.getReferencingColumn(parentTableSchema, tableName);
1301 logger.debug("insertTree Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
1302 client.getConnectionInfo(), tableName, parentTable, parentColumn, parentUuid, row);
1304 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows = Maps.newConcurrentMap();
1305 extractReferencedRows(node, databaseName, row, referencedRows, 0);
1306 DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
1307 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1309 String namedUuid = "Transaction_"+ tableName;
1310 this.processInsertTransaction(client, databaseName, tableName, parentTable, parentUuid,
1311 parentColumn, namedUuid, row, transactionBuilder);
1313 int referencedRowsInsertIndex = transactionBuilder.getOperations().size();
1314 // Insert Referenced Rows
1315 if (referencedRows != null) {
1316 for (UUID refUuid : referencedRows.keySet()) {
1317 Map.Entry<String, Row<GenericTableSchema>> referencedRow = referencedRows.get(refUuid);
1318 TableSchema<GenericTableSchema> refTableSchema = dbSchema.table(referencedRow.getKey(), GenericTableSchema.class);
1319 transactionBuilder.add(op.insert(refTableSchema, referencedRow.getValue())
1320 .withId(refUuid.toString()));
1324 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1325 List<OperationResult> operationResults;
1327 operationResults = results.get();
1328 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1329 throw new OvsdbPluginException("Insert Operation Failed");
1331 for (OperationResult result : operationResults) {
1332 if (result.getError() != null) {
1333 throw new OvsdbPluginException("Insert Operation Failed with Error : "+result.getError().toString());
1336 return getNormalizedRow(dbSchema, tableName, row, referencedRows, operationResults, referencedRowsInsertIndex);
1337 } catch (InterruptedException | ExecutionException e) {
1338 throw new OvsdbPluginException("Exception : "+e.getLocalizedMessage());
1343 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct.
1344 * This is a convenience method on top of {@link #insertTree(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertTree}
1346 * @param node OVSDB Node
1347 * @param databaseName Database Name that represents the Schema supported by the node.
1348 * @param tableName Table on which the row is inserted
1349 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1350 * @param row Row Tree with parent-child relationships via column of type refTable.
1351 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1352 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1355 public Row<GenericTableSchema> insertTree(Node node, String databaseName,
1356 String tableName, UUID parentRowUuid, Row<GenericTableSchema> row)
1357 throws OvsdbPluginException {
1358 return this.insertTree(node, databaseName, tableName, null, parentRowUuid, null, row);
1362 * Convenience method that helps insertTree to extract Rows that are referenced directly from within a primary row
1363 * to be inserted. These referenced rows are *NOT* defined in the OVSDB specification. But, we felt that from a northbound
1364 * application standpoint, having such an option is useful and our implementation supports it for applications to make use of.
1365 * In short, whichever ColumnSchema is based on an UUID (refered by RefTable in schema), applications can directly insert an
1366 * entire row and this method will help navigate it through and identify such cases.
1367 * After identifying these Referenced Rows, it will modify the primary row with Named UUIDs and fill out the referencedRows
1368 * Map structure so that insertTree can insert all the Rows defined in this Tree of rows in a single transaction with automatic
1369 * Mutation on the parent rows.
1371 * @param node OVSDB Node
1372 * @param dbName Database Name that represents the Schema supported by the node.
1373 * @param row Row Tree with parent-child relationships via column of type refTable.
1374 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1375 * @param namedUuidSuffix Named UUID must be unique for every new Row insert within a given transaction.
1376 * This index will help to retain the uniqueness.
1378 private void extractReferencedRows(Node node, String dbName, Row<GenericTableSchema> row,
1379 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1380 int namedUuidSuffix) {
1381 OvsdbClient client = connectionService.getConnection(node).getClient();
1382 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1383 for (Column column : columns) {
1384 if (column.getData() != null) {
1385 if (column.getData() instanceof ReferencedRow) {
1386 ReferencedRow refRowObject = (ReferencedRow)column.getData();
1387 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1388 column.setData(refUuid);
1390 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1391 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1392 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1393 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1394 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1395 } catch (InterruptedException | ExecutionException e) {
1396 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1398 } else if (column.getData() instanceof OvsdbSet) {
1399 OvsdbSet<Object> setObject = (OvsdbSet<Object>)column.getData();
1400 OvsdbSet<Object> modifiedSet = new OvsdbSet<Object>();
1401 for (Object obj : setObject) {
1402 if (obj instanceof ReferencedRow) {
1403 ReferencedRow refRowObject = (ReferencedRow)obj;
1404 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1405 modifiedSet.add(refUuid);
1407 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1408 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1409 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1410 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1411 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1412 } catch (InterruptedException | ExecutionException e) {
1413 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1416 modifiedSet.add(obj);
1419 column.setData(modifiedSet);
1426 * getNormalizedRow normalizes the Row from a namedUuid Space as defined in extractReferencedRows to the actual Uuid as created
1427 * by the Ovsdb-server. In order to perform this normalization, it processes the operation results for a corresponding Transaction
1428 * where the referenced rows are inserted along with the Primary row. It changes the named-Uuid to the actual Uuid before returning
1429 * the Row to the application.
1431 * @param dbSchema Database Schema supported by the node.
1432 * @param row Row Tree with parent-child relationships via column of type refTable.
1433 * @param tableName Table on which the row is inserted
1434 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1435 * @param operationResults Operation Results returned by ovsdb-server for the insertTree transaction
1436 * @param referencedRowsInsertIndex Starting index in OperationResults from which the ReferencedRow insert results begin.
1439 private Row<GenericTableSchema> getNormalizedRow(DatabaseSchema dbSchema, String tableName, Row<GenericTableSchema> row,
1440 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1441 List<OperationResult> operationResults, int referencedRowsInsertIndex) {
1442 UUID primaryRowUuid = operationResults.get(0).getUuid();
1443 TableSchema<GenericTableSchema> primaryRowTableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1444 ColumnSchema<GenericTableSchema, UUID> _uuid = primaryRowTableSchema.column("_uuid", UUID.class);
1445 if (_uuid != null) {
1446 Column<GenericTableSchema, UUID> _uuidColumn = new Column<GenericTableSchema, UUID>(_uuid, primaryRowUuid);
1447 row.addColumn("_uuid", _uuidColumn);
1450 if (referencedRows != null) {
1451 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1452 if (referencedRows != null) {
1453 for (int idx=0; idx < referencedRows.keySet().size(); idx++) {
1454 UUID refUuid = (UUID) referencedRows.keySet().toArray()[idx];
1455 for (Column column : columns) {
1456 if (column.getData() != null) {
1457 if ((column.getData() instanceof UUID) && column.getData().equals(refUuid)) {
1458 column.setData(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1459 } else if ((column.getData() instanceof OvsdbSet) && ((OvsdbSet)column.getData()).contains(refUuid)) {
1460 OvsdbSet<UUID> refSet = (OvsdbSet<UUID>)column.getData();
1461 refSet.remove(refUuid);
1462 refSet.add(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1473 public Row<GenericTableSchema> updateRow(Node node, String databaseName,
1474 String tableName, UUID rowUuid, Row<GenericTableSchema> row,
1475 boolean overwrite) throws OvsdbPluginException {
1476 Connection connection = connectionService.getConnection(node);
1477 OvsdbClient client = connection.getClient();
1479 logger.debug("updateRow : Connection : {} databaseName : {} tableName : {} rowUUID : {} row : {}",
1480 client.getConnectionInfo(), databaseName, tableName, rowUuid, row.toString());
1482 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1483 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1484 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1485 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
1486 transactionBuilder.add(op.update(tableSchema, row)
1487 .where(_uuid.opEqual(rowUuid))
1490 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1491 List<OperationResult> operationResults = results.get();
1492 for (OperationResult result : operationResults) {
1493 if (result.getError() != null) {
1494 throw new OvsdbPluginException("Error updating row : "+ result.getError());
1497 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1498 throw new OvsdbPluginException("Failed to update row. Please check OVS logs for more info.");
1501 return this.getRow(node, databaseName, tableName, rowUuid);
1502 } catch(Exception e){
1503 throw new OvsdbPluginException("Error updating row due to an exception "+ e.getMessage());
1508 public void deleteRow(Node node, String databaseName, String tableName, String parentTable, UUID parentRowUuid,
1509 String parentColumn, UUID rowUuid) throws OvsdbPluginException {
1510 Connection connection = connectionService.getConnection(node);
1511 OvsdbClient client = connection.getClient();
1513 if (parentTable == null && parentRowUuid != null) {
1514 parentTable = this.getTableNameForRowUuid(node, databaseName, parentRowUuid);
1517 if (parentColumn == null && parentTable != null) {
1518 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1519 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1520 parentColumn = this.getReferencingColumn(parentTableSchema, tableName);
1523 logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
1524 client.getConnectionInfo(), databaseName, tableName, rowUuid, parentTable, parentColumn);
1526 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1527 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1528 this.processDeleteTransaction(client, databaseName, tableName,
1529 parentTable, parentColumn, rowUuid.toString(), transactionBuilder);
1531 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1532 List<OperationResult> operationResults;
1534 operationResults = results.get();
1535 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1536 throw new OvsdbPluginException("Delete Operation Failed");
1538 for (OperationResult result : operationResults) {
1539 if (result.getError() != null) {
1540 throw new OvsdbPluginException("Delete Operation Failed with Error : "+result.getError().toString());
1543 } catch (InterruptedException | ExecutionException e) {
1544 // TODO Auto-generated catch block
1545 e.printStackTrace();
1550 public void deleteRow(Node node, String databaseName, String tableName, UUID rowUuid) throws OvsdbPluginException {
1551 this.deleteRow(node, databaseName, tableName, null, null, null, rowUuid);
1555 public Row<GenericTableSchema> getRow(Node node, String databaseName,
1556 String tableName, UUID uuid) throws OvsdbPluginException {
1557 ConcurrentMap<UUID, Row<GenericTableSchema>> rows = this.getRows(node, databaseName, tableName);
1559 return rows.get(uuid);
1565 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1566 String databaseName, String tableName) throws OvsdbPluginException {
1567 ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, databaseName, tableName);
1568 if (ovsTable == null) return null;
1569 ConcurrentMap<UUID, Row<GenericTableSchema>> tableDB = Maps.newConcurrentMap();
1570 for (String uuidStr : ovsTable.keySet()) {
1571 tableDB.put(new UUID(uuidStr), ovsTable.get(uuidStr));
1577 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1578 String databaseName, String tableName, String fiqlQuery)
1579 throws OvsdbPluginException {
1580 return this.getRows(node, databaseName, tableName);
1584 public List<String> getTables(Node node, String databaseName) throws OvsdbPluginException {
1585 ConcurrentMap<String, ConcurrentMap<String, Row>> cache = ovsdbInventoryService.getCache(node, databaseName);
1586 if (cache == null) return null;
1587 return new ArrayList<String>(cache.keySet());