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 Connection connection = connectionService.getConnection(node);
290 OvsdbClient client = connection.getClient();
292 logger.debug("updateRow : Connection : {} databaseName : {} tableName : {} rowUUID : {} row : {}",
293 client.getConnectionInfo(), databaseName, tableName, rowUUID, row.toString());
295 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
296 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
297 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
298 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
299 transactionBuilder.add(op.update(tableSchema, row)
300 .where(_uuid.opEqual(new UUID(rowUUID)))
303 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
304 List<OperationResult> operationResults = results.get();
305 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
306 return new StatusWithUuid(StatusCode.INTERNALERROR);
308 for (OperationResult result : operationResults) {
309 if (result.getError() != null) {
310 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
313 return new StatusWithUuid(StatusCode.SUCCESS);
314 } catch(Exception e){
315 logger.error("Error in updateRow(): ",e);
317 return new Status(StatusCode.INTERNALERROR);
320 private void processDeleteTransaction(OvsdbClient client, String databaseName, String childTable,
321 String parentTable, String parentColumn, String uuid, TransactionBuilder transactionBuilder) {
322 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
323 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
325 if (parentColumn != null) {
326 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
327 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
329 .add(op.mutate(parentTableSchema)
330 .addMutation(parentColumnSchema, Mutator.DELETE, new UUID(uuid))
331 .where(parentColumnSchema.opIncludes(new UUID(uuid)))
335 ColumnSchema<GenericTableSchema, UUID> _uuid = childTableSchema.column("_uuid", UUID.class);
336 transactionBuilder.add(op.delete(childTableSchema)
337 .where(_uuid.opEqual(new UUID(uuid)))
343 public Status deleteRow(Node node, String tableName, String uuid) {
344 String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
345 Connection connection = connectionService.getConnection(node);
346 OvsdbClient client = connection.getClient();
348 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
349 if (parentColumn == null) {
350 parentColumn = new String[]{null, null};
353 logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
354 client.getConnectionInfo(), databaseName, tableName, uuid, parentColumn[0], parentColumn[1]);
356 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
357 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
358 this.processDeleteTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
359 parentColumn[0], parentColumn[1], uuid, transactionBuilder);
361 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
362 List<OperationResult> operationResults;
364 operationResults = results.get();
365 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
366 return new StatusWithUuid(StatusCode.INTERNALERROR);
368 for (OperationResult result : operationResults) {
369 if (result.getError() != null) {
370 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
373 } catch (InterruptedException | ExecutionException e) {
374 // TODO Auto-generated catch block
378 return new Status(StatusCode.SUCCESS);
383 public ConcurrentMap<String, Row> getRows(Node node, String tableName) {
384 ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
390 public Row getRow(Node node, String tableName, String uuid) {
391 Map<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
392 if (ovsTable == null) return null;
393 return ovsTable.get(uuid);
398 public List<String> getTables(Node node) {
399 ConcurrentMap<String, ConcurrentMap<String, Row>> cache = ovsdbInventoryService.getCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME);
400 if (cache == null) return null;
401 return new ArrayList<String>(cache.keySet());
404 private List<InetAddress> getControllerIPAddresses(Connection connection) {
405 List<InetAddress> controllers = null;
406 InetAddress controllerIP = null;
408 controllers = new ArrayList<InetAddress>();
409 String addressString = System.getProperty("ovsdb.controller.address");
411 if (addressString != null) {
413 controllerIP = InetAddress.getByName(addressString);
414 if (controllerIP != null) {
415 controllers.add(controllerIP);
418 } catch (UnknownHostException e) {
419 logger.error("Host {} is invalid", addressString);
423 if (clusterServices != null) {
424 controllers = clusterServices.getClusteredControllers();
425 if (controllers != null && controllers.size() > 0) {
426 if (controllers.size() == 1) {
427 InetAddress controller = controllers.get(0);
428 if (!controller.equals(InetAddress.getLoopbackAddress())) {
437 addressString = System.getProperty("of.address");
439 if (addressString != null) {
441 controllerIP = InetAddress.getByName(addressString);
442 if (controllerIP != null) {
443 controllers.add(controllerIP);
446 } catch (UnknownHostException e) {
447 logger.error("Host {} is invalid", addressString);
452 controllerIP = connection.getClient().getConnectionInfo().getLocalAddress();
453 controllers.add(controllerIP);
455 } catch (Exception e) {
456 logger.debug("Invalid connection provided to getControllerIPAddresses", e);
461 private short getControllerOFPort() {
462 Short defaultOpenFlowPort = 6633;
463 Short openFlowPort = defaultOpenFlowPort;
464 String portString = System.getProperty("of.listenPort");
465 if (portString != null) {
467 openFlowPort = Short.decode(portString).shortValue();
468 } catch (NumberFormatException e) {
469 logger.warn("Invalid port:{}, use default({})", portString,
477 public Boolean setOFController(Node node, String bridgeUUID) throws InterruptedException, ExecutionException {
478 Connection connection = this.getConnection(node);
479 if (connection == null) {
483 Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
485 Status updateOperationStatus = null;
487 OvsdbSet<String> protocols = new OvsdbSet<String>();
489 String ofVersion = System.getProperty("ovsdb.of.version", OPENFLOW_10);
492 protocols.add("OpenFlow13");
497 protocols.add("OpenFlow10");
500 bridge.setProtocols(protocols);
501 updateOperationStatus = this.updateRow(node, bridge.getSchema().getName(),
502 null, bridgeUUID, bridge.getRow());
503 logger.debug("Bridge {} updated to {} with Status {}", bridgeUUID,
504 protocols.toArray()[0],updateOperationStatus);
506 } catch (SchemaVersionMismatchException e){
507 logger.debug(e.toString());
510 // If we fail to update the protocols
511 if (updateOperationStatus != null && !updateOperationStatus.isSuccess()) {
512 return updateOperationStatus.isSuccess();
515 Status status = null;
516 List<InetAddress> ofControllerAddrs = this.getControllerIPAddresses(connection);
517 short ofControllerPort = getControllerOFPort();
518 for (InetAddress ofControllerAddress : ofControllerAddrs) {
519 String newController = "tcp:"+ofControllerAddress.getHostAddress()+":"+ofControllerPort;
520 Controller controllerRow = connection.getClient().createTypedRowWrapper(Controller.class);
521 controllerRow.setTarget(newController);
522 //ToDo: Status gets overwritten on each iteration. If any operation other than the last fails it's ignored.
523 status = this.insertRow(node, controllerRow.getSchema().getName(), bridgeUUID, controllerRow.getRow());
526 if (status != null) {
527 return status.isSuccess();
534 public Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
535 if (connectionService == null) {
536 logger.error("Couldn't refer to the ConnectionService");
541 Connection connection = connectionService.getConnection(node);
542 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
544 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
545 for (String uuid : brTableCache.keySet()) {
546 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
547 if (bridge.getName().contains(bridgeIdentifier)) {
548 return setOFController(node, uuid);
551 } catch(Exception e) {
552 logger.error("Error in setBridgeOFController()",e);
558 public <T extends TypedBaseTable<?>> String getTableName(Node node, Class<T> typedClass) {
559 Connection connection = connectionService.getConnection(node);
560 if (connection == null) return null;
561 OvsdbClient client = connection.getClient();
562 TypedBaseTable<?> typedTable = client.getTypedRowWrapper(typedClass, null);
563 if (typedTable == null) return null;
564 return typedTable.getSchema().getName();
568 public <T extends TypedBaseTable<?>> T getTypedRow(Node node, Class<T> typedClass, Row row) {
569 Connection connection = connectionService.getConnection(node);
570 if (connection == null) return null;
571 OvsdbClient client = connection.getClient();
572 return (T)client.getTypedRowWrapper(typedClass, row);
576 public <T extends TypedBaseTable<?>> T createTypedRow(Node node, Class<T> typedClass) {
577 Connection connection = connectionService.getConnection(node);
578 if (connection == null) return null;
579 OvsdbClient client = connection.getClient();
580 return client.createTypedRowWrapper(typedClass);
583 public void _ovsconnect (CommandInterpreter ci) {
584 String bridgeName = ci.nextArgument();
585 if (bridgeName == null) {
586 ci.println("Please enter Bridge Name");
590 String ovsdbserver = ci.nextArgument();
591 if (ovsdbserver == null) {
592 ci.println("Please enter valid IP-Address");
596 InetAddress.getByName(ovsdbserver);
597 } catch (UnknownHostException e) {
598 logger.error("Unable to resolve " + ovsdbserver, e);
599 ci.println("Please enter valid IP-Address");
602 String port = ci.nextArgument();
607 ci.println("connecting to ovsdb server : "+ovsdbserver+":"+port+" ... ");
608 Map<ConnectionConstants, String> params = new HashMap<ConnectionConstants, String>();
609 params.put(ConnectionConstants.ADDRESS, ovsdbserver);
610 params.put(ConnectionConstants.PORT, port);
611 Node node = connectionService.connect(bridgeName, params);
612 if (node != null) ci.println("Node Name: "+node.toString());
613 else ci.println("Could not connect to Node");
616 public void _addBridge (CommandInterpreter ci) {
617 String nodeName = ci.nextArgument();
618 if (nodeName == null) {
619 ci.println("Please enter Node Name");
622 String bridgeName = ci.nextArgument();
623 if (bridgeName == null) {
624 ci.println("Please enter Bridge Name");
629 Node node = Node.fromString(nodeName);
631 ci.println("Invalid Node");
634 status = this.createBridgeDomain(node, bridgeName, null);
635 ci.println("Bridge creation status : "+status.toString());
638 public void _getBridgeDomains (CommandInterpreter ci) {
639 String nodeName = ci.nextArgument();
640 if (nodeName == null) {
641 ci.println("Please enter Node Name");
645 List<String> brlist = new ArrayList<String>();
646 Node node = Node.fromString(nodeName);
647 brlist = this.getBridgeDomains(node);
649 ci.println("Invalid Node");
652 ci.println("Existing Bridges: "+brlist.toString());
655 public void _deleteBridgeDomain (CommandInterpreter ci) {
656 String nodeName = ci.nextArgument();
657 if (nodeName == null) {
658 ci.println("Please enter Node Name");
661 String bridgeName = ci.nextArgument();
662 if (bridgeName == null) {
663 ci.println("Please enter Bridge Name");
667 Node node = Node.fromString(nodeName);
669 ci.println("Invalid Node");
672 status = this.deleteBridgeDomain(node, bridgeName);
673 ci.println("Bridge deletion status : "+status.toString());
676 public void _addPort (CommandInterpreter ci) {
677 String nodeName = ci.nextArgument();
678 if (nodeName == null) {
679 ci.println("Please enter Node Name");
683 String bridgeName = ci.nextArgument();
684 if (bridgeName == null) {
685 ci.println("Please enter Bridge Name");
689 String portName = ci.nextArgument();
690 if (portName == null) {
691 ci.println("Please enter Port Name");
695 String type = ci.nextArgument();
697 Map<String, String> configs = new HashMap<String, String>();
699 String configKey = ci.nextArgument();
700 if (configKey == null) break;
701 String configValue = ci.nextArgument();
702 if (configValue == null) break;
703 configs.put(configKey, configValue);
706 Map<ConfigConstants, Object> customConfigs = null;
708 customConfigs = new HashMap<ConfigConstants, Object>();
709 customConfigs.put(ConfigConstants.TYPE, type);
712 if (configs.size() > 0) {
713 if (customConfigs == null) customConfigs = new HashMap<ConfigConstants, Object>();
714 customConfigs.put(ConfigConstants.CUSTOM, configs);
715 ci.println(customConfigs.toString());
718 Node node = Node.fromString(nodeName);
720 ci.println("Invalid Node");
723 status = this.addPort(node, bridgeName, portName, customConfigs);
724 ci.println("Port creation status : "+status.toString());
727 public void _deletePort (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");
747 Node node = Node.fromString(nodeName);
749 ci.println("Invalid Node");
752 status = this.deletePort(node, bridgeName, portName);
753 ci.println("Port deletion status : "+status.toString());
756 public void _addPortVlan (CommandInterpreter ci) {
757 String nodeName = ci.nextArgument();
758 if (nodeName == null) {
759 ci.println("Please enter Node Name");
763 String bridgeName = ci.nextArgument();
764 if (bridgeName == null) {
765 ci.println("Please enter Bridge Name");
769 String portName = ci.nextArgument();
770 if (portName == null) {
771 ci.println("Please enter Port Name");
775 String vlan = ci.nextArgument();
777 ci.println("Please enter Valid Vlan");
781 Integer.parseInt(vlan);
782 } catch (NumberFormatException e) {
783 ci.println("Please enter Valid Vlan");
788 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
789 configs.put(ConfigConstants.TYPE, "VLAN");
790 configs.put(ConfigConstants.VLAN, vlan);
793 Node node = Node.fromString(nodeName);
795 ci.println("Invalid Node");
798 status = this.addPort(node, bridgeName, portName, configs);
799 ci.println("Port creation status : "+status.toString());
802 public void _addTunnel (CommandInterpreter ci) {
803 String nodeName = ci.nextArgument();
804 if (nodeName == null) {
805 ci.println("Please enter Node Name");
809 String bridgeName = ci.nextArgument();
810 if (bridgeName == null) {
811 ci.println("Please enter Bridge Name");
815 String portName = ci.nextArgument();
816 if (portName == null) {
817 ci.println("Please enter Port Name");
821 String tunnelType = ci.nextArgument();
822 if (tunnelType == null) {
823 ci.println("Please enter Tunnel Type");
827 String remoteIp = ci.nextArgument();
828 if (remoteIp == null) {
829 ci.println("Please enter valid Remote IP Address");
834 InetAddress.getByName(remoteIp);
835 } catch (Exception e) {
836 logger.error("Unable to resolve " + remoteIp, e);
837 ci.println("Please enter valid Remote IP Address");
841 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
842 configs.put(ConfigConstants.TYPE, "TUNNEL");
843 configs.put(ConfigConstants.TUNNEL_TYPE, tunnelType);
844 configs.put(ConfigConstants.DEST_IP, remoteIp);
847 Node node = Node.fromString(nodeName);
849 ci.println("Invalid Node");
852 status = this.addPort(node, bridgeName, portName, configs);
853 ci.println("Port creation status : "+status.toString());
856 public void _printCache (CommandInterpreter ci) {
857 String nodeName = ci.nextArgument();
858 if (nodeName == null) {
859 ci.println("Please enter Node Name");
862 Node node = Node.fromString(nodeName);
864 ci.println("Invalid Node");
867 ovsdbInventoryService.printCache(node);
870 public void _forceConnect (CommandInterpreter ci) {
871 String force = ci.nextArgument();
872 if (force.equalsIgnoreCase("YES")) {
875 else if (force.equalsIgnoreCase("NO")) {
876 forceConnect = false;
879 ci.println("Please enter YES or NO.");
881 ci.println("Current ForceConnect State : "+forceConnect);
885 public String getHelp() {
886 StringBuilder help = new StringBuilder();
887 help.append("---OVSDB CLI---\n");
888 help.append("\t ovsconnect <ConnectionName> <ip-address> - Connect to OVSDB\n");
889 help.append("\t addBridge <Node> <BridgeName> - Add Bridge\n");
890 help.append("\t getBridgeDomains <Node> - Get Bridges\n");
891 help.append("\t deleteBridgeDomain <Node> <BridgeName> - Delete a Bridge\n");
892 help.append("\t addPort <Node> <BridgeName> <PortName> <type> <options pairs> - Add Port\n");
893 help.append("\t deletePort <Node> <BridgeName> <PortName> - Delete Port\n");
894 help.append("\t addPortVlan <Node> <BridgeName> <PortName> <vlan> - Add Port, Vlan\n");
895 help.append("\t addTunnel <Node> <Bridge> <Port> <tunnel-type> <remote-ip> - Add Tunnel\n");
896 help.append("\t printCache <Node> - Prints Table Cache");
897 return help.toString();
903 * @param node Node serving this configuration service
904 * @param bridgeIdentifier String representation of a Bridge Connector
905 * @return Bridge Connector configurations
909 public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> configs) {
910 Connection connection = connectionService.getConnection(node);
911 OvsdbClient client = connection.getClient();
912 Bridge bridge = client.createTypedRowWrapper(Bridge.class);
913 bridge.setName(bridgeIdentifier);
915 String ovsTableUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
916 return this.insertRow(node, bridge.getSchema().getName(), ovsTableUuid, bridge.getRow());
920 * Create a Port Attached to a Bridge
921 * Ex. ovs-vsctl add-port br0 vif0
922 * @param node Node serving this configuration service
923 * @param bridgeIdentifier String representation of a Bridge Domain
924 * @param portIdentifier String representation of a user defined Port Name
928 public Status addPort(Node node, String bridgeIdentifier, String portIdentifier,
929 Map<ConfigConstants, Object> configs) {
930 Connection connection = connectionService.getConnection(node);
931 OvsdbClient client = connection.getClient();
933 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
934 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
935 if (rows == null || rows.size() == 0) {
936 return new Status(StatusCode.NOTFOUND);
938 for (String bridgeUuid : rows.keySet()) {
939 Row bridgeRow = rows.get(bridgeUuid);
940 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
941 if (bridge.getName().equals(bridgeIdentifier)) break;
943 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
944 return new Status(StatusCode.NOTFOUND);
947 Map<String, String> options = null;
949 Set<Long> tags = null;
950 if (configs != null) {
951 type = (String) configs.get(ConfigConstants.TYPE);
952 Map<String, String> customConfigs = (Map<String, String>) configs.get(ConfigConstants.CUSTOM);
953 if (customConfigs != null) {
954 options = new HashMap<String, String>();
955 for (String customConfig : customConfigs.keySet()) {
956 options.put(customConfig, customConfigs.get(customConfig));
962 logger.debug("Port type : " + type);
963 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.VLAN.name())) {
964 tags = new HashSet<Long>();
965 tags.add(Long.parseLong((String)configs.get(ConfigConstants.VLAN)));
969 Port port = client.createTypedRowWrapper(Port.class);
970 port.setName(portIdentifier);
971 if (tags != null) port.setTag(tags);
972 StatusWithUuid portStatus = this.insertRow(node, port.getSchema().getName(), bridge.getUuid().toString(), port.getRow());
974 if (!portStatus.isSuccess()) return portStatus;
975 // Ugly hack by adding a sleep for the Monitor Update to catch up.
976 // TODO : Remove this once the Select operation is in place.
977 // We are currently relying on the local Cache for any GET operation and that might fail if we try to
978 // fetch the last installed entry. Hence we need the Select operation to work.
982 } catch (InterruptedException e) {
983 // TODO Auto-generated catch block
987 Interface interfaceRow = client.createTypedRowWrapper(Interface.class);
988 ConcurrentMap<String, Row> intfRows = this.getRows(node, interfaceRow.getSchema().getName());
989 if (intfRows == null || intfRows.size() == 0) {
990 return new Status(StatusCode.NOTFOUND);
992 for (String intfUuid : intfRows.keySet()) {
993 Row intfRow = intfRows.get(intfUuid);
994 interfaceRow = client.getTypedRowWrapper(Interface.class, intfRow);
995 if (interfaceRow == null || interfaceRow.getName() == null) continue;
996 if (interfaceRow.getName().equals(portIdentifier)) break;
998 if (interfaceRow.getName() == null || !interfaceRow.getName().equals(portIdentifier)) {
999 return new Status(StatusCode.NOTFOUND);
1001 Interface updateInterface = client.createTypedRowWrapper(Interface.class);
1003 logger.debug("Interface type : " + type);
1004 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.TUNNEL.name())) {
1005 updateInterface.setType((String)configs.get(ConfigConstants.TUNNEL_TYPE));
1006 if (options == null) options = new HashMap<String, String>();
1007 options.put("remote_ip", (String)configs.get(ConfigConstants.DEST_IP));
1008 } else if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.PATCH.name()) ||
1009 type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.INTERNAL.name())) {
1010 updateInterface.setType(type.toLowerCase());
1013 if (options != null) {
1014 updateInterface.setOptions(options);
1017 Status intfStatus = null;
1018 intfStatus = this.updateRow(node, interfaceRow.getSchema().getName(), portStatus.getUuid().toString(),
1019 interfaceRow.getUuid().toString(), updateInterface.getRow());
1021 if (intfStatus.isSuccess()) return portStatus;
1026 * Implements the OVS Connection for Managers
1028 * @param node Node serving this configuration service
1029 * @param managerip String Representing IP and connection types
1031 @SuppressWarnings("unchecked")
1033 public boolean setManager(Node node, String managerip) {
1034 Connection connection = connectionService.getConnection(node);
1035 OvsdbClient client = connection.getClient();
1036 Manager manager = client.createTypedRowWrapper(Manager.class);
1037 manager.setTarget(ImmutableSet.of(managerip));
1039 OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
1040 ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
1041 if (row == null || row.size() == 0) {
1044 String ovsTableUuid = (String)row.keySet().toArray()[0];
1046 Status status = this.insertRow(node, manager.getSchema().getName(), ovsTableUuid, manager.getRow());
1047 return status.isSuccess();
1052 public Status addBridgeDomainConfig(Node node, String bridgeIdentfier,
1053 Map<ConfigConstants, Object> configs) {
1054 String mgmt = (String)configs.get(ConfigConstants.MGMT);
1056 if (setManager(node, mgmt)) return new Status(StatusCode.SUCCESS);
1058 return new Status(StatusCode.BADREQUEST);
1063 public Status deletePort(Node node, String bridgeIdentifier, String portIdentifier) {
1064 Connection connection = connectionService.getConnection(node);
1065 OvsdbClient client = connection.getClient();
1067 Port port = client.getTypedRowWrapper(Port.class, null);
1068 ConcurrentMap<String, Row> rows = this.getRows(node, port.getSchema().getName());
1069 if (rows == null || rows.size() == 0) {
1070 return new Status(StatusCode.NOTFOUND);
1072 for (String portUuid : rows.keySet()) {
1073 Row portRow = rows.get(portUuid);
1074 port = client.getTypedRowWrapper(Port.class, portRow);
1075 if (port.getName().equals(portIdentifier)) break;
1077 if (port.getName() == null || !port.getName().equals(portIdentifier)) {
1078 return new Status(StatusCode.NOTFOUND);
1080 return this.deleteRow(node, port.getSchema().getName(), port.getUuid().toString());
1085 public Status deleteBridgeDomain(Node node, String bridgeIdentifier) {
1086 Connection connection = connectionService.getConnection(node);
1087 OvsdbClient client = connection.getClient();
1089 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
1090 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
1091 if (rows == null || rows.size() == 0) {
1092 return new Status(StatusCode.NOTFOUND);
1094 for (String bridgeUuid : rows.keySet()) {
1095 Row bridgeRow = rows.get(bridgeUuid);
1096 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
1097 if (bridge.getName().equals(bridgeIdentifier)) break;
1099 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
1100 return new Status(StatusCode.NOTFOUND);
1102 return this.deleteRow(node, bridge.getSchema().getName(), bridge.getUuid().toString());
1106 public List<String> getBridgeDomains(Node node) {
1107 if (connectionService == null) {
1108 logger.error("Couldn't refer to the ConnectionService");
1112 Connection connection = connectionService.getConnection(node);
1113 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
1114 List<String> brlist = new ArrayList<String>();
1115 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
1116 if(brTableCache != null){
1117 for (String uuid : brTableCache.keySet()) {
1118 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
1119 brlist.add(bridge.getName());
1126 public NodeConnector getNodeConnector(Node arg0, String arg1, String arg2) {
1132 public Status addPortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1133 Map<ConfigConstants, Object> configs) {
1134 // TODO Auto-generated method stub
1140 public Node getBridgeDomainNode(Node node, String bridgeIdentifier) {
1141 // TODO Auto-generated method stub
1147 public Map<ConfigConstants, Object> getPortConfigs(Node node, String bridgeIdentifier,
1148 String portIdentifier) {
1149 // TODO Auto-generated method stub
1155 public Status removeBridgeDomainConfig(Node node, String bridgeIdentifier,
1156 Map<ConfigConstants, Object> configs) {
1157 // TODO Auto-generated method stub
1163 public Status removePortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1164 Map<ConfigConstants, Object> configs) {
1165 // TODO Auto-generated method stub
1171 public Map<ConfigConstants, Object> getBridgeDomainConfigs(Node node, String bridgeIdentifier) {
1172 // TODO Auto-generated method stub
1177 // SCHEMA-INDEPENDENT Configuration Service APIs
1179 private String getTableNameForRowUuid(Node node, String databaseName, UUID rowUuid) {
1180 ConcurrentMap<String, ConcurrentMap<String, Row>> cache = ovsdbInventoryService.getCache(node, databaseName);
1181 if (cache == null) return null;
1182 for (String tableName : cache.keySet()) {
1183 ConcurrentMap<String, Row> rows = cache.get(tableName);
1184 if (rows.get(rowUuid.toString()) != null) {
1191 private String getReferencingColumn (TableSchema<?> parentTableSchema, String childTableName) throws OvsdbPluginException {
1192 Map<String, ColumnSchema> columnSchemas = parentTableSchema.getColumnSchemas();
1193 String refColumn = null;
1194 for (String columnName : columnSchemas.keySet()) {
1195 ColumnSchema columnSchema = columnSchemas.get(columnName);
1196 if (columnSchema.getType().getBaseType().getClass().equals(UuidBaseType.class)) {
1197 UuidBaseType refType = (UuidBaseType)columnSchema.getType().getBaseType();
1198 if (refType.getRefTable() != null && refType.getRefTable().equalsIgnoreCase(childTableName)) {
1199 if (refColumn == null) {
1200 refColumn = columnName;
1202 throw new OvsdbPluginException("Multiple Referencing Columns for "+ childTableName +" on "+ parentTableSchema.getName());
1207 if (refColumn != null) {
1210 throw new OvsdbPluginException("No Referencing Column for "+childTableName+" on "+parentTableSchema.getName());
1213 * A common Insert Transaction convenience method that populates the TransactionBuilder with insert operation
1214 * for a Child Row and also mutates the parent row with the UUID of the inserted Child.
1216 private void processInsertTransaction(OvsdbClient client, String databaseName, String childTable,
1217 String parentTable, UUID parentUuid, String parentColumn, String namedUuid,
1218 Row<GenericTableSchema> row,
1219 TransactionBuilder transactionBuilder) {
1220 // Insert the row as the first transaction entry
1221 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1222 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
1223 transactionBuilder.add(op.insert(childTableSchema, row)
1224 .withId(namedUuid));
1226 // Followed by the Mutation
1227 if (parentColumn != null) {
1228 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1229 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
1230 ColumnSchema<GenericTableSchema, UUID> _uuid = parentTableSchema.column("_uuid", UUID.class);
1233 .add(op.mutate(parentTableSchema)
1234 .addMutation(parentColumnSchema, Mutator.INSERT, new UUID(namedUuid))
1235 .where(_uuid.opEqual(parentUuid))
1241 * insert a Row in a Table of a specified Database Schema.
1243 * This method can insert just a single Row specified in the row parameter.
1244 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1245 * can insert a hierarchy of rows with parent-child relationship.
1247 * @param node OVSDB Node
1248 * @param databaseName Database Name that represents the Schema supported by the node.
1249 * @param tableName Table on which the row is inserted
1250 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1251 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1252 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1253 * @param row Row of table Content to be inserted
1254 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1255 * @return UUID of the inserted Row
1258 public UUID insertRow(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1259 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1260 Connection connection = connectionService.getConnection(node);
1261 OvsdbClient client = connection.getClient();
1262 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1263 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1265 Row<GenericTableSchema> processedRow = this.insertTree(node, databaseName, tableName, parentTable, parentUuid, parentColumn, row);
1267 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
1268 Column<GenericTableSchema, UUID> uuid = processedRow.getColumn(_uuid);
1269 return uuid.getData();
1273 * insert a Row in a Table of a specified Database Schema. This is a convenience method on top of
1274 * {@link insertRow(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertRow}
1275 * which assumes that OVSDB schema implementation that corresponds to the databaseName will provide
1276 * the necessary service to populate the Parent Table Name and Parent Column Name.
1278 * This method can insert just a single Row specified in the row parameter.
1279 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1280 * can insert a hierarchy of rows with parent-child relationship.
1282 * @param node OVSDB Node
1283 * @param databaseName Database Name that represents the Schema supported by the node.
1284 * @param tableName Table on which the row is inserted
1285 * @param parentUuid UUID of the parent table to which this operation will result in attaching/mutating.
1286 * @param row Row of table Content to be inserted
1287 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1288 * @return UUID of the inserted Row
1291 public UUID insertRow(Node node, String databaseName, String tableName,
1292 UUID parentRowUuid, Row<GenericTableSchema> row)
1293 throws OvsdbPluginException {
1294 return this.insertRow(node, databaseName, tableName, null, parentRowUuid, null, row);
1298 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct
1300 * @param node OVSDB Node
1301 * @param databaseName Database Name that represents the Schema supported by the node.
1302 * @param tableName Table on which the row is inserted
1303 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1304 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1305 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1306 * @param row Row Tree with parent-child relationships via column of type refTable.
1307 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1308 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1311 public Row<GenericTableSchema> insertTree(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1312 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1313 Connection connection = connectionService.getConnection(node);
1314 OvsdbClient client = connection.getClient();
1316 if (databaseName == null || tableName == null) {
1317 throw new OvsdbPluginException("databaseName, tableName and parentUuid are Mandatory Parameters");
1320 if (parentTable == null && parentUuid != null) {
1321 parentTable = this.getTableNameForRowUuid(node, databaseName, parentUuid);
1324 if (parentColumn == null && parentTable != null) {
1325 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1326 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1327 parentColumn = this.getReferencingColumn(parentTableSchema, tableName);
1330 logger.debug("insertTree Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
1331 client.getConnectionInfo(), tableName, parentTable, parentColumn, parentUuid, row);
1333 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows = Maps.newConcurrentMap();
1334 extractReferencedRows(node, databaseName, row, referencedRows, 0);
1335 DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
1336 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1338 String namedUuid = "Transaction_"+ tableName;
1339 this.processInsertTransaction(client, databaseName, tableName, parentTable, parentUuid,
1340 parentColumn, namedUuid, row, transactionBuilder);
1342 int referencedRowsInsertIndex = transactionBuilder.getOperations().size();
1343 // Insert Referenced Rows
1344 if (referencedRows != null) {
1345 for (UUID refUuid : referencedRows.keySet()) {
1346 Map.Entry<String, Row<GenericTableSchema>> referencedRow = referencedRows.get(refUuid);
1347 TableSchema<GenericTableSchema> refTableSchema = dbSchema.table(referencedRow.getKey(), GenericTableSchema.class);
1348 transactionBuilder.add(op.insert(refTableSchema, referencedRow.getValue())
1349 .withId(refUuid.toString()));
1353 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1354 List<OperationResult> operationResults;
1356 operationResults = results.get();
1357 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1358 throw new OvsdbPluginException("Insert Operation Failed");
1360 for (OperationResult result : operationResults) {
1361 if (result.getError() != null) {
1362 throw new OvsdbPluginException("Insert Operation Failed with Error : "+result.getError().toString());
1365 return getNormalizedRow(dbSchema, tableName, row, referencedRows, operationResults, referencedRowsInsertIndex);
1366 } catch (InterruptedException | ExecutionException e) {
1367 throw new OvsdbPluginException("Exception : "+e.getLocalizedMessage());
1372 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct.
1373 * This is a convenience method on top of {@link #insertTree(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertTree}
1375 * @param node OVSDB Node
1376 * @param databaseName Database Name that represents the Schema supported by the node.
1377 * @param tableName Table on which the row is inserted
1378 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1379 * @param row Row Tree with parent-child relationships via column of type refTable.
1380 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1381 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1384 public Row<GenericTableSchema> insertTree(Node node, String databaseName,
1385 String tableName, UUID parentRowUuid, Row<GenericTableSchema> row)
1386 throws OvsdbPluginException {
1387 return this.insertTree(node, databaseName, tableName, null, parentRowUuid, null, row);
1391 * Convenience method that helps insertTree to extract Rows that are referenced directly from within a primary row
1392 * to be inserted. These referenced rows are *NOT* defined in the OVSDB specification. But, we felt that from a northbound
1393 * application standpoint, having such an option is useful and our implementation supports it for applications to make use of.
1394 * In short, whichever ColumnSchema is based on an UUID (refered by RefTable in schema), applications can directly insert an
1395 * entire row and this method will help navigate it through and identify such cases.
1396 * After identifying these Referenced Rows, it will modify the primary row with Named UUIDs and fill out the referencedRows
1397 * Map structure so that insertTree can insert all the Rows defined in this Tree of rows in a single transaction with automatic
1398 * Mutation on the parent rows.
1400 * @param node OVSDB Node
1401 * @param dbName Database Name that represents the Schema supported by the node.
1402 * @param row Row Tree with parent-child relationships via column of type refTable.
1403 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1404 * @param namedUuidSuffix Named UUID must be unique for every new Row insert within a given transaction.
1405 * This index will help to retain the uniqueness.
1407 private void extractReferencedRows(Node node, String dbName, Row<GenericTableSchema> row,
1408 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1409 int namedUuidSuffix) {
1410 OvsdbClient client = connectionService.getConnection(node).getClient();
1411 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1412 for (Column column : columns) {
1413 if (column.getData() != null) {
1414 if (column.getData() instanceof ReferencedRow) {
1415 ReferencedRow refRowObject = (ReferencedRow)column.getData();
1416 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1417 column.setData(refUuid);
1419 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1420 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1421 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1422 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1423 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1424 } catch (InterruptedException | ExecutionException e) {
1425 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1427 } else if (column.getData() instanceof OvsdbSet) {
1428 OvsdbSet<Object> setObject = (OvsdbSet<Object>)column.getData();
1429 OvsdbSet<Object> modifiedSet = new OvsdbSet<Object>();
1430 for (Object obj : setObject) {
1431 if (obj instanceof ReferencedRow) {
1432 ReferencedRow refRowObject = (ReferencedRow)obj;
1433 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1434 modifiedSet.add(refUuid);
1436 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1437 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1438 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1439 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1440 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1441 } catch (InterruptedException | ExecutionException e) {
1442 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1445 modifiedSet.add(obj);
1448 column.setData(modifiedSet);
1455 * getNormalizedRow normalizes the Row from a namedUuid Space as defined in extractReferencedRows to the actual Uuid as created
1456 * by the Ovsdb-server. In order to perform this normalization, it processes the operation results for a corresponding Transaction
1457 * where the referenced rows are inserted along with the Primary row. It changes the named-Uuid to the actual Uuid before returning
1458 * the Row to the application.
1460 * @param dbSchema Database Schema supported by the node.
1461 * @param row Row Tree with parent-child relationships via column of type refTable.
1462 * @param tableName Table on which the row is inserted
1463 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1464 * @param operationResults Operation Results returned by ovsdb-server for the insertTree transaction
1465 * @param referencedRowsInsertIndex Starting index in OperationResults from which the ReferencedRow insert results begin.
1468 private Row<GenericTableSchema> getNormalizedRow(DatabaseSchema dbSchema, String tableName, Row<GenericTableSchema> row,
1469 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1470 List<OperationResult> operationResults, int referencedRowsInsertIndex) {
1471 UUID primaryRowUuid = operationResults.get(0).getUuid();
1472 TableSchema<GenericTableSchema> primaryRowTableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1473 ColumnSchema<GenericTableSchema, UUID> _uuid = primaryRowTableSchema.column("_uuid", UUID.class);
1474 if (_uuid != null) {
1475 Column<GenericTableSchema, UUID> _uuidColumn = new Column<GenericTableSchema, UUID>(_uuid, primaryRowUuid);
1476 row.addColumn("_uuid", _uuidColumn);
1479 if (referencedRows != null) {
1480 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1481 if (referencedRows != null) {
1482 for (int idx=0; idx < referencedRows.keySet().size(); idx++) {
1483 UUID refUuid = (UUID) referencedRows.keySet().toArray()[idx];
1484 for (Column column : columns) {
1485 if (column.getData() != null) {
1486 if ((column.getData() instanceof UUID) && column.getData().equals(refUuid)) {
1487 column.setData(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1488 } else if ((column.getData() instanceof OvsdbSet) && ((OvsdbSet)column.getData()).contains(refUuid)) {
1489 OvsdbSet<UUID> refSet = (OvsdbSet<UUID>)column.getData();
1490 refSet.remove(refUuid);
1491 refSet.add(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1502 public Row<GenericTableSchema> updateRow(Node node, String databaseName,
1503 String tableName, UUID rowUuid, Row<GenericTableSchema> row,
1504 boolean overwrite) throws OvsdbPluginException {
1505 throw new OvsdbPluginException("Not implemented Yet");
1509 public void deleteRow(Node node, String databaseName, String tableName, String parentTable, UUID parentRowUuid,
1510 String parentColumn, UUID rowUuid) throws OvsdbPluginException {
1511 throw new OvsdbPluginException("Not implemented Yet");
1515 public void deleteRow(Node node, String databaseName, String tableName,
1516 UUID rowUuid) throws OvsdbPluginException {
1517 throw new OvsdbPluginException("Not implemented Yet");
1521 public Row<GenericTableSchema> getRow(Node node, String databaseName,
1522 String tableName, UUID uuid) throws OvsdbPluginException {
1523 throw new OvsdbPluginException("Not implemented Yet");
1527 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1528 String databaseName, String tableName) throws OvsdbPluginException {
1529 throw new OvsdbPluginException("Not implemented Yet");
1533 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1534 String databaseName, String tableName, String fiqlQuery)
1535 throws OvsdbPluginException {
1536 throw new OvsdbPluginException("Not implemented Yet");
1540 public List<String> getTables(Node node, String databaseName) throws OvsdbPluginException {
1541 throw new OvsdbPluginException("Not implemented Yet");