OPT_BOOTSTRAP_CA_CERT,
OPT_PEER_CA_CERT,
OPT_SYNC_FROM,
+ OPT_SYNC_EXCLUDE,
VLOG_OPTION_ENUMS,
DAEMON_OPTION_ENUMS
};
{"certificate", required_argument, NULL, 'c'},
{"ca-cert", required_argument, NULL, 'C'},
{"sync-from", required_argument, NULL, OPT_SYNC_FROM},
+ {"sync-exclude-tables", required_argument, NULL, OPT_SYNC_EXCLUDE},
{NULL, 0, NULL, 0},
};
char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
connect_to_remote_server = true;
break;
+ case OPT_SYNC_EXCLUDE:
+ set_tables_blacklist(optarg);
+ break;
+
case '?':
exit(EXIT_FAILURE);
static char *remote_ovsdb_server;
static struct jsonrpc *rpc;
static struct sset monitored_tables = SSET_INITIALIZER(&monitored_tables);
+static struct sset tables_blacklist = SSET_INITIALIZER(&tables_blacklist);
static bool reset_dbs = true;
+void replication_init(void);
static struct jsonrpc *open_jsonrpc(const char *server);
static struct ovsdb_error *check_jsonrpc_error(int error,
struct jsonrpc_msg **reply_);
struct ovsdb_table *table,
struct json *new);
\f
+void
+replication_init(void)
+{
+ sset_init(&monitored_tables);
+ sset_init(&tables_blacklist);
+ reset_dbs = true;
+}
+
void
replication_run(struct shash *all_dbs)
{
remote_ovsdb_server = remote_server ? xstrdup(remote_server) : NULL;
}
+void
+set_tables_blacklist(const char *blacklist)
+{
+ char *save_ptr = NULL;
+ char *blacklist_item;
+
+ replication_init();
+
+ if (blacklist) {
+ char *t_blacklist = xstrdup(blacklist);
+ for (blacklist_item = strtok_r(t_blacklist, ",", &save_ptr);
+ blacklist_item != NULL;
+ blacklist_item = strtok_r(NULL, ",", &save_ptr)) {
+ sset_add(&tables_blacklist, blacklist_item);
+ }
+ free(t_blacklist);
+ }
+}
+
void
disconnect_remote_server(void)
{
jsonrpc_close(rpc);
sset_destroy(&monitored_tables);
+ sset_destroy(&tables_blacklist);
if (remote_ovsdb_server) {
free(remote_ovsdb_server);
struct ovsdb_table *table = table_node->data;
struct ovsdb_row *row;
- HMAP_FOR_EACH (row, hmap_node, &table->rows) {
- ovsdb_txn_row_delete(txn, row);
+ /* Do not reset if table is blacklisted. */
+ char *blacklist_item = xasprintf(
+ "%s%s%s", db->schema->name, ":", table_node->name);
+ if (!sset_contains(&tables_blacklist, blacklist_item)) {
+ HMAP_FOR_EACH (row, hmap_node, &table->rows) {
+ ovsdb_txn_row_delete(txn, row);
+ }
}
+ free(blacklist_item);
}
}
for (int j = 0; j < n; j++) {
struct ovsdb_table_schema *table = nodes[j]->data;
- add_monitored_table(table, monitor_request);
+
+ /* Check if table is not blacklisted. */
+ char *blacklist_item = xasprintf(
+ "%s%s%s", db_name, ":", table->name);
+ if (!sset_contains(&tables_blacklist, blacklist_item)) {
+ add_monitored_table(table, monitor_request);
+ }
+ free(blacklist_item);
}
free(nodes);
void replication_run(struct shash *dbs);
void set_remote_ovsdb_server(const char *remote_server);
+void set_tables_blacklist(const char *blacklist);
void disconnect_remote_server(void);
const struct db *find_db(const struct shash *all_dbs, const char *db_name);
void replication_usage(void);
tests/ovsdb-execution.at \
tests/ovsdb-trigger.at \
tests/ovsdb-tool.at \
+ tests/ovsdb-replication.at \
tests/ovsdb-server.at \
tests/ovsdb-monitor.at \
tests/ovsdb-idl.at \
--- /dev/null
+AT_BANNER([OVSDB -- replication])
+
+m4_divert_push([PREPARE_TESTS])
+[
+replication_schema () {
+ cat <<'EOF'
+ {"name": "mydb",
+ "tables": {
+ "a": {
+ "columns": {
+ "number": {"type": "integer"},
+ "name": {"type": "string"}},
+ "indexes": [["number"]]},
+ "b": {
+ "columns": {
+ "number": {"type": "integer"},
+ "name": {"type": "string"}},
+ "indexes": [["number"]]}}
+ }
+EOF
+}
+]
+m4_divert_pop([PREPARE_TESTS])
+
+m4_define([REPLICATION_EXAMPLES], [
+
+OVSDB_CHECK_REPLICATION([insert monitored table, insert excluded table],
+ [replication_schema],
+ [[[["mydb",
+ {"op": "insert",
+ "table": "a",
+ "row": {"number": 0, "name": "zero"}}]]],
+ [[["mydb",
+ {"op": "insert",
+ "table": "b",
+ "row": {"number": 1, "name": "one"}}]]]],
+ [[7,9c7,8
+< _uuid name number
+< ------------------------------------ ---- ------
+< <0> one 1 @&t@
+---
+> _uuid name number
+> ----- ---- ------]]
+)
+
+OVSDB_CHECK_REPLICATION([insert monitored table, update excluded table],
+ [replication_schema],
+ [[[["mydb",
+ {"op": "insert",
+ "table": "a",
+ "row": {"number": 0, "name": "zero"}}]]],
+ [[["mydb",
+ {"op": "insert",
+ "table": "b",
+ "row": {"number": 1, "name": "one"}}]]],
+ [[["mydb",
+ {"op": "update",
+ "table": "b",
+ "where":[["name","==","one"]],
+ "row": {"number": 2, "name": "two"}}]]]],
+ [[7,9c7,8
+< _uuid name number
+< ------------------------------------ ---- ------
+< <0> two 2 @&t@
+---
+> _uuid name number
+> ----- ---- ------]]
+)
+
+OVSDB_CHECK_REPLICATION([update monitored table, insert excluded table],
+ [replication_schema],
+ [[[["mydb",
+ {"op": "insert",
+ "table": "a",
+ "row": {"number": 0, "name": "zero"}}]]],
+ [[["mydb",
+ {"op": "update",
+ "table": "a",
+ "where":[["name","==","zero"]],
+ "row": {"number": 1, "name": "one"}}]]],
+ [[["mydb",
+ {"op": "insert",
+ "table": "b",
+ "row": {"number": 2, "name": "two"}}]]]],
+ [[7,9c7,8
+< _uuid name number
+< ------------------------------------ ---- ------
+< <0> two 2 @&t@
+---
+> _uuid name number
+> ----- ---- ------]]
+)
+
+OVSDB_CHECK_REPLICATION([update monitored table, update excluded table],
+ [replication_schema],
+ [[[["mydb",
+ {"op": "insert",
+ "table": "a",
+ "row": {"number": 0, "name": "zero"}}]]],
+ [[["mydb",
+ {"op": "update",
+ "table": "a",
+ "where":[["name","==","zero"]],
+ "row": {"number": 1, "name": "one"}}]]],
+ [[["mydb",
+ {"op": "insert",
+ "table": "b",
+ "row": {"number": 2, "name": "two"}}]]],
+ [[["mydb",
+ {"op": "update",
+ "table": "b",
+ "where":[["name","==","two"]],
+ "row": {"number": 3, "name": "three"}}]]]],
+ [[7,9c7,8
+< _uuid name number
+< ------------------------------------ ----- ------
+< <0> three 3 @&t@
+---
+> _uuid name number
+> ----- ---- ------]]
+)
+
+OVSDB_CHECK_REPLICATION([delete monitored table, insert excluded table],
+ [replication_schema],
+ [[[["mydb",
+ {"op": "insert",
+ "table": "a",
+ "row": {"number": 0, "name": "zero"}}]]],
+ [[["mydb",
+ {"op": "delete",
+ "table": "a",
+ "where":[["name","==","zero"]]}]]],
+ [[["mydb",
+ {"op": "insert",
+ "table": "b",
+ "row": {"number": 1, "name": "one"}}]]]],
+ [[6,8c6,7
+< _uuid name number
+< ------------------------------------ ---- ------
+< <0> one 1 @&t@
+---
+> _uuid name number
+> ----- ---- ------]]
+)
+
+OVSDB_CHECK_REPLICATION([delete monitored table, update excluded table],
+ [replication_schema],
+ [[[["mydb",
+ {"op": "insert",
+ "table": "a",
+ "row": {"number": 0, "name": "zero"}}]]],
+ [[["mydb",
+ {"op": "delete",
+ "table": "a",
+ "where":[["name","==","zero"]]}]]],
+ [[["mydb",
+ {"op": "insert",
+ "table": "b",
+ "row": {"number": 1, "name": "one"}}]]],
+ [[["mydb",
+ {"op": "update",
+ "table": "b",
+ "where":[["name","==","one"]],
+ "row": {"number": 2, "name": "two"}}]]]],
+ [[6,8c6,7
+< _uuid name number
+< ------------------------------------ ---- ------
+< <0> two 2 @&t@
+---
+> _uuid name number
+> ----- ---- ------]]
+)
+
+])
AT_CLEANUP])
EXECUTION_EXAMPLES
+
+AT_BANNER([OVSDB -- ovsdb-server replication table-exclusion (TCP IPv4 sockets)])
+
+# OVSDB_CHECK_REPLICATION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates two databases with the given SCHEMA, and starts an
+# ovsdb-server on each database.
+# Runs each of the TRANSACTIONS (which should be a quoted list of
+# quoted strings) against one of the servers with ovsdb-client one at a
+# time. The server replicates its database to the other ovsdb-server.
+#
+# Checks that the difference between the dump of the databases is
+# OUTPUT, but UUIDs in the output are replaced by markers of the form
+# <N> where N is a number. The first unique UUID is replaced by <0>,
+# the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_REPLICATION],
+ [AT_SETUP([$1])
+ AT_KEYWORDS([ovsdb server tcp replication table-exclusion])
+ $2 > schema
+ AT_CHECK([ovsdb-tool create db1 schema], [0], [stdout], [ignore])
+ AT_CHECK([ovsdb-tool create db2 schema], [0], [stdout], [ignore])
+
+ AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server1.log --pidfile="`pwd`"/pid --remote=ptcp:0:127.0.0.1 --unixctl="`pwd`"/unixctl db1], [0], [ignore], [ignore])
+ PARSE_LISTENING_PORT([ovsdb-server1.log], [TCP_PORT1])
+
+ AT_CHECK([ovsdb-server --detach --no-chdir --log-file=ovsdb-server2.log --pidfile="`pwd`"/pid2 --remote=ptcp:0:127.0.0.1 --unixctl="`pwd`"/unixctl2 --sync-from=tcp:127.0.0.1:$TCP_PORT1 --sync-exclude-tables=mydb:b db2], [0], [ignore], [ignore])
+ PARSE_LISTENING_PORT([ovsdb-server2.log], [TCP_PORT2])
+
+ m4_foreach([txn], [$3],
+ [AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT1 'txn'; sleep 2], [0], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+ ])
+
+ AT_CHECK([ovsdb-client dump tcp:127.0.0.1:$TCP_PORT1], [0], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+ cat stdout >> dump1
+ AT_CHECK([ovsdb-client dump tcp:127.0.0.1:$TCP_PORT2], [0], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+ cat stdout >> dump2
+
+ AT_CHECK([diff dump1 dump2], [1], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+ cat stdout >> output
+
+ AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+ [test ! -e pid || kill `cat pid`; test ! -e pid2 || kill `cat pid2`])
+
+ OVSDB_SERVER_SHUTDOWN
+ OVSDB_SERVER_SHUTDOWN2
+ AT_CLEANUP])
+
+REPLICATION_EXAMPLES
m4_include([tests/ovsdb-execution.at])
m4_include([tests/ovsdb-trigger.at])
m4_include([tests/ovsdb-tool.at])
+m4_include([tests/ovsdb-replication.at])
m4_include([tests/ovsdb-server.at])
m4_include([tests/ovsdb-monitor.at])
m4_include([tests/ovsdb-idl.at])