summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBen Pfaff <blp@ovn.org>2017-12-28 13:21:11 -0800
committerBen Pfaff <blp@ovn.org>2018-03-24 12:04:52 -0700
commit53178986d7fc86bcfc2f297b547a97ee71a21bb7 (patch)
treebc01be74235a8c3e2cb80180f64c0ef61fac0ab3 /tests
parent10621d795331a3ddddb3e96086a9fda7ad156efc (diff)
downloadopenvswitch-53178986d7fc86bcfc2f297b547a97ee71a21bb7.tar.gz
ovsdb: Add support for online schema conversion.
With this change, "ovsdb-client convert" can be used to convert a database from one schema to another without taking the database offline. This can be useful to minimize downtime for a database during a software upgrade. Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Justin Pettit <jpettit@ovn.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/ovsdb-monitor.at4
-rw-r--r--tests/ovsdb-server.at263
-rw-r--r--tests/test-ovsdb.c14
3 files changed, 273 insertions, 8 deletions
diff --git a/tests/ovsdb-monitor.at b/tests/ovsdb-monitor.at
index 2434f43cb..917a5cc09 100644
--- a/tests/ovsdb-monitor.at
+++ b/tests/ovsdb-monitor.at
@@ -29,11 +29,11 @@ m4_define([OVSDB_CHECK_MONITOR],
on_exit 'kill `cat ovsdb-server.pid`'
AT_CAPTURE_FILE([ovsdb-client-log])
if test "$IS_WIN32" = "yes"; then
- AT_CHECK([ovsdb-client -vjsonrpc --pidfile --log-file="`pwd`"/ovsdb-client-log -d json monitor --format=csv unix:socket $4 $5 $8 > output 2>/dev/null &],
+ AT_CHECK([ovsdb-client -vjsonrpc --detach --pidfile --log-file="`pwd`"/ovsdb-client-log -d json monitor --format=csv unix:socket $4 $5 $8 > output],
[0], [ignore], [ignore])
sleep 1
else
- AT_CHECK([ovsdb-client -vjsonrpc --detach --no-chdir --pidfile --log-file="`pwd`"/ovsdb-client-log -d json monitor --format=csv unix:socket $4 $5 $8 > output],
+ AT_CHECK([ovsdb-client -vjsonrpc --detach --no-chdir --pidfile --log-file="`pwd`"/ovsdb-client-log -d json monitor --format=csv unix:socket $4 $5 $8 > output 2>/dev/null],
[0], [ignore], [ignore])
fi
on_exit 'kill `cat ovsdb-client.pid`'
diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
index 2786cbbf3..704382846 100644
--- a/tests/ovsdb-server.at
+++ b/tests/ovsdb-server.at
@@ -789,6 +789,269 @@ _uuid name number
OVSDB_SERVER_SHUTDOWN
AT_CLEANUP
+AT_SETUP([schema conversion online])
+AT_KEYWORDS([ovsdb server convert needs-conversion])
+on_exit 'kill `cat *.pid`'
+ordinal_schema > schema
+AT_DATA([new-schema],
+ [[{"name": "ordinals",
+ "tables": {
+ "ordinals": {
+ "columns": {
+ "number": {"type": "integer"}}}}}
+]])
+dnl Make sure that "ovsdb-tool create" works with a dangling symlink for
+dnl the database and the lockfile, creating the target of each symlink rather
+dnl than replacing the symlinks with regular files.
+mkdir dir
+if test "$IS_WIN32" = "no"; then
+ ln -s dir/db db
+ ln -s dir/.db.~lock~ .db.~lock~
+ AT_SKIP_IF([test ! -h db || test ! -h .db.~lock~])
+fi
+AT_CHECK([ovsdb-tool create db schema])
+dnl Put some data in the database.
+AT_CHECK(
+ [[for pair in 'zero 0' 'one 1' 'two 2' 'three 3' 'four 4' 'five 5'; do
+ set -- $pair
+ ovsdb-tool transact db '
+ ["ordinals",
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"name": "'$1'", "number": '$2'}},
+ {"op": "comment",
+ "comment": "add row for '"$pair"'"}]'
+ done | uuidfilt]], [0],
+[[[{"uuid":["uuid","<0>"]},{}]
+[{"uuid":["uuid","<1>"]},{}]
+[{"uuid":["uuid","<2>"]},{}]
+[{"uuid":["uuid","<3>"]},{}]
+[{"uuid":["uuid","<4>"]},{}]
+[{"uuid":["uuid","<5>"]},{}]
+]], [ignore])
+
+dnl Start the database server.
+AT_CHECK([ovsdb-server -vfile -vvlog:off --detach --no-chdir --pidfile --log-file --remote=punix:db.sock db], [0])
+AT_CAPTURE_FILE([ovsdb-server.log])
+
+dnl Try "needs-conversion".
+AT_CHECK([ovsdb-client needs-conversion schema], [0], [no
+])
+AT_CHECK([ovsdb-client needs-conversion new-schema], [0], [yes
+])
+
+dnl Start two monitors on the 'ordinals' db, one that is database
+dnl change aware and one that is not.
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=monitor-ordinals-aware.pid --log-file=monitor-ordinals-aware.log --db-change-aware --no-headings monitor ordinals ordinals number name > monitor-ordinals-aware.stdout 2> monitor-ordinals-aware.stderr])
+AT_CAPTURE_FILE([monitor-ordinals-aware.stdout])
+AT_CAPTURE_FILE([monitor-ordinals-aware.log])
+AT_CAPTURE_FILE([monitor-ordinals-aware.stderr])
+
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=monitor-ordinals-unaware.pid --log-file=monitor-ordinals-unaware.log --no-db-change-aware --no-headings monitor ordinals ordinals number name > monitor-ordinals-unaware.stdout 2> monitor-ordinals-unaware.stderr])
+AT_CAPTURE_FILE([monitor-ordinals-unaware.stdout])
+AT_CAPTURE_FILE([monitor-ordinals-unaware.log])
+AT_CAPTURE_FILE([monitor-ordinals-unaware.stderr])
+
+dnl Start two monitors on the '_Server' db, one that is database
+dnl change aware and one that is not.
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=monitor-server-aware.pid --log-file=monitor-server-aware.log --db-change-aware --no-headings monitor _Server Database name > monitor-server-aware.stdout 2> monitor-server-aware.stderr])
+AT_CAPTURE_FILE([monitor-server-aware.stdout])
+AT_CAPTURE_FILE([monitor-server-aware.log])
+AT_CAPTURE_FILE([monitor-server-aware.stderr])
+
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=monitor-server-unaware.pid --log-file=monitor-server-unaware.log --no-db-change-aware --no-headings monitor _Server Database name > monitor-server-unaware.stdout 2> monitor-server-unaware.stderr])
+AT_CAPTURE_FILE([monitor-server-unaware.stdout])
+AT_CAPTURE_FILE([monitor-server-unaware.log])
+AT_CAPTURE_FILE([monitor-server-unaware.stderr])
+
+dnl Start two long-running transactions (triggers) on the 'ordinals' db,
+dnl one that is database change aware and one that is not.
+ordinals_txn='[["ordinals",
+ {"op": "wait",
+ "table": "ordinals",
+ "where": [["name", "==", "seven"]],
+ "columns": ["name", "number"],
+ "rows": [],
+ "until": "!="}]]'
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=trigger-ordinals-aware.pid --log-file=trigger-ordinals-aware.log --db-change-aware transact "$ordinals_txn" > trigger-ordinals-aware.stdout 2> trigger-ordinals-aware.stderr])
+AT_CAPTURE_FILE([trigger-ordinals-aware.stdout])
+AT_CAPTURE_FILE([trigger-ordinals-aware.log])
+AT_CAPTURE_FILE([trigger-ordinals-aware.stderr])
+
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=trigger-ordinals-unaware.pid --log-file=trigger-ordinals-unaware.log --no-db-change-aware transact "$ordinals_txn" > trigger-ordinals-unaware.stdout 2> trigger-ordinals-unaware.stderr])
+AT_CAPTURE_FILE([trigger-ordinals-unaware.stdout])
+AT_CAPTURE_FILE([trigger-ordinals-unaware.log])
+AT_CAPTURE_FILE([trigger-ordinals-unaware.stderr])
+
+dnl Start two long-running transactions (triggers) on the _Server db,
+dnl one that is database change aware and one that is not.
+server_txn='[["_Server",
+ {"op": "wait",
+ "table": "Database",
+ "where": [["name", "==", "xyzzy"]],
+ "columns": ["name"],
+ "rows": [],
+ "until": "!="}]]'
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=trigger-server-aware.pid --log-file=trigger-server-aware.log --db-change-aware transact "$server_txn" > trigger-server-aware.stdout 2> trigger-server-aware.stderr])
+AT_CAPTURE_FILE([trigger-server-aware.stdout])
+AT_CAPTURE_FILE([trigger-server-aware.log])
+AT_CAPTURE_FILE([trigger-server-aware.stderr])
+
+AT_CHECK([ovsdb-client -vfile -vvlog:off --detach --pidfile=trigger-server-unaware.pid --log-file=trigger-server-unaware.log --no-db-change-aware transact "$server_txn" > trigger-server-unaware.stdout 2> trigger-server-unaware.stderr])
+AT_CAPTURE_FILE([trigger-server-unaware.stdout])
+AT_CAPTURE_FILE([trigger-server-unaware.log])
+AT_CAPTURE_FILE([trigger-server-unaware.stderr])
+
+dnl Dump out and check the actual database contents.
+AT_CHECK([ovsdb-client dump unix:db.sock ordinals], [0], [stdout])
+AT_CHECK([uuidfilt stdout], [0], [dnl
+ordinals table
+_uuid name number
+------------------------------------ ----- ------
+<0> five 5
+<1> four 4
+<2> one 1
+<3> three 3
+<4> two 2
+<5> zero 0
+])
+
+dnl Convert the database.
+AT_CHECK([ovsdb-client convert new-schema])
+
+dnl Try "needs-conversion".
+AT_CHECK([ovsdb-client needs-conversion schema], [0], [yes
+])
+AT_CHECK([ovsdb-client needs-conversion new-schema], [0], [no
+])
+
+dnl Verify that the "ordinals" monitors behaved as they should have.
+dnl Both should have exited, for different reasons.
+dnl The db-aware _Server monitor should still be running, but not the unaware
+dnl one.
+for x in unaware aware; do
+ OVS_WAIT_WHILE([test -e monitor-ordinals-$x.pid])
+ AT_CHECK([sort -k 3 monitor-ordinals-$x.stdout | uuidfilt], [0],
+[<0> initial 0 zero
+<1> initial 1 one
+<2> initial 2 two
+<3> initial 3 three
+<4> initial 4 four
+<5> initial 5 five
+])
+done
+AT_CHECK([sed 's/.*: //' monitor-ordinals-unaware.stderr], [0], [receive failed (End of file)
+])
+AT_CHECK([sed 's/.*: //' monitor-ordinals-aware.stderr], [0], [ordinals database was removed
+])
+
+dnl Verify that the _Server monitors behaved as they should have.
+dnl The db-aware monitor should still be running, but not the unaware one.
+for x in aware unaware; do
+ AT_CHECK([sort -k 3 monitor-server-$x.stdout | uuidfilt], [0],
+[<0> initial _Server
+<1> initial ordinals
+])
+done
+OVS_WAIT_WHILE([test -e monitor-server-unaware.pid])
+AT_CHECK([sed 's/.*: //' monitor-ordinals-unaware.stderr], [0], [receive failed (End of file)
+])
+AT_CHECK([test -e monitor-server-aware.pid])
+
+dnl Verify that the "ordinals" triggers behaved as they should have:
+dnl Both should have exited, for different reasons.
+for x in unaware aware; do
+ OVS_WAIT_WHILE([test -e trigger-ordinals-$x.pid])
+ AT_CHECK([cat trigger-ordinals-$x.stdout])
+done
+AT_CHECK([cat trigger-ordinals-unaware.stderr], [0], [ovsdb-client: transaction failed (End of file)
+])
+AT_CHECK([cat trigger-ordinals-aware.stderr], [0], [ovsdb-client: transaction returned error: {"error":"canceled"}
+])
+
+dnl Verify that the _Server triggers behaved as they should have:
+dnl The db-aware trigger should still be waiting, but not the unaware one.
+for x in aware unaware; do
+ AT_CHECK([cat trigger-server-$x.stdout])
+done
+OVS_WAIT_WHILE([test -e trigger-server-unaware.pid])
+AT_CHECK([sed 's/.*: //' trigger-ordinals-unaware.stderr], [0], [transaction failed (End of file)
+])
+AT_CHECK([test -e trigger-server-aware.pid])
+
+dnl We can't fully re-check the contents of the database log, because the
+dnl order of the records is not predictable, but there should only be 4 lines
+dnl in it now.
+AT_CAPTURE_FILE([db])
+AT_CHECK([test `wc -l < db` -eq 4])
+dnl And check that the dumped data is the same except for the removed column:
+AT_CHECK([ovsdb-client dump unix:db.sock ordinals | uuidfilt], [0], [dnl
+ordinals table
+_uuid number
+------------------------------------ ------
+<0> 0
+<1> 1
+<2> 2
+<3> 3
+<4> 4
+<5> 5
+])
+dnl Now check that the converted database is still online and can be modified,
+dnl then check that the database log has one more record and that the data
+dnl is as expected.
+AT_CHECK(
+ [[ovsdb-client transact '
+ ["ordinals",
+ {"op": "insert",
+ "table": "ordinals",
+ "row": {"number": 6}},
+ {"op": "comment",
+ "comment": "add row for 6"}]' | uuidfilt]], [0],
+ [[[{"uuid":["uuid","<0>"]},{}]
+]])
+AT_CHECK([test `wc -l < db` -eq 6])
+AT_CHECK([ovsdb-client dump unix:db.sock ordinals | uuidfilt], [0], [dnl
+ordinals table
+_uuid number
+------------------------------------ ------
+<0> 0
+<1> 1
+<2> 2
+<3> 3
+<4> 4
+<5> 5
+<6> 6
+])
+dnl Now kill and restart the database server to ensure that the data is
+dnl correct on disk as well as in memory.
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CHECK([[ovsdb-server -vfile -vvlog:off --detach --no-chdir --pidfile --log-file --remote=punix:db.sock db]],
+ [0])
+AT_CHECK([ovsdb-client dump unix:db.sock ordinals | uuidfilt], [0], [dnl
+ordinals table
+_uuid number
+------------------------------------ ------
+<0> 0
+<1> 1
+<2> 2
+<3> 3
+<4> 4
+<5> 5
+<6> 6
+])
+
+dnl Make sure that "db" is still a symlink to dir/db instead of getting
+dnl replaced by a regular file, ditto for .db.~lock~.
+if test "$IS_WIN32" = "no"; then
+ AT_CHECK([test -h db])
+ AT_CHECK([test -h .db.~lock~])
+ AT_CHECK([test -f dir/db])
+ AT_CHECK([test -f dir/.db.~lock~])
+fi
+
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+AT_CLEANUP
+
AT_SETUP([ovsdb-server combines updates on backlogged connections])
on_exit 'kill `cat *.pid`'
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index c0c5a4df5..8502ad73f 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -1522,14 +1522,14 @@ struct test_trigger {
static void
do_trigger_dump(struct test_trigger *t, long long int now, const char *title)
{
- struct json *result;
+ struct jsonrpc_msg *reply;
char *s;
- result = ovsdb_trigger_steal_result(&t->trigger);
- s = json_to_string(result, JSSF_SORT);
+ reply = ovsdb_trigger_steal_reply(&t->trigger);
+ s = json_to_string(reply->result, JSSF_SORT);
printf("t=%lld: trigger %d (%s): %s\n", now, t->number, title, s);
free(s);
- json_destroy(result);
+ jsonrpc_msg_destroy(reply);
ovsdb_trigger_destroy(&t->trigger);
free(t);
}
@@ -1569,8 +1569,10 @@ do_trigger(struct ovs_cmdl_context *ctx)
json_destroy(params);
} else {
struct test_trigger *t = xmalloc(sizeof *t);
- ovsdb_trigger_init(&session, db, &t->trigger, params, now, false,
- NULL, NULL);
+ ovsdb_trigger_init(&session, db, &t->trigger,
+ jsonrpc_create_request("transact", params,
+ NULL),
+ now, false, NULL, NULL);
t->number = number++;
if (ovsdb_trigger_is_complete(&t->trigger)) {
do_trigger_dump(t, now, "immediate");