From: Mario Cabrera Date: Tue, 29 Mar 2016 17:01:00 +0000 (-0600) Subject: ovsdb: Add table exclusion functionality to OVSDB replication X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=7a9d65d294c903ef77191cd143a467a5a1e8d3ac;p=ovs.git ovsdb: Add table exclusion functionality to OVSDB replication A blacklist of tables that will be excluded from replication can be specified by the following option: --sync-exclude-tables=db:table[,db:table]… Where 'table' corresponds to a table name, and 'db' corresponds to the database name where the table resides. Signed-off-by: Mario Cabrera Signed-off-by: Ben Pfaff --- diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 650c164ac..1b9de19c9 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -1266,6 +1266,7 @@ parse_options(int *argcp, char **argvp[], OPT_BOOTSTRAP_CA_CERT, OPT_PEER_CA_CERT, OPT_SYNC_FROM, + OPT_SYNC_EXCLUDE, VLOG_OPTION_ENUMS, DAEMON_OPTION_ENUMS }; @@ -1285,6 +1286,7 @@ parse_options(int *argcp, char **argvp[], {"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); @@ -1350,6 +1352,10 @@ parse_options(int *argcp, char **argvp[], connect_to_remote_server = true; break; + case OPT_SYNC_EXCLUDE: + set_tables_blacklist(optarg); + break; + case '?': exit(EXIT_FAILURE); diff --git a/ovsdb/replication.c b/ovsdb/replication.c index 669f4758c..1fa0f253a 100644 --- a/ovsdb/replication.c +++ b/ovsdb/replication.c @@ -35,8 +35,10 @@ 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_); @@ -72,6 +74,14 @@ static struct ovsdb_error *execute_update(struct ovsdb_txn *txn, struct ovsdb_table *table, struct json *new); +void +replication_init(void) +{ + sset_init(&monitored_tables); + sset_init(&tables_blacklist); + reset_dbs = true; +} + void replication_run(struct shash *all_dbs) { @@ -108,11 +118,31 @@ set_remote_ovsdb_server(const char *remote_server) 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); @@ -160,9 +190,15 @@ reset_database(struct ovsdb *db, struct ovsdb_txn *txn) 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); } } @@ -293,7 +329,14 @@ send_monitor_requests(struct shash *all_dbs) 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); diff --git a/ovsdb/replication.h b/ovsdb/replication.h index f9b7d6323..74acdbaa5 100644 --- a/ovsdb/replication.h +++ b/ovsdb/replication.h @@ -32,6 +32,7 @@ struct db { 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); diff --git a/tests/automake.mk b/tests/automake.mk index 777f6db74..8b24221ae 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -75,6 +75,7 @@ TESTSUITE_AT = \ 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 \ diff --git a/tests/ovsdb-replication.at b/tests/ovsdb-replication.at new file mode 100644 index 000000000..bd96ae78d --- /dev/null +++ b/tests/ovsdb-replication.at @@ -0,0 +1,174 @@ +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 +> ----- ---- ------]] +) + +]) diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 30140462b..299e53774 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -1023,3 +1023,59 @@ m4_define([OVSDB_CHECK_EXECUTION], 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 +# 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 diff --git a/tests/ovsdb.at b/tests/ovsdb.at index 500071334..b20ab9e4b 100644 --- a/tests/ovsdb.at +++ b/tests/ovsdb.at @@ -143,6 +143,7 @@ m4_include([tests/ovsdb-transaction.at]) 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])