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.ColumnSchema;
50 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
51 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
52 import org.opendaylight.ovsdb.lib.schema.TableSchema;
53 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
54 import org.opendaylight.ovsdb.plugin.OvsdbConfigService;
55 import org.opendaylight.ovsdb.plugin.api.Connection;
56 import org.opendaylight.ovsdb.plugin.api.OvsVswitchdSchemaConstants;
57 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
58 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
59 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryService;
60 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
61 import org.opendaylight.ovsdb.plugin.error.OvsdbPluginException;
62 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
63 import org.opendaylight.ovsdb.schema.openvswitch.Controller;
64 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
65 import org.opendaylight.ovsdb.schema.openvswitch.Manager;
66 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
67 import org.opendaylight.ovsdb.schema.openvswitch.Port;
68 import org.osgi.framework.BundleContext;
69 import org.osgi.framework.FrameworkUtil;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
73 import com.fasterxml.jackson.databind.node.ObjectNode;
74 import com.google.common.collect.ImmutableSet;
75 import com.google.common.collect.Maps;
76 import com.google.common.util.concurrent.ListenableFuture;
78 public class ConfigurationServiceImpl implements IPluginInBridgeDomainConfigService,
79 OvsdbConfigurationService,
83 private static final Logger logger = LoggerFactory
84 .getLogger(ConfigurationServiceImpl.class);
86 OvsdbConnectionService connectionService;
87 OvsdbInventoryService ovsdbInventoryService;
88 boolean forceConnect = false;
89 protected static final String OPENFLOW_10 = "1.0";
90 protected static final String OPENFLOW_13 = "1.3";
96 * Function called by the dependency manager when at least one dependency
97 * become unsatisfied or when the component is shutting down because for
98 * example bundle is being stopped.
105 * Function called by dependency manager after "init ()" is called and after
106 * the services provided by the class are registered in the service registry
110 registerWithOSGIConsole();
113 private void registerWithOSGIConsole() {
114 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
116 bundleContext.registerService(CommandProvider.class.getName(), this,
121 * Function called by the dependency manager before the services exported by
122 * the component are unregistered, this will be followed by a "destroy ()"
129 public void setConnectionServiceInternal(OvsdbConnectionService connectionService) {
130 this.connectionService = connectionService;
133 public void unsetConnectionServiceInternal(OvsdbConnectionService connectionService) {
134 if (this.connectionService == connectionService) {
135 this.connectionService = null;
139 public void setOvsdbInventoryService(OvsdbInventoryService ovsdbInventoryService) {
140 this.ovsdbInventoryService = ovsdbInventoryService;
143 public void unsetInventoryServiceInternal(OvsdbInventoryService ovsdbInventoryService) {
144 if (this.ovsdbInventoryService == ovsdbInventoryService) {
145 this.ovsdbInventoryService = null;
149 private IClusterGlobalServices clusterServices;
151 public void setClusterServices(IClusterGlobalServices i) {
152 this.clusterServices = i;
155 public void unsetClusterServices(IClusterGlobalServices i) {
156 if (this.clusterServices == i) {
157 this.clusterServices = null;
161 private Connection getConnection (Node node) {
162 Connection connection = connectionService.getConnection(node);
163 if (connection == null || !connection.getClient().isActive()) {
170 * There are a few Open_vSwitch schema specific special case handling to be done for
171 * the older API (such as by inserting a mandatory Interface row automatically upon inserting
174 private void handleSpecialInsertCase(OvsdbClient client, String databaseName,
175 String tableName, String uuid, Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
176 Port port = client.getTypedRowWrapper(Port.class, null);
177 if (databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME) && tableName.equals(port.getSchema().getName())) {
178 port = client.getTypedRowWrapper(Port.class, row);
179 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
180 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
181 ColumnSchema<GenericTableSchema, Set<UUID>> columnSchema = tableSchema.multiValuedColumn("interfaces", UUID.class);
182 String namedUuid = "Special_"+tableName;
183 List<Operation> priorOperations = transactionBuilder.getOperations();
184 Insert portOperation = (Insert)priorOperations.get(0);
185 portOperation.value(columnSchema, new UUID(namedUuid));
187 Column<GenericTableSchema, ?> nameColumn = port.getNameColumn();
188 List<Column<GenericTableSchema, ?>> columns = new ArrayList<Column<GenericTableSchema, ?>>();
189 columns.add(nameColumn);
190 Row<GenericTableSchema> intfRow = new Row<GenericTableSchema>(tableSchema, columns);
191 this.processTypedInsertTransaction(client, databaseName, "Interface", null, null, null, namedUuid, intfRow, transactionBuilder);
196 * A common Transaction that takes in old API style Parent_uuid and inserts a mutation on
197 * the parent table for the newly inserted Child.
198 * Due to some additional special case(s), the Transaction is further amended by handleSpecialInsertCase
200 private void processTypedInsertTransaction(OvsdbClient client, String databaseName, String childTable,
201 String parentTable, String parentUuid, String parentColumn, String namedUuid,
202 Row<GenericTableSchema> row, TransactionBuilder transactionBuilder) {
203 this.processInsertTransaction(client, databaseName, childTable, parentTable, new UUID(parentUuid), parentColumn,
204 namedUuid, row, transactionBuilder);
206 * There are a few Open_vSwitch schema specific special case handling to be done for
207 * the older API (such as by inserting a mandatory Interface row automatically upon inserting
210 handleSpecialInsertCase(client, databaseName, childTable, namedUuid, row, transactionBuilder);
214 * TODO : Move all the Special Cases out of ConfigurationService and into the Schema specific bundles.
215 * But that makes plugin more reliant on the Typed Bundles more than just API wrapper.
216 * Keeping these Special Handling locally till we introduce the full schema independent APIs in the
219 public String getSpecialCaseParentUUID(Node node, String databaseName, String childTableName) {
220 if (!databaseName.equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) return null;
221 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(childTableName);
222 if (parentColumn != null && parentColumn[0].equals(OvsVswitchdSchemaConstants.DATABASE_NAME)) {
223 Connection connection = connectionService.getConnection(node);
224 OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
225 ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
226 if (row == null || row.size() == 0) return null;
227 return (String)row.keySet().toArray()[0];
233 * Though this is a New API that takes in Row object, this still is considered a
234 * Deprecated call because of the assumption with a Single Row insertion.
235 * An ideal insertRow must be able to take in multiple Rows, which includes the
236 * Row being inserted in one Table and other Rows that needs mutate in other Tables.
240 public StatusWithUuid insertRow(Node node, String tableName, String parentUuid, Row<GenericTableSchema> row) {
241 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
242 if (parentColumn == null) {
243 parentColumn = new String[]{null, null};
246 Connection connection = connectionService.getConnection(node);
247 OvsdbClient client = connection.getClient();
249 if (parentUuid == null) {
250 parentUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
252 logger.debug("insertRow Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
253 client.getConnectionInfo(), tableName, parentColumn[0], parentColumn[1], parentUuid, row);
255 DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
256 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
258 String namedUuid = "Transaction_"+ tableName;
259 this.processTypedInsertTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
260 parentColumn[0], parentUuid, parentColumn[1], namedUuid,
261 row, transactionBuilder);
263 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
264 List<OperationResult> operationResults;
266 operationResults = results.get();
267 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
268 return new StatusWithUuid(StatusCode.INTERNALERROR);
270 for (OperationResult result : operationResults) {
271 if (result.getError() != null) {
272 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
275 UUID uuid = operationResults.get(0).getUuid();
276 return new StatusWithUuid(StatusCode.SUCCESS, uuid);
277 } catch (InterruptedException | ExecutionException e) {
278 // TODO Auto-generated catch block
279 return new StatusWithUuid(StatusCode.INTERNALERROR, e.getLocalizedMessage());
286 public Status updateRow (Node node, String tableName, String parentUUID, String rowUUID, Row row) {
287 String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
288 Connection connection = connectionService.getConnection(node);
289 OvsdbClient client = connection.getClient();
291 logger.debug("updateRow : Connection : {} databaseName : {} tableName : {} rowUUID : {} row : {}",
292 client.getConnectionInfo(), databaseName, tableName, rowUUID, row.toString());
294 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
295 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
296 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
297 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
298 transactionBuilder.add(op.update(tableSchema, row)
299 .where(_uuid.opEqual(new UUID(rowUUID)))
302 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
303 List<OperationResult> operationResults = results.get();
304 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
305 return new StatusWithUuid(StatusCode.INTERNALERROR);
307 for (OperationResult result : operationResults) {
308 if (result.getError() != null) {
309 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
312 return new StatusWithUuid(StatusCode.SUCCESS);
313 } catch(Exception e){
314 logger.error("Error in updateRow(): ",e);
316 return new Status(StatusCode.INTERNALERROR);
319 private void processDeleteTransaction(OvsdbClient client, String databaseName, String childTable,
320 String parentTable, String parentColumn, String uuid, TransactionBuilder transactionBuilder) {
321 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
322 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
324 if (parentColumn != null) {
325 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
326 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
328 .add(op.mutate(parentTableSchema)
329 .addMutation(parentColumnSchema, Mutator.DELETE, new UUID(uuid))
330 .where(parentColumnSchema.opIncludes(new UUID(uuid)))
334 ColumnSchema<GenericTableSchema, UUID> _uuid = childTableSchema.column("_uuid", UUID.class);
335 transactionBuilder.add(op.delete(childTableSchema)
336 .where(_uuid.opEqual(new UUID(uuid)))
342 public Status deleteRow(Node node, String tableName, String uuid) {
343 String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
344 Connection connection = connectionService.getConnection(node);
345 OvsdbClient client = connection.getClient();
347 String[] parentColumn = OvsVswitchdSchemaConstants.getParentColumnToMutate(tableName);
348 if (parentColumn == null) {
349 parentColumn = new String[]{null, null};
352 logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
353 client.getConnectionInfo(), databaseName, tableName, uuid, parentColumn[0], parentColumn[1]);
355 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
356 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
357 this.processDeleteTransaction(client, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
358 parentColumn[0], parentColumn[1], uuid, transactionBuilder);
360 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
361 List<OperationResult> operationResults;
363 operationResults = results.get();
364 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
365 return new StatusWithUuid(StatusCode.INTERNALERROR);
367 for (OperationResult result : operationResults) {
368 if (result.getError() != null) {
369 return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
372 } catch (InterruptedException | ExecutionException e) {
373 // TODO Auto-generated catch block
377 return new Status(StatusCode.SUCCESS);
382 public ConcurrentMap<String, Row> getRows(Node node, String tableName) {
383 ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
389 public Row getRow(Node node, String tableName, String uuid) {
390 Map<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName);
391 if (ovsTable == null) return null;
392 return ovsTable.get(uuid);
397 public List<String> getTables(Node node) {
398 ConcurrentMap<String, ConcurrentMap<String, Row>> cache = ovsdbInventoryService.getCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME);
399 if (cache == null) return null;
400 return new ArrayList<String>(cache.keySet());
403 private List<InetAddress> getControllerIPAddresses(Connection connection) {
404 List<InetAddress> controllers = null;
405 InetAddress controllerIP = null;
407 controllers = new ArrayList<InetAddress>();
408 String addressString = System.getProperty("ovsdb.controller.address");
410 if (addressString != null) {
412 controllerIP = InetAddress.getByName(addressString);
413 if (controllerIP != null) {
414 controllers.add(controllerIP);
417 } catch (UnknownHostException e) {
418 logger.error("Host {} is invalid", addressString);
422 if (clusterServices != null) {
423 controllers = clusterServices.getClusteredControllers();
424 if (controllers != null && controllers.size() > 0) {
425 if (controllers.size() == 1) {
426 InetAddress controller = controllers.get(0);
427 if (!controller.equals(InetAddress.getLoopbackAddress())) {
436 addressString = System.getProperty("of.address");
438 if (addressString != null) {
440 controllerIP = InetAddress.getByName(addressString);
441 if (controllerIP != null) {
442 controllers.add(controllerIP);
445 } catch (UnknownHostException e) {
446 logger.error("Host {} is invalid", addressString);
451 controllerIP = connection.getClient().getConnectionInfo().getLocalAddress();
452 controllers.add(controllerIP);
454 } catch (Exception e) {
455 logger.debug("Invalid connection provided to getControllerIPAddresses", e);
460 private short getControllerOFPort() {
461 Short defaultOpenFlowPort = 6633;
462 Short openFlowPort = defaultOpenFlowPort;
463 String portString = System.getProperty("of.listenPort");
464 if (portString != null) {
466 openFlowPort = Short.decode(portString).shortValue();
467 } catch (NumberFormatException e) {
468 logger.warn("Invalid port:{}, use default({})", portString,
476 public Boolean setOFController(Node node, String bridgeUUID) throws InterruptedException, ExecutionException {
477 Connection connection = this.getConnection(node);
478 if (connection == null) {
482 Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
484 Status updateOperationStatus = null;
486 OvsdbSet<String> protocols = new OvsdbSet<String>();
488 String ofVersion = System.getProperty("ovsdb.of.version", OPENFLOW_10);
491 protocols.add("OpenFlow13");
496 protocols.add("OpenFlow10");
499 bridge.setProtocols(protocols);
500 updateOperationStatus = this.updateRow(node, bridge.getSchema().getName(),
501 null, bridgeUUID, bridge.getRow());
502 logger.debug("Bridge {} updated to {} with Status {}", bridgeUUID,
503 protocols.toArray()[0],updateOperationStatus);
505 } catch (SchemaVersionMismatchException e){
506 logger.debug(e.toString());
509 // If we fail to update the protocols
510 if (updateOperationStatus != null && !updateOperationStatus.isSuccess()) {
511 return updateOperationStatus.isSuccess();
514 Status status = null;
515 List<InetAddress> ofControllerAddrs = this.getControllerIPAddresses(connection);
516 short ofControllerPort = getControllerOFPort();
517 for (InetAddress ofControllerAddress : ofControllerAddrs) {
518 String newController = "tcp:"+ofControllerAddress.getHostAddress()+":"+ofControllerPort;
519 Controller controllerRow = connection.getClient().createTypedRowWrapper(Controller.class);
520 controllerRow.setTarget(newController);
521 //ToDo: Status gets overwritten on each iteration. If any operation other than the last fails it's ignored.
522 status = this.insertRow(node, controllerRow.getSchema().getName(), bridgeUUID, controllerRow.getRow());
525 if (status != null) {
526 return status.isSuccess();
533 public Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
534 if (connectionService == null) {
535 logger.error("Couldn't refer to the ConnectionService");
540 Connection connection = connectionService.getConnection(node);
541 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
543 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
544 for (String uuid : brTableCache.keySet()) {
545 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
546 if (bridge.getName().contains(bridgeIdentifier)) {
547 return setOFController(node, uuid);
550 } catch(Exception e) {
551 logger.error("Error in setBridgeOFController()",e);
557 public <T extends TypedBaseTable<?>> String getTableName(Node node, Class<T> typedClass) {
558 Connection connection = connectionService.getConnection(node);
559 if (connection == null) return null;
560 OvsdbClient client = connection.getClient();
561 TypedBaseTable<?> typedTable = client.getTypedRowWrapper(typedClass, null);
562 if (typedTable == null) return null;
563 return typedTable.getSchema().getName();
567 public <T extends TypedBaseTable<?>> T getTypedRow(Node node, Class<T> typedClass, Row row) {
568 Connection connection = connectionService.getConnection(node);
569 if (connection == null) return null;
570 OvsdbClient client = connection.getClient();
571 return (T)client.getTypedRowWrapper(typedClass, row);
575 public <T extends TypedBaseTable<?>> T createTypedRow(Node node, Class<T> typedClass) {
576 Connection connection = connectionService.getConnection(node);
577 if (connection == null) return null;
578 OvsdbClient client = connection.getClient();
579 return client.createTypedRowWrapper(typedClass);
582 public void _ovsconnect (CommandInterpreter ci) {
583 String bridgeName = ci.nextArgument();
584 if (bridgeName == null) {
585 ci.println("Please enter Bridge Name");
589 String ovsdbserver = ci.nextArgument();
590 if (ovsdbserver == null) {
591 ci.println("Please enter valid IP-Address");
595 InetAddress.getByName(ovsdbserver);
596 } catch (UnknownHostException e) {
597 logger.error("Unable to resolve " + ovsdbserver, e);
598 ci.println("Please enter valid IP-Address");
601 String port = ci.nextArgument();
606 ci.println("connecting to ovsdb server : "+ovsdbserver+":"+port+" ... ");
607 Map<ConnectionConstants, String> params = new HashMap<ConnectionConstants, String>();
608 params.put(ConnectionConstants.ADDRESS, ovsdbserver);
609 params.put(ConnectionConstants.PORT, port);
610 Node node = connectionService.connect(bridgeName, params);
611 if (node != null) ci.println("Node Name: "+node.toString());
612 else ci.println("Could not connect to Node");
615 public void _addBridge (CommandInterpreter ci) {
616 String nodeName = ci.nextArgument();
617 if (nodeName == null) {
618 ci.println("Please enter Node Name");
621 String bridgeName = ci.nextArgument();
622 if (bridgeName == null) {
623 ci.println("Please enter Bridge Name");
628 Node node = Node.fromString(nodeName);
630 ci.println("Invalid Node");
633 status = this.createBridgeDomain(node, bridgeName, null);
634 ci.println("Bridge creation status : "+status.toString());
637 public void _getBridgeDomains (CommandInterpreter ci) {
638 String nodeName = ci.nextArgument();
639 if (nodeName == null) {
640 ci.println("Please enter Node Name");
644 List<String> brlist = new ArrayList<String>();
645 Node node = Node.fromString(nodeName);
646 brlist = this.getBridgeDomains(node);
648 ci.println("Invalid Node");
651 ci.println("Existing Bridges: "+brlist.toString());
654 public void _deleteBridgeDomain (CommandInterpreter ci) {
655 String nodeName = ci.nextArgument();
656 if (nodeName == null) {
657 ci.println("Please enter Node Name");
660 String bridgeName = ci.nextArgument();
661 if (bridgeName == null) {
662 ci.println("Please enter Bridge Name");
666 Node node = Node.fromString(nodeName);
668 ci.println("Invalid Node");
671 status = this.deleteBridgeDomain(node, bridgeName);
672 ci.println("Bridge deletion status : "+status.toString());
675 public void _addPort (CommandInterpreter ci) {
676 String nodeName = ci.nextArgument();
677 if (nodeName == null) {
678 ci.println("Please enter Node Name");
682 String bridgeName = ci.nextArgument();
683 if (bridgeName == null) {
684 ci.println("Please enter Bridge Name");
688 String portName = ci.nextArgument();
689 if (portName == null) {
690 ci.println("Please enter Port Name");
694 String type = ci.nextArgument();
696 Map<String, String> configs = new HashMap<String, String>();
698 String configKey = ci.nextArgument();
699 if (configKey == null) break;
700 String configValue = ci.nextArgument();
701 if (configValue == null) break;
702 configs.put(configKey, configValue);
705 Map<ConfigConstants, Object> customConfigs = null;
707 customConfigs = new HashMap<ConfigConstants, Object>();
708 customConfigs.put(ConfigConstants.TYPE, type);
711 if (configs.size() > 0) {
712 if (customConfigs == null) customConfigs = new HashMap<ConfigConstants, Object>();
713 customConfigs.put(ConfigConstants.CUSTOM, configs);
714 ci.println(customConfigs.toString());
717 Node node = Node.fromString(nodeName);
719 ci.println("Invalid Node");
722 status = this.addPort(node, bridgeName, portName, customConfigs);
723 ci.println("Port creation status : "+status.toString());
726 public void _deletePort (CommandInterpreter ci) {
727 String nodeName = ci.nextArgument();
728 if (nodeName == null) {
729 ci.println("Please enter Node Name");
733 String bridgeName = ci.nextArgument();
734 if (bridgeName == null) {
735 ci.println("Please enter Bridge Name");
739 String portName = ci.nextArgument();
740 if (portName == null) {
741 ci.println("Please enter Port Name");
746 Node node = Node.fromString(nodeName);
748 ci.println("Invalid Node");
751 status = this.deletePort(node, bridgeName, portName);
752 ci.println("Port deletion status : "+status.toString());
755 public void _addPortVlan (CommandInterpreter ci) {
756 String nodeName = ci.nextArgument();
757 if (nodeName == null) {
758 ci.println("Please enter Node Name");
762 String bridgeName = ci.nextArgument();
763 if (bridgeName == null) {
764 ci.println("Please enter Bridge Name");
768 String portName = ci.nextArgument();
769 if (portName == null) {
770 ci.println("Please enter Port Name");
774 String vlan = ci.nextArgument();
776 ci.println("Please enter Valid Vlan");
780 Integer.parseInt(vlan);
781 } catch (NumberFormatException e) {
782 ci.println("Please enter Valid Vlan");
787 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
788 configs.put(ConfigConstants.TYPE, "VLAN");
789 configs.put(ConfigConstants.VLAN, vlan);
792 Node node = Node.fromString(nodeName);
794 ci.println("Invalid Node");
797 status = this.addPort(node, bridgeName, portName, configs);
798 ci.println("Port creation status : "+status.toString());
801 public void _addTunnel (CommandInterpreter ci) {
802 String nodeName = ci.nextArgument();
803 if (nodeName == null) {
804 ci.println("Please enter Node Name");
808 String bridgeName = ci.nextArgument();
809 if (bridgeName == null) {
810 ci.println("Please enter Bridge Name");
814 String portName = ci.nextArgument();
815 if (portName == null) {
816 ci.println("Please enter Port Name");
820 String tunnelType = ci.nextArgument();
821 if (tunnelType == null) {
822 ci.println("Please enter Tunnel Type");
826 String remoteIp = ci.nextArgument();
827 if (remoteIp == null) {
828 ci.println("Please enter valid Remote IP Address");
833 InetAddress.getByName(remoteIp);
834 } catch (Exception e) {
835 logger.error("Unable to resolve " + remoteIp, e);
836 ci.println("Please enter valid Remote IP Address");
840 Map<ConfigConstants, Object> configs = new HashMap<ConfigConstants, Object>();
841 configs.put(ConfigConstants.TYPE, "TUNNEL");
842 configs.put(ConfigConstants.TUNNEL_TYPE, tunnelType);
843 configs.put(ConfigConstants.DEST_IP, remoteIp);
846 Node node = Node.fromString(nodeName);
848 ci.println("Invalid Node");
851 status = this.addPort(node, bridgeName, portName, configs);
852 ci.println("Port creation status : "+status.toString());
855 public void _printCache (CommandInterpreter ci) {
856 String nodeName = ci.nextArgument();
857 if (nodeName == null) {
858 ci.println("Please enter Node Name");
861 Node node = Node.fromString(nodeName);
863 ci.println("Invalid Node");
866 ovsdbInventoryService.printCache(node);
869 public void _forceConnect (CommandInterpreter ci) {
870 String force = ci.nextArgument();
871 if (force.equalsIgnoreCase("YES")) {
874 else if (force.equalsIgnoreCase("NO")) {
875 forceConnect = false;
878 ci.println("Please enter YES or NO.");
880 ci.println("Current ForceConnect State : "+forceConnect);
884 public String getHelp() {
885 StringBuilder help = new StringBuilder();
886 help.append("---OVSDB CLI---\n");
887 help.append("\t ovsconnect <ConnectionName> <ip-address> - Connect to OVSDB\n");
888 help.append("\t addBridge <Node> <BridgeName> - Add Bridge\n");
889 help.append("\t getBridgeDomains <Node> - Get Bridges\n");
890 help.append("\t deleteBridgeDomain <Node> <BridgeName> - Delete a Bridge\n");
891 help.append("\t addPort <Node> <BridgeName> <PortName> <type> <options pairs> - Add Port\n");
892 help.append("\t deletePort <Node> <BridgeName> <PortName> - Delete Port\n");
893 help.append("\t addPortVlan <Node> <BridgeName> <PortName> <vlan> - Add Port, Vlan\n");
894 help.append("\t addTunnel <Node> <Bridge> <Port> <tunnel-type> <remote-ip> - Add Tunnel\n");
895 help.append("\t printCache <Node> - Prints Table Cache");
896 return help.toString();
902 * @param node Node serving this configuration service
903 * @param bridgeIdentifier String representation of a Bridge Connector
904 * @return Bridge Connector configurations
908 public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> configs) {
909 Connection connection = connectionService.getConnection(node);
910 OvsdbClient client = connection.getClient();
911 Bridge bridge = client.createTypedRowWrapper(Bridge.class);
912 bridge.setName(bridgeIdentifier);
914 String ovsTableUuid = this.getSpecialCaseParentUUID(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
915 return this.insertRow(node, bridge.getSchema().getName(), ovsTableUuid, bridge.getRow());
919 * Create a Port Attached to a Bridge
920 * Ex. ovs-vsctl add-port br0 vif0
921 * @param node Node serving this configuration service
922 * @param bridgeIdentifier String representation of a Bridge Domain
923 * @param portIdentifier String representation of a user defined Port Name
927 public Status addPort(Node node, String bridgeIdentifier, String portIdentifier,
928 Map<ConfigConstants, Object> configs) {
929 Connection connection = connectionService.getConnection(node);
930 OvsdbClient client = connection.getClient();
932 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
933 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
934 if (rows == null || rows.size() == 0) {
935 return new Status(StatusCode.NOTFOUND);
937 for (String bridgeUuid : rows.keySet()) {
938 Row bridgeRow = rows.get(bridgeUuid);
939 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
940 if (bridge.getName().equals(bridgeIdentifier)) break;
942 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
943 return new Status(StatusCode.NOTFOUND);
946 Map<String, String> options = null;
948 Set<Long> tags = null;
949 if (configs != null) {
950 type = (String) configs.get(ConfigConstants.TYPE);
951 Map<String, String> customConfigs = (Map<String, String>) configs.get(ConfigConstants.CUSTOM);
952 if (customConfigs != null) {
953 options = new HashMap<String, String>();
954 for (String customConfig : customConfigs.keySet()) {
955 options.put(customConfig, customConfigs.get(customConfig));
961 logger.debug("Port type : " + type);
962 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.VLAN.name())) {
963 tags = new HashSet<Long>();
964 tags.add(Long.parseLong((String)configs.get(ConfigConstants.VLAN)));
968 Port port = client.createTypedRowWrapper(Port.class);
969 port.setName(portIdentifier);
970 if (tags != null) port.setTag(tags);
971 StatusWithUuid portStatus = this.insertRow(node, port.getSchema().getName(), bridge.getUuid().toString(), port.getRow());
973 if (!portStatus.isSuccess()) return portStatus;
974 // Ugly hack by adding a sleep for the Monitor Update to catch up.
975 // TODO : Remove this once the Select operation is in place.
976 // We are currently relying on the local Cache for any GET operation and that might fail if we try to
977 // fetch the last installed entry. Hence we need the Select operation to work.
981 } catch (InterruptedException e) {
982 // TODO Auto-generated catch block
986 Interface interfaceRow = client.createTypedRowWrapper(Interface.class);
987 ConcurrentMap<String, Row> intfRows = this.getRows(node, interfaceRow.getSchema().getName());
988 if (intfRows == null || intfRows.size() == 0) {
989 return new Status(StatusCode.NOTFOUND);
991 for (String intfUuid : intfRows.keySet()) {
992 Row intfRow = intfRows.get(intfUuid);
993 interfaceRow = client.getTypedRowWrapper(Interface.class, intfRow);
994 if (interfaceRow == null || interfaceRow.getName() == null) continue;
995 if (interfaceRow.getName().equals(portIdentifier)) break;
997 if (interfaceRow.getName() == null || !interfaceRow.getName().equals(portIdentifier)) {
998 return new Status(StatusCode.NOTFOUND);
1000 Interface updateInterface = client.createTypedRowWrapper(Interface.class);
1002 logger.debug("Interface type : " + type);
1003 if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.TUNNEL.name())) {
1004 updateInterface.setType((String)configs.get(ConfigConstants.TUNNEL_TYPE));
1005 if (options == null) options = new HashMap<String, String>();
1006 options.put("remote_ip", (String)configs.get(ConfigConstants.DEST_IP));
1007 } else if (type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.PATCH.name()) ||
1008 type.equalsIgnoreCase(OvsVswitchdSchemaConstants.PortType.INTERNAL.name())) {
1009 updateInterface.setType(type.toLowerCase());
1012 if (options != null) {
1013 updateInterface.setOptions(options);
1016 Status intfStatus = null;
1017 intfStatus = this.updateRow(node, interfaceRow.getSchema().getName(), portStatus.getUuid().toString(),
1018 interfaceRow.getUuid().toString(), updateInterface.getRow());
1020 if (intfStatus.isSuccess()) return portStatus;
1025 * Implements the OVS Connection for Managers
1027 * @param node Node serving this configuration service
1028 * @param managerip String Representing IP and connection types
1030 @SuppressWarnings("unchecked")
1032 public boolean setManager(Node node, String managerip) {
1033 Connection connection = connectionService.getConnection(node);
1034 OvsdbClient client = connection.getClient();
1035 Manager manager = client.createTypedRowWrapper(Manager.class);
1036 manager.setTarget(ImmutableSet.of(managerip));
1038 OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
1039 ConcurrentMap<String, Row> row = this.getRows(node, openVSwitch.getSchema().getName());
1040 if (row == null || row.size() == 0) {
1043 String ovsTableUuid = (String)row.keySet().toArray()[0];
1045 Status status = this.insertRow(node, manager.getSchema().getName(), ovsTableUuid, manager.getRow());
1046 return status.isSuccess();
1051 public Status addBridgeDomainConfig(Node node, String bridgeIdentfier,
1052 Map<ConfigConstants, Object> configs) {
1053 String mgmt = (String)configs.get(ConfigConstants.MGMT);
1055 if (setManager(node, mgmt)) return new Status(StatusCode.SUCCESS);
1057 return new Status(StatusCode.BADREQUEST);
1062 public Status deletePort(Node node, String bridgeIdentifier, String portIdentifier) {
1063 Connection connection = connectionService.getConnection(node);
1064 OvsdbClient client = connection.getClient();
1066 Port port = client.getTypedRowWrapper(Port.class, null);
1067 ConcurrentMap<String, Row> rows = this.getRows(node, port.getSchema().getName());
1068 if (rows == null || rows.size() == 0) {
1069 return new Status(StatusCode.NOTFOUND);
1071 for (String portUuid : rows.keySet()) {
1072 Row portRow = rows.get(portUuid);
1073 port = client.getTypedRowWrapper(Port.class, portRow);
1074 if (port.getName().equals(portIdentifier)) break;
1076 if (port.getName() == null || !port.getName().equals(portIdentifier)) {
1077 return new Status(StatusCode.NOTFOUND);
1079 return this.deleteRow(node, port.getSchema().getName(), port.getUuid().toString());
1084 public Status deleteBridgeDomain(Node node, String bridgeIdentifier) {
1085 Connection connection = connectionService.getConnection(node);
1086 OvsdbClient client = connection.getClient();
1088 Bridge bridge = client.getTypedRowWrapper(Bridge.class, null);
1089 ConcurrentMap<String, Row> rows = this.getRows(node, bridge.getSchema().getName());
1090 if (rows == null || rows.size() == 0) {
1091 return new Status(StatusCode.NOTFOUND);
1093 for (String bridgeUuid : rows.keySet()) {
1094 Row bridgeRow = rows.get(bridgeUuid);
1095 bridge = client.getTypedRowWrapper(Bridge.class, bridgeRow);
1096 if (bridge.getName().equals(bridgeIdentifier)) break;
1098 if (bridge.getName() == null || !bridge.getName().equals(bridgeIdentifier)) {
1099 return new Status(StatusCode.NOTFOUND);
1101 return this.deleteRow(node, bridge.getSchema().getName(), bridge.getUuid().toString());
1105 public List<String> getBridgeDomains(Node node) {
1106 if (connectionService == null) {
1107 logger.error("Couldn't refer to the ConnectionService");
1111 Connection connection = connectionService.getConnection(node);
1112 Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
1113 List<String> brlist = new ArrayList<String>();
1114 Map<String, Row> brTableCache = ovsdbInventoryService.getTableCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME, bridge.getSchema().getName());
1115 if(brTableCache != null){
1116 for (String uuid : brTableCache.keySet()) {
1117 bridge = connection.getClient().getTypedRowWrapper(Bridge.class, brTableCache.get(uuid));
1118 brlist.add(bridge.getName());
1125 public NodeConnector getNodeConnector(Node arg0, String arg1, String arg2) {
1131 public Status addPortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1132 Map<ConfigConstants, Object> configs) {
1133 // TODO Auto-generated method stub
1139 public Node getBridgeDomainNode(Node node, String bridgeIdentifier) {
1140 // TODO Auto-generated method stub
1146 public Map<ConfigConstants, Object> getPortConfigs(Node node, String bridgeIdentifier,
1147 String portIdentifier) {
1148 // TODO Auto-generated method stub
1154 public Status removeBridgeDomainConfig(Node node, String bridgeIdentifier,
1155 Map<ConfigConstants, Object> configs) {
1156 // TODO Auto-generated method stub
1162 public Status removePortConfig(Node node, String bridgeIdentifier, String portIdentifier,
1163 Map<ConfigConstants, Object> configs) {
1164 // TODO Auto-generated method stub
1170 public Map<ConfigConstants, Object> getBridgeDomainConfigs(Node node, String bridgeIdentifier) {
1171 // TODO Auto-generated method stub
1176 // SCHEMA-INDEPENDENT Configuration Service APIs
1179 * A common Insert Transaction convenience method that populates the TransactionBuilder with insert operation
1180 * for a Child Row and also mutates the parent row with the UUID of the inserted Child.
1182 private void processInsertTransaction(OvsdbClient client, String databaseName, String childTable,
1183 String parentTable, UUID parentUuid, String parentColumn, String namedUuid,
1184 Row<GenericTableSchema> row,
1185 TransactionBuilder transactionBuilder) {
1186 // Insert the row as the first transaction entry
1187 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1188 TableSchema<GenericTableSchema> childTableSchema = dbSchema.table(childTable, GenericTableSchema.class);
1189 transactionBuilder.add(op.insert(childTableSchema, row)
1190 .withId(namedUuid));
1192 // Followed by the Mutation
1193 if (parentColumn != null) {
1194 TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
1195 ColumnSchema<GenericTableSchema, UUID> parentColumnSchema = parentTableSchema.column(parentColumn, UUID.class);
1196 ColumnSchema<GenericTableSchema, UUID> _uuid = parentTableSchema.column("_uuid", UUID.class);
1199 .add(op.mutate(parentTableSchema)
1200 .addMutation(parentColumnSchema, Mutator.INSERT, new UUID(namedUuid))
1201 .where(_uuid.opEqual(parentUuid))
1207 * insert a Row in a Table of a specified Database Schema.
1209 * This method can insert just a single Row specified in the row parameter.
1210 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1211 * can insert a hierarchy of rows with parent-child relationship.
1213 * @param node OVSDB Node
1214 * @param databaseName Database Name that represents the Schema supported by the node.
1215 * @param tableName Table on which the row is inserted
1216 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1217 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1218 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1219 * @param row Row of table Content to be inserted
1220 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1221 * @return UUID of the inserted Row
1224 public UUID insertRow(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1225 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1226 Connection connection = connectionService.getConnection(node);
1227 OvsdbClient client = connection.getClient();
1228 DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
1229 TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1231 Row<GenericTableSchema> processedRow = this.insertTree(node, databaseName, tableName, parentTable, parentUuid, parentColumn, row);
1233 ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
1234 Column<GenericTableSchema, UUID> uuid = processedRow.getColumn(_uuid);
1235 return uuid.getData();
1239 * insert a Row in a Table of a specified Database Schema. This is a convenience method on top of
1240 * {@link insertRow(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertRow}
1241 * which assumes that OVSDB schema implementation that corresponds to the databaseName will provide
1242 * the necessary service to populate the Parent Table Name and Parent Column Name.
1244 * This method can insert just a single Row specified in the row parameter.
1245 * But {@link #insertTree(Node, String, String, UUID, Row<GenericTableSchema>) insertTree}
1246 * can insert a hierarchy of rows with parent-child relationship.
1248 * @param node OVSDB Node
1249 * @param databaseName Database Name that represents the Schema supported by the node.
1250 * @param tableName Table on which the row is inserted
1251 * @param parentUuid UUID of the parent table to which this operation will result in attaching/mutating.
1252 * @param row Row of table Content to be inserted
1253 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1254 * @return UUID of the inserted Row
1257 public UUID insertRow(Node node, String databaseName, String tableName,
1258 UUID parentRowUuid, Row<GenericTableSchema> row)
1259 throws OvsdbPluginException {
1260 return this.insertRow(node, databaseName, tableName, null, parentRowUuid, null, row);
1264 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct
1266 * @param node OVSDB Node
1267 * @param databaseName Database Name that represents the Schema supported by the node.
1268 * @param tableName Table on which the row is inserted
1269 * @param parentTable Name of the Parent Table to which this operation will result in attaching/mutating.
1270 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1271 * @param parentColumn Name of the Column in the Parent Table to be mutated with the UUID that results from the insert operation.
1272 * @param row Row Tree with parent-child relationships via column of type refTable.
1273 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1274 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1277 public Row<GenericTableSchema> insertTree(Node node, String databaseName, String tableName, String parentTable, UUID parentUuid,
1278 String parentColumn, Row<GenericTableSchema> row) throws OvsdbPluginException {
1279 Connection connection = connectionService.getConnection(node);
1280 OvsdbClient client = connection.getClient();
1282 if (databaseName == null || tableName == null) {
1283 throw new OvsdbPluginException("databaseName, tableName and parentUuid are Mandatory Parameters");
1285 logger.debug("insertTree Connection : {} Table : {} ParentTable : {} Parent Column: {} Parent UUID : {} Row : {}",
1286 client.getConnectionInfo(), tableName, parentTable, parentColumn, parentUuid, row);
1288 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows = Maps.newConcurrentMap();
1289 extractReferencedRows(node, databaseName, row, referencedRows, 0);
1290 DatabaseSchema dbSchema = client.getDatabaseSchema(OvsVswitchdSchemaConstants.DATABASE_NAME);
1291 TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
1293 String namedUuid = "Transaction_"+ tableName;
1294 this.processInsertTransaction(client, databaseName, tableName, parentTable, parentUuid,
1295 parentColumn, namedUuid, row, transactionBuilder);
1297 int referencedRowsInsertIndex = transactionBuilder.getOperations().size();
1298 // Insert Referenced Rows
1299 if (referencedRows != null) {
1300 for (UUID refUuid : referencedRows.keySet()) {
1301 Map.Entry<String, Row<GenericTableSchema>> referencedRow = referencedRows.get(refUuid);
1302 TableSchema<GenericTableSchema> refTableSchema = dbSchema.table(referencedRow.getKey(), GenericTableSchema.class);
1303 transactionBuilder.add(op.insert(refTableSchema, referencedRow.getValue())
1304 .withId(refUuid.toString()));
1308 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
1309 List<OperationResult> operationResults;
1311 operationResults = results.get();
1312 if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
1313 throw new OvsdbPluginException("Insert Operation Failed");
1315 for (OperationResult result : operationResults) {
1316 if (result.getError() != null) {
1317 throw new OvsdbPluginException("Insert Operation Failed with Error : "+result.getError().toString());
1320 return getNormalizedRow(dbSchema, tableName, row, referencedRows, operationResults, referencedRowsInsertIndex);
1321 } catch (InterruptedException | ExecutionException e) {
1322 throw new OvsdbPluginException("Exception : "+e.getLocalizedMessage());
1327 * inserts a Tree of Rows in multiple Tables that has parent-child relationships referenced through the OVSDB schema's refTable construct.
1328 * This is a convenience method on top of {@link #insertTree(Node, String, String, String, UUID, String, Row<GenericTableSchema>) insertTree}
1330 * @param node OVSDB Node
1331 * @param databaseName Database Name that represents the Schema supported by the node.
1332 * @param tableName Table on which the row is inserted
1333 * @param parentUuid UUID of a Row in parent table to which this operation will result in attaching/mutating.
1334 * @param row Row Tree with parent-child relationships via column of type refTable.
1335 * @throws OvsdbPluginException Any failure during the insert transaction will result in a specific exception.
1336 * @return Returns the row tree with the UUID of every inserted Row populated in the _uuid column of every row in the tree
1339 public Row<GenericTableSchema> insertTree(Node node, String databaseName,
1340 String tableName, UUID parentRowUuid, Row<GenericTableSchema> row)
1341 throws OvsdbPluginException {
1342 return this.insertTree(node, databaseName, tableName, null, parentRowUuid, null, row);
1346 * Convenience method that helps insertTree to extract Rows that are referenced directly from within a primary row
1347 * to be inserted. These referenced rows are *NOT* defined in the OVSDB specification. But, we felt that from a northbound
1348 * application standpoint, having such an option is useful and our implementation supports it for applications to make use of.
1349 * In short, whichever ColumnSchema is based on an UUID (refered by RefTable in schema), applications can directly insert an
1350 * entire row and this method will help navigate it through and identify such cases.
1351 * After identifying these Referenced Rows, it will modify the primary row with Named UUIDs and fill out the referencedRows
1352 * Map structure so that insertTree can insert all the Rows defined in this Tree of rows in a single transaction with automatic
1353 * Mutation on the parent rows.
1355 * @param node OVSDB Node
1356 * @param dbName Database Name that represents the Schema supported by the node.
1357 * @param row Row Tree with parent-child relationships via column of type refTable.
1358 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1359 * @param namedUuidSuffix Named UUID must be unique for every new Row insert within a given transaction.
1360 * This index will help to retain the uniqueness.
1362 private void extractReferencedRows(Node node, String dbName, Row<GenericTableSchema> row,
1363 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1364 int namedUuidSuffix) {
1365 OvsdbClient client = connectionService.getConnection(node).getClient();
1366 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1367 for (Column column : columns) {
1368 if (column.getData() != null) {
1369 if (column.getData() instanceof ReferencedRow) {
1370 ReferencedRow refRowObject = (ReferencedRow)column.getData();
1371 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1372 column.setData(refUuid);
1374 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1375 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1376 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1377 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1378 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1379 } catch (InterruptedException | ExecutionException e) {
1380 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1382 } else if (column.getData() instanceof OvsdbSet) {
1383 OvsdbSet<Object> setObject = (OvsdbSet<Object>)column.getData();
1384 OvsdbSet<Object> modifiedSet = new OvsdbSet<Object>();
1385 for (Object obj : setObject) {
1386 if (obj instanceof ReferencedRow) {
1387 ReferencedRow refRowObject = (ReferencedRow)obj;
1388 UUID refUuid = new UUID("NamedUuid"+namedUuidSuffix++);
1389 modifiedSet.add(refUuid);
1391 DatabaseSchema dbSchema = client.getSchema(dbName).get();
1392 GenericTableSchema schema = dbSchema.table(refRowObject.getRefTable(), GenericTableSchema.class);
1393 Row<GenericTableSchema> refRow = schema.createRow((ObjectNode)refRowObject.getJsonNode());
1394 referencedRows.put(refUuid, new AbstractMap.SimpleEntry<String, Row<GenericTableSchema>>(refRowObject.getRefTable(), refRow));
1395 extractReferencedRows(node, dbName, refRow, referencedRows, namedUuidSuffix);
1396 } catch (InterruptedException | ExecutionException e) {
1397 logger.error("Exception while extracting multi-level Row references " + e.getLocalizedMessage());
1400 modifiedSet.add(obj);
1403 column.setData(modifiedSet);
1410 * getNormalizedRow normalizes the Row from a namedUuid Space as defined in extractReferencedRows to the actual Uuid as created
1411 * by the Ovsdb-server. In order to perform this normalization, it processes the operation results for a corresponding Transaction
1412 * where the referenced rows are inserted along with the Primary row. It changes the named-Uuid to the actual Uuid before returning
1413 * the Row to the application.
1415 * @param dbSchema Database Schema supported by the node.
1416 * @param row Row Tree with parent-child relationships via column of type refTable.
1417 * @param tableName Table on which the row is inserted
1418 * @param referencedRows Map of Named-UUID to the actual referenced row (with RefTable)
1419 * @param operationResults Operation Results returned by ovsdb-server for the insertTree transaction
1420 * @param referencedRowsInsertIndex Starting index in OperationResults from which the ReferencedRow insert results begin.
1423 private Row<GenericTableSchema> getNormalizedRow(DatabaseSchema dbSchema, String tableName, Row<GenericTableSchema> row,
1424 Map<UUID, Map.Entry<String, Row<GenericTableSchema>>> referencedRows,
1425 List<OperationResult> operationResults, int referencedRowsInsertIndex) {
1426 UUID primaryRowUuid = operationResults.get(0).getUuid();
1427 TableSchema<GenericTableSchema> primaryRowTableSchema = dbSchema.table(tableName, GenericTableSchema.class);
1428 ColumnSchema<GenericTableSchema, UUID> _uuid = primaryRowTableSchema.column("_uuid", UUID.class);
1429 if (_uuid != null) {
1430 Column<GenericTableSchema, UUID> _uuidColumn = new Column<GenericTableSchema, UUID>(_uuid, primaryRowUuid);
1431 row.addColumn("_uuid", _uuidColumn);
1434 if (referencedRows != null) {
1435 Collection<Column<GenericTableSchema, ?>> columns = row.getColumns();
1436 if (referencedRows != null) {
1437 for (int idx=0; idx < referencedRows.keySet().size(); idx++) {
1438 UUID refUuid = (UUID) referencedRows.keySet().toArray()[idx];
1439 for (Column column : columns) {
1440 if (column.getData() != null) {
1441 if ((column.getData() instanceof UUID) && column.getData().equals(refUuid)) {
1442 column.setData(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1443 } else if ((column.getData() instanceof OvsdbSet) && ((OvsdbSet)column.getData()).contains(refUuid)) {
1444 OvsdbSet<UUID> refSet = (OvsdbSet<UUID>)column.getData();
1445 refSet.remove(refUuid);
1446 refSet.add(operationResults.get(referencedRowsInsertIndex + idx).getUuid());
1457 public Row<GenericTableSchema> updateRow(Node node, String databaseName,
1458 String tableName, UUID rowUuid, Row<GenericTableSchema> row,
1459 boolean overwrite) throws OvsdbPluginException {
1460 throw new OvsdbPluginException("Not implemented Yet");
1464 public void deleteRow(Node node, String databaseName, String tableName, String parentTable, UUID parentRowUuid,
1465 String parentColumn, UUID rowUuid) throws OvsdbPluginException {
1466 throw new OvsdbPluginException("Not implemented Yet");
1470 public void deleteRow(Node node, String databaseName, String tableName,
1471 UUID rowUuid) throws OvsdbPluginException {
1472 throw new OvsdbPluginException("Not implemented Yet");
1476 public Row<GenericTableSchema> getRow(Node node, String databaseName,
1477 String tableName, UUID uuid) throws OvsdbPluginException {
1478 throw new OvsdbPluginException("Not implemented Yet");
1482 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1483 String databaseName, String tableName) throws OvsdbPluginException {
1484 throw new OvsdbPluginException("Not implemented Yet");
1488 public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
1489 String databaseName, String tableName, String fiqlQuery)
1490 throws OvsdbPluginException {
1491 throw new OvsdbPluginException("Not implemented Yet");
1495 public List<String> getTables(Node node, String databaseName) throws OvsdbPluginException {
1496 throw new OvsdbPluginException("Not implemented Yet");