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.opendaylight.ovsdb.utils.config.ConfigProperties;
71 import org.osgi.framework.BundleContext;
72 import org.osgi.framework.FrameworkUtil;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
76 import com.fasterxml.jackson.databind.node.ObjectNode;
77 import com.google.common.collect.ImmutableSet;
78 import com.google.common.collect.Maps;
79 import com.google.common.collect.Sets;
80 import com.google.common.util.concurrent.ListenableFuture;
82 public class ConfigurationServiceImpl implements IPluginInBridgeDomainConfigService,
83 OvsdbConfigurationService,
87 private static final Logger logger = LoggerFactory
88 .getLogger(ConfigurationServiceImpl.class);
90 OvsdbConnectionService connectionService;
91 OvsdbInventoryService ovsdbInventoryService;
92 boolean forceConnect = false;
93 protected static final String OPENFLOW_10 = "1.0";
94 protected static final String OPENFLOW_13 = "1.3";
100 * Function called by the dependency manager when at least one dependency
101 * become unsatisfied or when the component is shutting down because for
102 * example bundle is being stopped.
109 * Function called by dependency manager after "init ()" is called and after
110 * the services provided by the class are registered in the service registry
114 registerWithOSGIConsole();
117 private void registerWithOSGIConsole() {
118 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
120 bundleContext.registerService(CommandProvider.class.getName(), this,
125 * Function called by the dependency manager before the services exported by
126 * the component are unregistered, this will be followed by a "destroy ()"
133 public void setConnectionServiceInternal(OvsdbConnectionService connectionService) {
134 this.connectionService = connectionService;
137 public void unsetConnectionServiceInternal(OvsdbConnectionService connectionService) {
138 if (this.connectionService == connectionService) {
139 this.connectionService = null;
143 public void setOvsdbInventoryService(OvsdbInventoryService ovsdbInventoryService) {
144 this.ovsdbInventoryService = ovsdbInventoryService;
147 public void unsetInventoryServiceInternal(OvsdbInventoryService ovsdbInventoryService) {
148 if (this.ovsdbInventoryService == ovsdbInventoryService) {
149 this.ovsdbInventoryService = null;
153 private IClusterGlobalServices clusterServices;
155 public void setClusterServices(IClusterGlobalServices i) {
156 this.clusterServices = i;
159 public void unsetClusterServices(IClusterGlobalServices i) {
160 if (this.clusterServices == i) {
161 this.clusterServices = null;
165 private Connection getConnection (Node node) {
166 Connection connection = connectionService.getConnection(node);
167 if (connection == null || !connection.getClient().isActive()) {
174 * There are a few Open_vSwitch schema specific special case handling to be done for
175 * the older API (such as by inserting a mandatory Interface row automatically upon inserting
178 private void handleSpecialInsertCase(OvsdbClient client, String databaseName,
179 String tableName, String uuid, Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
180 Port port = client.getTypedRowWrapper(Port.class, null);
181 if (databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME) && tableName.equals(port.getSchema().getName())) {
182 port = client.getTypedRowWrapper(Port.class, row);
183 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
184 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
185 ColumnSchema<GenericTableSchema, Set<UUID>> columnSchema = tableSchema.multiValuedColumn("interfaces", UUID.class);
186 String namedUuid = "Special_"+tableName;
187 List<Operation> priorOperations = transactionBuilder.getOperations();
188 Insert portOperation = (Insert)priorOperations.get(0);
189 portOperation.value(columnSchema, new UUID(namedUuid));
191 Column<GenericTableSchema, ?> nameColumn = port.getNameColumn();
192 List<Column<GenericTableSchema, ?>> columns = new ArrayList<Column<GenericTableSchema, ?>>();
193 columns.add(nameColumn);
194 Row<GenericTableSchema> intfRow = new Row<GenericTableSchema>(tableSchema, columns);
195 this.processTypedInsertTransaction(client, databaseName, "Interface", null, null, null, namedUuid, intfRow, transactionBuilder);
200 * A common Transaction that takes in old API style Parent_uuid and inserts a mutation on
201 * the parent table for the newly inserted Child.
202 * Due to some additional special case(s), the Transaction is further amended by handleSpecialInsertCase
204 private void processTypedInsertTransaction(OvsdbClient client, String databaseName, String childTable,
205 String parentTable, String parentUuid, String parentColumn, String namedUuid,
206 Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
207 this.processInsertTransaction(client, databaseName, childTable, parentTable, new UUID(parentUuid), parentColumn,
208 namedUuid, row, transactionBuilder);
210 * There are a few Open_vSwitch schema specific special case handling to be done for
211 * the older API (such as by inserting a mandatory Interface row automatically upon inserting
214 handleSpecialInsertCase(client, databaseName, childTable, namedUuid, row, transactionBuilder);
218 * TODO : Move all the Special Cases out of ConfigurationService and into the Schema specific bundles.
219 * But that makes plugin more reliant on the Typed Bundles more than just API wrapper.
220 * Keeping these Special Handling locally till we introduce the full schema independent APIs in the
223 public String getSpecialCaseParentUUID(Node node, String databaseName, String childTableName) {
224 if (!databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) return null;
225 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(childTableName);
226 if (parentColumn != null && parentColumn[0].equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) {
227 Connection connection = connectionService.getConnection(node);
228 OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
229 ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
230 if (row == null || row.size() == 0) return null;
231 return (String)row.keySet().toArray()[0];
237 * Though this is a New API that takes in Row object, this still is considered a
238 * Deprecated call because of the assumption with a Single Row insertion.
239 * An ideal insertRow must be able to take in multiple Rows, which includes the
240 * Row being inserted in one Table and other Rows that needs mutate in other Tables.
244 public StatusWithUuid insertRow(Node node, String tableName, String parentUuid, Row<GenericTableSchema> row) {
245 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
246 if (parentColumn == null) {
247 parentColumn = new String[]{null, null};
250 Connection connection = connectionService.getConnection(node);
251 OvsdbClient client = connection.getClient();
253 if (parentUuid == null) {
254 parentUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
256 logger.debug("insertRow Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
257 client.getConnectionInfo(), tableName, parentColumn[0], parentColumn[1], parentUuid, row);
259 DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
260 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
262 String namedUuid = "Transaction_"+ tableName;
263 this.processTypedInsertTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
264 parentColumn[0], parentUuid, parentColumn[1], namedUuid,
265 row, transactionBuilder);
267 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
268 List<OperationResult> operationResults;
270 operationResults = results.get();
271 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
272 return new StatusWithUuid(StatusCode.INTERNALERROR);
274 for (OperationResult result : operationResults) {
275 if (result.getError() != null) {
276 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
279 UUID uuid = operationResults.get(0).getUuid();
280 return new StatusWithUuid(StatusCode.SUCCESS, uuid);
281 } catch (InterruptedException | ExecutionException e) {
282 // TODO Auto-generated catch block
283 return new StatusWithUuid(StatusCode.INTERNALERROR, e.getLocalizedMessage());
290 public Status updateRow (Node node, String tableName, String parentUUID, String rowUUID, Row row) {
291 String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
292 Row<GenericTableSchema> updatedRow = this.updateRow(node, databaseName, tableName, new UUID(rowUUID), row, true);
293 return new StatusWithUuid(StatusCode.SUCCESS);
296 private void processDeleteTransaction(OvsdbClient client, String databaseName, String childTable,
297 String parentTable, String parentColumn, String uuid, TransactionBuilder transactionBuilder) {
298 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
299 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
301 if (parentColumn != null) {
302 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
303 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
305 .add(op.mutate(parentTableSchema)
306 .addMutation(parentColumnSchema, Mutator.DELETE, new UUID(uuid))
307 .where(parentColumnSchema.opIncludes(new UUID(uuid)))
311 ColumnSchema<GenericTableSchema, UUID> _uuid = childTableSchema.column("_uuid", UUID.class);
312 transactionBuilder.add(op.delete(childTableSchema)
313 .where(_uuid.opEqual(new UUID(uuid)))
319 public Status deleteRow(Node node, String tableName, String uuid) {
320 String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
321 Connection connection = connectionService.getConnection(node);
322 OvsdbClient client = connection.getClient();
324 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
325 if (parentColumn == null) {
326 parentColumn = new String[]{null, null};
329 logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
330 client.getConnectionInfo(), databaseName, tableName, uuid, parentColumn[0], parentColumn[1]);
332 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
333 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
334 this.processDeleteTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
335 parentColumn[0], parentColumn[1], uuid, transactionBuilder);
337 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
338 List<OperationResult> operationResults;
340 operationResults = results.get();
341 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
342 return new StatusWithUuid(StatusCode.INTERNALERROR);
344 for (OperationResult result : operationResults) {
345 if (result.getError() != null) {
346 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
349 } catch (InterruptedException | ExecutionException e) {
350 logger.error("Error in deleteRow()", e);
353 return new Status(StatusCode.SUCCESS);
358 public ConcurrentMap<String, Row> getRows(Node node, String tableName) {
359 ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
365 public Row getRow(Node node, String tableName, String uuid) {
366 Map<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
367 if (ovsTable == null) return null;
368 return ovsTable.get(uuid);
373 public List<String> getTables(Node node) {
374 return this.getTables(node, OvsVswitchdSchemaConstants.DATABASE_NAME);
377 private InetAddress getControllerIPAddress(Connection connection) {
378 InetAddress controllerIP = null;
380 String addressString = ConfigProperties.getProperty(this.getClass(), "ovsdb.controller.address");
382 if (addressString != null) {
384 controllerIP = InetAddress.getByName(addressString);
385 if (controllerIP != null) {
388 } catch (UnknownHostException e) {
389 logger.error("Host {} is invalid", addressString);
393 addressString = ConfigProperties.getProperty(this.getClass(), "of.address");
395 if (addressString != null) {
397 controllerIP = InetAddress.getByName(addressString);
398 if (controllerIP != null) {
401 } catch (UnknownHostException e) {
402 logger.error("Host {} is invalid", addressString);
407 controllerIP = connection.getClient().getConnectionInfo().getLocalAddress();
409 } catch (Exception e) {
410 logger.debug("Invalid connection provided to getControllerIPAddresses", e);
415 private short getControllerOFPort() {
416 Short defaultOpenFlowPort = 6633;
417 Short openFlowPort = defaultOpenFlowPort;
418 String portString = ConfigProperties.getProperty(this.getClass(), "of.listenPort");
419 if (portString != null) {
421 openFlowPort = Short.decode(portString).shortValue();
422 } catch (NumberFormatException e) {
423 logger.warn("Invalid port:{}, use default({})", portString,
430 private UUID getCurrentControllerUuid(Node node, final String controllerTableName, final String target) {
431 ConcurrentMap<String, Row> rows = this.getRows(node, controllerTableName);
434 for (Map.Entry<String, Row> entry : rows.entrySet()) {
435 Controller currController = this.getTypedRow(node, Controller.class, entry.getValue());
436 Column<GenericTableSchema, String> column = currController.getTargetColumn();
437 String currTarget = column.getData();
438 if (currTarget != null && currTarget.equalsIgnoreCase(target)) {
439 return currController.getUuid();
447 public Boolean setOFController(Node node, String bridgeUUID) throws InterruptedException, ExecutionException {
448 Connection connection = this.getConnection(node);
449 if (connection == null) {
453 Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
455 Status updateOperationStatus = null;
457 OvsdbSet<String> protocols = new OvsdbSet<String>();
459 String ofVersion = System.getProperty("ovsdb.of.version", OPENFLOW_13);
462 protocols.add("OpenFlow10");
467 protocols.add("OpenFlow13");
470 bridge.setProtocols(protocols);
471 updateOperationStatus = this.updateRow(node, bridge.getSchema().getName(),
472 null, bridgeUUID, bridge.getRow());
473 logger.debug("Bridge {} updated to {} with Status {}", bridgeUUID,
474 protocols.toArray()[0],updateOperationStatus);
476 } catch (SchemaVersionMismatchException e){
477 logger.debug(e.toString());
480 // If we fail to update the protocols
481 if (updateOperationStatus != null && !updateOperationStatus.isSuccess()) {
482 return updateOperationStatus.isSuccess();
485 Status status = null;
486 UUID currControllerUuid = null;
487 InetAddress ofControllerAddr = this.getControllerIPAddress(connection);
488 short ofControllerPort = getControllerOFPort();
489 String newControllerTarget = "tcp:"+ofControllerAddr.getHostAddress()+":"+ofControllerPort;
490 Controller newController = connection.getClient().createTypedRowWrapper(Controller.class);
491 newController.setTarget(newControllerTarget);
492 final String controllerTableName = newController.getSchema().getName();
494 currControllerUuid = getCurrentControllerUuid(node, controllerTableName, newControllerTarget);
496 if (currControllerUuid != null) {
497 bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
498 bridge.setController(Sets.newHashSet(currControllerUuid));
499 status = this.updateRow(node, bridge.getSchema().getName(), null, bridgeUUID, bridge.getRow());
501 status = this.insertRow(node, controllerTableName, bridgeUUID, newController.getRow());
504 if (status != null) {
505 return status.isSuccess();
512 public Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
513 if (connectionService == null) {
514 logger.error("Couldn't refer to the ConnectionService");
519 Connection connection = connectionService.getConnection(node);
520 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
522 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
523 for (String uuid : brTableCache.keySet()) {
524 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
525 if (bridge.getName().contains(bridgeIdentifier)) {
526 return setOFController(node, uuid);
529 } catch(Exception e) {
530 logger.error("Error in setBridgeOFController()",e);
536 public <T extends TypedBaseTable<?>> String getTableName(Node node, Class<T> typedClass) {
537 Connection connection = connectionService.getConnection(node);
538 if (connection == null) return null;
539 OvsdbClient client = connection.getClient();
540 TypedBaseTable<?> typedTable = client.getTypedRowWrapper(typedClass, null);
541 if (typedTable == null) return null;
542 return typedTable.getSchema().getName();
546 public <T extends TypedBaseTable<?>> T getTypedRow(Node node, Class<T> typedClass, Row row) {
547 Connection connection = connectionService.getConnection(node);
548 if (connection == null) return null;
549 OvsdbClient client = connection.getClient();
550 return (T)client.getTypedRowWrapper(typedClass, row);
554 public <T extends TypedBaseTable<?>> T createTypedRow(Node node, Class<T> typedClass) {
555 Connection connection = connectionService.getConnection(node);
556 if (connection == null) return null;
557 OvsdbClient client = connection.getClient();
558 return client.createTypedRowWrapper(typedClass);
561 public void _ovsconnect (CommandInterpreter ci) {
562 String bridgeName = ci.nextArgument();
563 if (bridgeName == null) {
564 ci.println("Please enter Bridge Name");
568 String ovsdbserver = ci.nextArgument();
569 if (ovsdbserver == null) {
570 ci.println("Please enter valid IP-Address");
574 InetAddress.getByName(ovsdbserver);
575 } catch (UnknownHostException e) {
576 logger.error("Unable to resolve " + ovsdbserver, e);
577 ci.println("Please enter valid IP-Address");
580 String port = ci.nextArgument();
585 ci.println("connecting to ovsdb server : "+ovsdbserver+":"+port+" ... ");
586 Map<ConnectionConstants, String> params = new HashMap<ConnectionConstants, String>();
587 params.put(ConnectionConstants.ADDRESS, ovsdbserver);
588 params.put(ConnectionConstants.PORT, port);
589 Node node = connectionService.connect(bridgeName, params);
590 if (node != null) ci.println("Node Name: "+node.toString());
591 else ci.println("Could not connect to Node");
594 public void _addBridge (CommandInterpreter ci) {
595 String nodeName = ci.nextArgument();
596 if (nodeName == null) {
597 ci.println("Please enter Node Name");
600 String bridgeName = ci.nextArgument();
601 if (bridgeName == null) {
602 ci.println("Please enter Bridge Name");
607 Node node = Node.fromString(nodeName);
609 ci.println("Invalid Node");
612 status = this.createBridgeDomain(node, bridgeName, null);
613 ci.println("Bridge creation status : "+status.toString());
616 public void _getBridgeDomains (CommandInterpreter ci) {
617 String nodeName = ci.nextArgument();
618 if (nodeName == null) {
619 ci.println("Please enter Node Name");
623 List<String> brlist = new ArrayList<String>();
624 Node node = Node.fromString(nodeName);
625 brlist = this.getBridgeDomains(node);
627 ci.println("Invalid Node");
630 ci.println("Existing Bridges: "+brlist.toString());
633 public void _deleteBridgeDomain (CommandInterpreter ci) {
634 String nodeName = ci.nextArgument();
635 if (nodeName == null) {
636 ci.println("Please enter Node Name");
639 String bridgeName = ci.nextArgument();
640 if (bridgeName == null) {
641 ci.println("Please enter Bridge Name");
645 Node node = Node.fromString(nodeName);
647 ci.println("Invalid Node");
650 status = this.deleteBridgeDomain(node, bridgeName);
651 ci.println("Bridge deletion status : "+status.toString());
654 public void _addPort (CommandInterpreter ci) {
655 String nodeName = ci.nextArgument();
656 if (nodeName == null) {
657 ci.println("Please enter Node Name");
661 String bridgeName = ci.nextArgument();
662 if (bridgeName == null) {
663 ci.println("Please enter Bridge Name");
667 String portName = ci.nextArgument();
668 if (portName == null) {
669 ci.println("Please enter Port Name");
673 String type = ci.nextArgument();
675 Map<String, String> configs = new HashMap<String, String>();
677 String configKey = ci.nextArgument();
678 if (configKey == null) break;
679 String configValue = ci.nextArgument();
680 if (configValue == null) break;
681 configs.put(configKey, configValue);
684 Map<ConfigConstants, Object> customConfigs = null;
686 customConfigs = new HashMap<ConfigConstants, Object>();
687 customConfigs.put(ConfigConstants.TYPE, type);
690 if (configs.size() > 0) {
691 if (customConfigs == null) customConfigs = new HashMap<ConfigConstants, Object>();
692 customConfigs.put(ConfigConstants.CUSTOM, configs);
693 ci.println(customConfigs.toString());
696 Node node = Node.fromString(nodeName);
698 ci.println("Invalid Node");
701 status = this.addPort(node, bridgeName, portName, customConfigs);
702 ci.println("Port creation status : "+status.toString());
705 public void _deletePort (CommandInterpreter ci) {
706 String nodeName = ci.nextArgument();
707 if (nodeName == null) {
708 ci.println("Please enter Node Name");
712 String bridgeName = ci.nextArgument();
713 if (bridgeName == null) {
714 ci.println("Please enter Bridge Name");
718 String portName = ci.nextArgument();
719 if (portName == null) {
720 ci.println("Please enter Port Name");
725 Node node = Node.fromString(nodeName);
727 ci.println("Invalid Node");
730 status = this.deletePort(node, bridgeName, portName);
731 ci.println("Port deletion status : "+status.toString());
734 public void _addPortVlan (CommandInterpreter ci) {
735 String nodeName = ci.nextArgument();
736 if (nodeName == null) {
737 ci.println("Please enter Node Name");
741 String bridgeName = ci.nextArgument();
742 if (bridgeName == null) {
743 ci.println("Please enter Bridge Name");
747 String portName = ci.nextArgument();
748 if (portName == null) {
749 ci.println("Please enter Port Name");
753 String vlan = ci.nextArgument();
755 ci.println("Please enter Valid Vlan");
759 Integer.parseInt(vlan);
760 } catch (NumberFormatException e) {
761 ci.println("Please enter Valid Vlan");
766 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
767 configs.put(ConfigConstants.TYPE, "VLAN");
768 configs.put(ConfigConstants.VLAN, vlan);
771 Node node = Node.fromString(nodeName);
773 ci.println("Invalid Node");
776 status = this.addPort(node, bridgeName, portName, configs);
777 ci.println("Port creation status : "+status.toString());
780 public void _addTunnel (CommandInterpreter ci) {
781 String nodeName = ci.nextArgument();
782 if (nodeName == null) {
783 ci.println("Please enter Node Name");
787 String bridgeName = ci.nextArgument();
788 if (bridgeName == null) {
789 ci.println("Please enter Bridge Name");
793 String portName = ci.nextArgument();
794 if (portName == null) {
795 ci.println("Please enter Port Name");
799 String tunnelType = ci.nextArgument();
800 if (tunnelType == null) {
801 ci.println("Please enter Tunnel Type");
805 String remoteIp = ci.nextArgument();
806 if (remoteIp == null) {
807 ci.println("Please enter valid Remote IP Address");
812 InetAddress.getByName(remoteIp);
813 } catch (Exception e) {
814 logger.error("Unable to resolve " + remoteIp, e);
815 ci.println("Please enter valid Remote IP Address");
819 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
820 configs.put(ConfigConstants.TYPE, "TUNNEL");
821 configs.put(ConfigConstants.TUNNEL_TYPE, tunnelType);
822 configs.put(ConfigConstants.DEST_IP, remoteIp);
825 Node node = Node.fromString(nodeName);
827 ci.println("Invalid Node");
830 status = this.addPort(node, bridgeName, portName, configs);
831 ci.println("Port creation status : "+status.toString());
834 public void _printCache (CommandInterpreter ci) {
835 String nodeName = ci.nextArgument();
836 if (nodeName == null) {
837 ci.println("Please enter Node Name");
840 Node node = Node.fromString(nodeName);
842 ci.println("Invalid Node");
845 ovsdbInventoryService.printCache(node);
848 public void _forceConnect (CommandInterpreter ci) {
849 String force = ci.nextArgument();
850 if (force.equalsIgnoreCase("YES")) {
853 else if (force.equalsIgnoreCase("NO")) {
854 forceConnect = false;
857 ci.println("Please enter YES or NO.");
859 ci.println("Current ForceConnect State : "+forceConnect);
863 public String getHelp() {
864 StringBuilder help = new StringBuilder();
865 help.append("---OVSDB CLI---\n");
866 help.append("\t ovsconnect <ConnectionName> <ip-address> - Connect to OVSDB\n");
867 help.append("\t addBridge <Node> <BridgeName> - Add Bridge\n");
868 help.append("\t getBridgeDomains <Node> - Get Bridges\n");
869 help.append("\t deleteBridgeDomain <Node> <BridgeName> - Delete a Bridge\n");
870 help.append("\t addPort <Node> <BridgeName> <PortName> <type> <options pairs> - Add Port\n");
871 help.append("\t deletePort <Node> <BridgeName> <PortName> - Delete Port\n");
872 help.append("\t addPortVlan <Node> <BridgeName> <PortName> <vlan> - Add Port, Vlan\n");
873 help.append("\t addTunnel <Node> <Bridge> <Port> <tunnel-type> <remote-ip> - Add Tunnel\n");
874 help.append("\t printCache <Node> - Prints Table Cache");
875 return help.toString();
881 * @param node Node serving this configuration service
882 * @param bridgeIdentifier String representation of a Bridge Connector
883 * @return Bridge Connector configurations
887 public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> configs) {
888 Connection connection = connectionService.getConnection(node);
889 OvsdbClient client = connection.getClient();
890 Bridge bridge = client.createTypedRowWrapper(Bridge.class);
891 bridge.setName(bridgeIdentifier);
893 String ovsTableUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
894 return this.insertRow(node, bridge.getSchema().getName(), ovsTableUuid, bridge.getRow());
898 * Create a Port Attached to a Bridge
899 * Ex. ovs-vsctl add-port br0 vif0
900 * @param node Node serving this configuration service
901 * @param bridgeIdentifier String representation of a Bridge Domain
902 * @param portIdentifier String representation of a user defined Port Name
906 public Status addPort(Node node, String bridgeIdentifier, String portIdentifier,
907 Map<ConfigConstants, Object> configs) {
908 Connection connection = connectionService.getConnection(node);
909 OvsdbClient client = connection.getClient();
911 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
912 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
913 if (rows == null || rows.size() == 0) {
914 return new Status(StatusCode.NOTFOUND);
916 for (String bridgeUuid : rows.keySet()) {
917 Row bridgeRow = rows.get(bridgeUuid);
918 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
919 if (bridge.getName().equals(bridgeIdentifier)) break;
921 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
922 return new Status(StatusCode.NOTFOUND);
925 Map<String, String> options = null;
927 Set<Long> tags = null;
928 if (configs != null) {
929 type = (String) configs.get(ConfigConstants.TYPE);
930 Map<String, String> customConfigs = (Map<String, String>) configs.get(ConfigConstants.CUSTOM);
931 if (customConfigs != null) {
932 options = new HashMap<String, String>();
933 for (String customConfig : customConfigs.keySet()) {
934 options.put(customConfig, customConfigs.get(customConfig));
940 logger.debug("Port type : " + type);
941 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.VLAN.name())) {
942 tags = new HashSet<Long>();
943 tags.add(Long.parseLong((String)configs.get(ConfigConstants.VLAN)));
947 Port port = client.createTypedRowWrapper(Port.class);
948 port.setName(portIdentifier);
949 if (tags != null) port.setTag(tags);
950 StatusWithUuid portStatus = this.insertRow(node, port.getSchema().getName(), bridge.getUuid().toString(), port.getRow());
952 if (!portStatus.isSuccess()) return portStatus;
953 // Ugly hack by adding a sleep for the Monitor Update to catch up.
954 // TODO : Remove this once the Select operation is in place.
955 // We are currently relying on the local Cache for any GET operation and that might fail if we try to
956 // fetch the last installed entry. Hence we need the Select operation to work.
960 } catch (InterruptedException e) {
961 // TODO Auto-generated catch block
962 logger.error("Thread interrupted", e);
965 Interface interfaceRow = client.createTypedRowWrapper(Interface.class);
966 ConcurrentMap<String, Row> intfRows = this.getRows(node, interfaceRow.getSchema().getName());
967 if (intfRows == null || intfRows.size() == 0) {
968 return new Status(StatusCode.NOTFOUND);
970 for (String intfUuid : intfRows.keySet()) {
971 Row intfRow = intfRows.get(intfUuid);
972 interfaceRow = client.getTypedRowWrapper(Interface.class, intfRow);
973 if (interfaceRow == null || interfaceRow.getName() == null) continue;
974 if (interfaceRow.getName().equals(portIdentifier)) break;
976 if (interfaceRow.getName() == null || !interfaceRow.getName().equals(portIdentifier)) {
977 return new Status(StatusCode.NOTFOUND);
979 Interface updateInterface = client.createTypedRowWrapper(Interface.class);
981 logger.debug("Interface type : " + type);
982 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.TUNNEL.name())) {
983 updateInterface.setType((String)configs.get(ConfigConstants.TUNNEL_TYPE));
984 if (options == null) options = new HashMap<String, String>();
985 options.put("remote_ip", (String)configs.get(ConfigConstants.DEST_IP));
986 } else if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.PATCH.name()) ||
987 type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.INTERNAL.name())) {
988 updateInterface.setType(type.toLowerCase());
991 if (options != null) {
992 updateInterface.setOptions(options);
995 Status intfStatus = null;
996 intfStatus = this.updateRow(node, interfaceRow.getSchema().getName(), portStatus.getUuid().toString(),
997 interfaceRow.getUuid().toString(), updateInterface.getRow());
999 if (intfStatus.isSuccess()) return portStatus;
1004 * Implements the OVS Connection for Managers
1006 * @param node Node serving this configuration service
1007 * @param managerip String Representing IP and connection types
1009 @SuppressWarnings("unchecked")
1011 public boolean setManager(Node node, String managerip) {
1012 Connection connection = connectionService.getConnection(node);
1013 OvsdbClient client = connection.getClient();
1014 Manager manager = client.createTypedRowWrapper(Manager.class);
1015 manager.setTarget(ImmutableSet.of(managerip));
1017 OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
1018 ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
1019 if (row == null || row.size() == 0) {
1022 String ovsTableUuid = (String)row.keySet().toArray()[0];
1024 Status status = this.insertRow(node, manager.getSchema().getName(), ovsTableUuid, manager.getRow());
1025 return status.isSuccess();
1030 public Status addBridgeDomainConfig(Node node, String bridgeIdentfier,
1031 Map<ConfigConstants, Object> configs) {
1032 String mgmt = (String)configs.get(ConfigConstants.MGMT);
1034 if (setManager(node, mgmt)) return new Status(StatusCode.SUCCESS);
1036 return new Status(StatusCode.BADREQUEST);
1041 public Status deletePort(Node node, String bridgeIdentifier, String portIdentifier) {
1042 Connection connection = connectionService.getConnection(node);
1043 OvsdbClient client = connection.getClient();
1045 Port port = client.getTypedRowWrapper(Port.class, null);
1046 ConcurrentMap<String, Row> rows = this.getRows(node, port.getSchema().getName());
1047 if (rows == null || rows.size() == 0) {
1048 return new Status(StatusCode.NOTFOUND);
1050 for (String portUuid : rows.keySet()) {
1051 Row portRow = rows.get(portUuid);
1052 port = client.getTypedRowWrapper(Port.class, portRow);
1053 if (port.getName().equals(portIdentifier)) break;
1055 if (port.getName() == null || !port.getName().equals(portIdentifier)) {
1056 return new Status(StatusCode.NOTFOUND);
1058 return this.deleteRow(node, port.getSchema().getName(), port.getUuid().toString());
1063 public Status deleteBridgeDomain(Node node, String bridgeIdentifier) {
1064 Connection connection = connectionService.getConnection(node);
1065 OvsdbClient client = connection.getClient();
1067 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
1068 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
1069 if (rows == null || rows.size() == 0) {
1070 return new Status(StatusCode.NOTFOUND);
1072 for (String bridgeUuid : rows.keySet()) {
1073 Row bridgeRow = rows.get(bridgeUuid);
1074 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
1075 if (bridge.getName().equals(bridgeIdentifier)) break;
1077 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
1078 return new Status(StatusCode.NOTFOUND);
1080 return this.deleteRow(node, bridge.getSchema().getName(), bridge.getUuid().toString());
1084 public List<String> getBridgeDomains(Node node) {
1085 if (connectionService == null) {
1086 logger.error("Couldn't refer to the ConnectionService");
1090 Connection connection = connectionService.getConnection(node);
1091 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
1092 List<String> brlist = new ArrayList<String>();
1093 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
1094 if(brTableCache != null){
1095 for (String uuid : brTableCache.keySet()) {
1096 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
1097 brlist.add(bridge.getName());
1104 public NodeConnector getNodeConnector(Node arg0, String arg1, String arg2) {
1110 public Status addPortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1111 Map<ConfigConstants, Object> configs) {
1112 // TODO Auto-generated method stub
1118 public Node getBridgeDomainNode(Node node, String bridgeIdentifier) {
1119 // TODO Auto-generated method stub
1125 public Map<ConfigConstants, Object> getPortConfigs(Node node, String bridgeIdentifier,
1126 String portIdentifier) {
1127 // TODO Auto-generated method stub
1133 public Status removeBridgeDomainConfig(Node node, String bridgeIdentifier,
1134 Map<ConfigConstants, Object> configs) {
1135 // TODO Auto-generated method stub
1141 public Status removePortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1142 Map<ConfigConstants, Object> configs) {
1143 // TODO Auto-generated method stub
1149 public Map<ConfigConstants, Object> getBridgeDomainConfigs(Node node, String bridgeIdentifier) {
1150 // TODO Auto-generated method stub
1155 // SCHEMA-INDEPENDENT Configuration Service APIs
1157 private String getTableNameForRowUuid(Node node, String databaseName, UUID rowUuid) {
1158 ConcurrentMap<String, ConcurrentMap<String, Row>> cache = ovsdbInventoryService.getCache(node, databaseName);
1159 if (cache == null) return null;
1160 for (String tableName : cache.keySet()) {
1161 ConcurrentMap<String, Row> rows = cache.get(tableName);
1162 if (rows.get(rowUuid.toString()) != null) {
1169 private String getReferencingColumn (TableSchema<?> parentTableSchema, String childTableName) throws OvsdbPluginException {
1170 Map<String, ColumnSchema> columnSchemas = parentTableSchema.getColumnSchemas();
1171 String refColumn = null;
1172 for (String columnName : columnSchemas.keySet()) {
1173 ColumnSchema columnSchema = columnSchemas.get(columnName);
1174 if (columnSchema.getType().getBaseType().getClass().equals(UuidBaseType.class)) {
1175 UuidBaseType refType = (UuidBaseType)columnSchema.getType().getBaseType();
1176 if (refType.getRefTable() != null && refType.getRefTable().equalsIgnoreCase(childTableName)) {
1177 if (refColumn == null) {
1178 refColumn = columnName;
1180 throw new OvsdbPluginException("Multiple Referencing Columns for "+ childTableName +" on "+ parentTableSchema.getName());
1185 if (refColumn != null) {
1188 throw new OvsdbPluginException("No Referencing Column for "+childTableName+" on "+parentTableSchema.getName());
1191 * A common Insert Transaction convenience method that populates the TransactionBuilder with insert operation
1192 * for a Child Row and also mutates the parent row with the UUID of the inserted Child.
1194 private void processInsertTransaction(OvsdbClient client, String databaseName, String childTable,
1195 String parentTable, UUID parentUuid, String parentColumn, String namedUuid,
1196 Row<GenericTableSchema> row,
1197 TransactionBuilder transactionBuilder) {
1198 // Insert the row as the first transaction entry
1199 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1200 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
1201 transactionBuilder.add(op.insert(childTableSchema, row)
1202 .withId(namedUuid));
1204 // Followed by the Mutation
1205 if (parentColumn != null) {
1206 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1207 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
1208 ColumnSchema<GenericTableSchema, UUID> _uuid = parentTableSchema.column("_uuid", UUID.class);
1211 .add(op.mutate(parentTableSchema)
1212 .addMutation(parentColumnSchema, Mutator.INSERT, new UUID(namedUuid))
1213 .where(_uuid.opEqual(parentUuid))
1219 * insert a Row in a Table of a specified Database Schema.
1221 * This method can insert just a single Row specified in the row parameter.
1222 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1223 * can insert a hierarchy of rows with parent-child relationship.
1225 * @param node OVSDB Node
1226 * @param databaseName Database Name that represents the Schema supported by the node.
1227 * @param tableName Table on which the row is inserted
1228 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1229 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1230 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1231 * @param row Row of table Content to be inserted
1232 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1233 * @return UUID of the inserted Row
1236 public UUID insertRow(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1237 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1238 Connection connection = connectionService.getConnection(node);
1239 OvsdbClient client = connection.getClient();
1240 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1241 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1243 Row<GenericTableSchema> processedRow = this.insertTree(node, databaseName, tableName, parentTable, parentUuid, parentColumn, row);
1245 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
1246 Column<GenericTableSchema, UUID> uuid = processedRow.getColumn(_uuid);
1247 return uuid.getData();
1251 * insert a Row in a Table of a specified Database Schema. This is a convenience method on top of
1252 * {@link insertRow(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertRow}
1253 * which assumes that OVSDB schema implementation that corresponds to the databaseName will provide
1254 * the necessary service to populate the Parent Table Name and Parent Column Name.
1256 * This method can insert just a single Row specified in the row parameter.
1257 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1258 * can insert a hierarchy of rows with parent-child relationship.
1260 * @param node OVSDB Node
1261 * @param databaseName Database Name that represents the Schema supported by the node.
1262 * @param tableName Table on which the row is inserted
1263 * @param parentUuid UUID of the parent table to which this operation will result in attaching/mutating.
1264 * @param row Row of table Content to be inserted
1265 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1266 * @return UUID of the inserted Row
1269 public UUID insertRow(Node node, String databaseName, String tableName,
1270 UUID parentRowUuid, Row<GenericTableSchema> row)
1271 throws OvsdbPluginException {
1272 return this.insertRow(node, databaseName, tableName, null, parentRowUuid, null, row);
1276 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct
1278 * @param node OVSDB Node
1279 * @param databaseName Database Name that represents the Schema supported by the node.
1280 * @param tableName Table on which the row is inserted
1281 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1282 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1283 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1284 * @param row Row Tree with parent-child relationships via column of type refTable.
1285 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1286 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1289 public Row<GenericTableSchema> insertTree(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1290 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1291 Connection connection = connectionService.getConnection(node);
1292 OvsdbClient client = connection.getClient();
1294 if (databaseName == null || tableName == null) {
1295 throw new OvsdbPluginException("databaseName, tableName and parentUuid are Mandatory Parameters");
1298 if (parentTable == null && parentUuid != null) {
1299 parentTable = this.getTableNameForRowUuid(node, databaseName, parentUuid);
1302 if (parentColumn == null && parentTable != null) {
1303 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1304 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1305 parentColumn = this.getReferencingColumn(parentTableSchema, tableName);
1308 logger.debug("insertTree Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
1309 client.getConnectionInfo(), tableName, parentTable, parentColumn, parentUuid, row);
1311 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows = Maps.newConcurrentMap();
1312 extractReferencedRows(node, databaseName, row, referencedRows, 0);
1313 DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
1314 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1316 String namedUuid = "Transaction_"+ tableName;
1317 this.processInsertTransaction(client, databaseName, tableName, parentTable, parentUuid,
1318 parentColumn, namedUuid, row, transactionBuilder);
1320 int referencedRowsInsertIndex = transactionBuilder.getOperations().size();
1321 // Insert Referenced Rows
1322 if (referencedRows != null) {
1323 for (UUID refUuid : referencedRows.keySet()) {
1324 Map.Entry<String, Row<GenericTableSchema>> referencedRow = referencedRows.get(refUuid);
1325 TableSchema<GenericTableSchema> refTableSchema = dbSchema.table(referencedRow.getKey(), GenericTableSchema.class);
1326 transactionBuilder.add(op.insert(refTableSchema, referencedRow.getValue())
1327 .withId(refUuid.toString()));
1331 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1332 List<OperationResult> operationResults;
1334 operationResults = results.get();
1335 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1336 throw new OvsdbPluginException("Insert Operation Failed");
1338 for (OperationResult result : operationResults) {
1339 if (result.getError() != null) {
1340 throw new OvsdbPluginException("Insert Operation Failed with Error : "+result.getError().toString());
1343 return getNormalizedRow(dbSchema, tableName, row, referencedRows, operationResults, referencedRowsInsertIndex);
1344 } catch (InterruptedException | ExecutionException e) {
1345 throw new OvsdbPluginException("Exception : "+e.getLocalizedMessage());
1350 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct.
1351 * This is a convenience method on top of {@link #insertTree(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertTree}
1353 * @param node OVSDB Node
1354 * @param databaseName Database Name that represents the Schema supported by the node.
1355 * @param tableName Table on which the row is inserted
1356 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1357 * @param row Row Tree with parent-child relationships via column of type refTable.
1358 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1359 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1362 public Row<GenericTableSchema> insertTree(Node node, String databaseName,
1363 String tableName, UUID parentRowUuid, Row<GenericTableSchema> row)
1364 throws OvsdbPluginException {
1365 return this.insertTree(node, databaseName, tableName, null, parentRowUuid, null, row);
1369 * Convenience method that helps insertTree to extract Rows that are referenced directly from within a primary row
1370 * to be inserted. These referenced rows are *NOT* defined in the OVSDB specification. But, we felt that from a northbound
1371 * application standpoint, having such an option is useful and our implementation supports it for applications to make use of.
1372 * In short, whichever ColumnSchema is based on an UUID (refered by RefTable in schema), applications can directly insert an
1373 * entire row and this method will help navigate it through and identify such cases.
1374 * After identifying these Referenced Rows, it will modify the primary row with Named UUIDs and fill out the referencedRows
1375 * Map structure so that insertTree can insert all the Rows defined in this Tree of rows in a single transaction with automatic
1376 * Mutation on the parent rows.
1378 * @param node OVSDB Node
1379 * @param dbName Database Name that represents the Schema supported by the node.
1380 * @param row Row Tree with parent-child relationships via column of type refTable.
1381 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1382 * @param namedUuidSuffix Named UUID must be unique for every new Row insert within a given transaction.
1383 * This index will help to retain the uniqueness.
1385 private void extractReferencedRows(Node node, String dbName, Row<GenericTableSchema> row,
1386 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1387 int namedUuidSuffix) {
1388 OvsdbClient client = connectionService.getConnection(node).getClient();
1389 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1390 for (Column column : columns) {
1391 if (column.getData() != null) {
1392 if (column.getData() instanceof ReferencedRow) {
1393 ReferencedRow refRowObject = (ReferencedRow)column.getData();
1394 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1395 column.setData(refUuid);
1397 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1398 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1399 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1400 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1401 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1402 } catch (InterruptedException | ExecutionException e) {
1403 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1405 } else if (column.getData() instanceof OvsdbSet) {
1406 OvsdbSet<Object> setObject = (OvsdbSet<Object>)column.getData();
1407 OvsdbSet<Object> modifiedSet = new OvsdbSet<Object>();
1408 for (Object obj : setObject) {
1409 if (obj instanceof ReferencedRow) {
1410 ReferencedRow refRowObject = (ReferencedRow)obj;
1411 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1412 modifiedSet.add(refUuid);
1414 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1415 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1416 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1417 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1418 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1419 } catch (InterruptedException | ExecutionException e) {
1420 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1423 modifiedSet.add(obj);
1426 column.setData(modifiedSet);
1433 * getNormalizedRow normalizes the Row from a namedUuid Space as defined in extractReferencedRows to the actual Uuid as created
1434 * by the Ovsdb-server. In order to perform this normalization, it processes the operation results for a corresponding Transaction
1435 * where the referenced rows are inserted along with the Primary row. It changes the named-Uuid to the actual Uuid before returning
1436 * the Row to the application.
1438 * @param dbSchema Database Schema supported by the node.
1439 * @param row Row Tree with parent-child relationships via column of type refTable.
1440 * @param tableName Table on which the row is inserted
1441 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1442 * @param operationResults Operation Results returned by ovsdb-server for the insertTree transaction
1443 * @param referencedRowsInsertIndex Starting index in OperationResults from which the ReferencedRow insert results begin.
1446 private Row<GenericTableSchema> getNormalizedRow(DatabaseSchema dbSchema, String tableName, Row<GenericTableSchema> row,
1447 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1448 List<OperationResult> operationResults, int referencedRowsInsertIndex) {
1449 UUID primaryRowUuid = operationResults.get(0).getUuid();
1450 TableSchema<GenericTableSchema> primaryRowTableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1451 ColumnSchema<GenericTableSchema, UUID> _uuid = primaryRowTableSchema.column("_uuid", UUID.class);
1452 if (_uuid != null) {
1453 Column<GenericTableSchema, UUID> _uuidColumn = new Column<GenericTableSchema, UUID>(_uuid, primaryRowUuid);
1454 row.addColumn("_uuid", _uuidColumn);
1457 if (referencedRows != null) {
1458 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1459 if (referencedRows != null) {
1460 for (int idx=0; idx < referencedRows.keySet().size(); idx++) {
1461 UUID refUuid = (UUID) referencedRows.keySet().toArray()[idx];
1462 for (Column column : columns) {
1463 if (column.getData() != null) {
1464 if ((column.getData() instanceof UUID) && column.getData().equals(refUuid)) {
1465 column.setData(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1466 } else if ((column.getData() instanceof OvsdbSet) && ((OvsdbSet)column.getData()).contains(refUuid)) {
1467 OvsdbSet<UUID> refSet = (OvsdbSet<UUID>)column.getData();
1468 refSet.remove(refUuid);
1469 refSet.add(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1480 public Row<GenericTableSchema> updateRow(Node node, String databaseName,
1481 String tableName, UUID rowUuid, Row<GenericTableSchema> row,
1482 boolean overwrite) throws OvsdbPluginException {
1483 Connection connection = connectionService.getConnection(node);
1484 OvsdbClient client = connection.getClient();
1486 logger.debug("updateRow : Connection : {} databaseName : {} tableName : {} rowUUID : {} row : {}",
1487 client.getConnectionInfo(), databaseName, tableName, rowUuid, row.toString());
1489 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1490 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1491 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1492 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
1493 transactionBuilder.add(op.update(tableSchema, row)
1494 .where(_uuid.opEqual(rowUuid))
1497 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1498 List<OperationResult> operationResults = results.get();
1499 for (OperationResult result : operationResults) {
1500 if (result.getError() != null) {
1501 throw new OvsdbPluginException("Error updating row : " + result.getError() +
1502 " Details: " + result.getDetails());
1505 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1506 throw new OvsdbPluginException("Failed to update row. Please check OVS logs for more info.");
1509 return this.getRow(node, databaseName, tableName, rowUuid);
1510 } catch(Exception e){
1511 throw new OvsdbPluginException("Error updating row due to an exception "+ e.getMessage());
1516 public void deleteRow(Node node, String databaseName, String tableName, String parentTable, UUID parentRowUuid,
1517 String parentColumn, UUID rowUuid) throws OvsdbPluginException {
1518 Connection connection = connectionService.getConnection(node);
1519 OvsdbClient client = connection.getClient();
1521 if (parentTable == null && parentRowUuid != null) {
1522 parentTable = this.getTableNameForRowUuid(node, databaseName, parentRowUuid);
1525 if (parentColumn == null && parentTable != null) {
1526 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1527 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1528 parentColumn = this.getReferencingColumn(parentTableSchema, tableName);
1531 logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
1532 client.getConnectionInfo(), databaseName, tableName, rowUuid, parentTable, parentColumn);
1534 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1535 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1536 this.processDeleteTransaction(client, databaseName, tableName,
1537 parentTable, parentColumn, rowUuid.toString(), transactionBuilder);
1539 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1540 List<OperationResult> operationResults;
1542 operationResults = results.get();
1543 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1544 throw new OvsdbPluginException("Delete Operation Failed");
1546 for (OperationResult result : operationResults) {
1547 if (result.getError() != null) {
1548 throw new OvsdbPluginException("Delete Operation Failed with Error : "+result.getError().toString());
1551 } catch (InterruptedException | ExecutionException e) {
1552 // TODO Auto-generated catch block
1553 e.printStackTrace();
1558 public void deleteRow(Node node, String databaseName, String tableName, UUID rowUuid) throws OvsdbPluginException {
1559 this.deleteRow(node, databaseName, tableName, null, null, null, rowUuid);
1563 public Row<GenericTableSchema> getRow(Node node, String databaseName,
1564 String tableName, UUID uuid) throws OvsdbPluginException {
1565 ConcurrentMap<UUID, Row<GenericTableSchema>> rows = this.getRows(node, databaseName, tableName);
1567 return rows.get(uuid);
1573 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1574 String databaseName, String tableName) throws OvsdbPluginException {
1575 ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, databaseName, tableName);
1576 if (ovsTable == null) return null;
1577 ConcurrentMap<UUID, Row<GenericTableSchema>> tableDB = Maps.newConcurrentMap();
1578 for (String uuidStr : ovsTable.keySet()) {
1579 tableDB.put(new UUID(uuidStr), ovsTable.get(uuidStr));
1585 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1586 String databaseName, String tableName, String fiqlQuery)
1587 throws OvsdbPluginException {
1588 return this.getRows(node, databaseName, tableName);
1592 public List<String> getTables(Node node, String databaseName) throws OvsdbPluginException {
1593 ConcurrentMap<String, ConcurrentMap<String, Row>> cache = ovsdbInventoryService.getCache(node, databaseName);
1594 if (cache == null) return null;
1595 return new ArrayList<String>(cache.keySet());