On Sat, Jan 16, 2016 at 12:16 AM, Liran Schour <lir...@il.ibm.com> wrote:
> Add monitor_cond method to ovsdb-client. Add unit tests. > See ovsdb-client(1) man page for details. > > Signed-off-by: Liran Schour <lir...@il.ibm.com> > --- > NEWS | 3 +- > ovsdb/ovsdb-client.1.in | 37 +++++----- > ovsdb/ovsdb-client.c | 74 ++++++++++++++------ > tests/ovsdb-monitor.at | 178 > ++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 252 insertions(+), 40 deletions(-) > > diff --git a/NEWS b/NEWS > index 4433329..21a6f63 100644 > --- a/NEWS > +++ b/NEWS > @@ -1,7 +1,8 @@ > Post-v2.5.0 > --------------------- > - ovsdb-server: > - * New "monitor2" and "update2" extensions to RFC 7047. > + * New "monitor_cond" "monitor_cond_chane" and "update2" extensions to > s/monitor_cond_chane/monitor_cond_update/ + RFC 7047. > - OpenFlow: > * OpenFlow 1.1+ OFPT_QUEUE_GET_CONFIG_REQUEST now supports OFPP_ANY. > > diff --git a/ovsdb/ovsdb-client.1.in b/ovsdb/ovsdb-client.1.in > index 5d99f59..1d58db8 100644 > --- a/ovsdb/ovsdb-client.1.in > +++ b/ovsdb/ovsdb-client.1.in > @@ -33,10 +33,8 @@ ovsdb\-client \- command-line interface to > \fBovsdb-server\fR(1) > .br > \fBovsdb\-client \fR[\fIoptions\fR] \fBmonitor\fI \fR[\fIserver\fR] > \fR[\fIdatabase\fR] \fBALL\fR > .br > -\fBovsdb\-client \fR[\fIoptions\fR] \fBmonitor2\fI \fR[\fIserver\fR] > \fR[\fIdatabase\fR] \fItable\fR > -[\fIcolumn\fR[\fB,\fIcolumn\fR]...]... > -.br > -\fBovsdb\-client \fR[\fIoptions\fR] \fBmonitor2\fI \fR[\fIserver\fR] > \fR[\fIdatabase\fR] \fBALL\fR > +\fBovsdb\-client \fR[\fIoptions\fR] \fBmonitor-cond\fI \fR[\fIserver\fR] > \fR[\fIdatabase\fR] \fItable\fR > +\fIconditions [\fIcolumn\fR[\fB,\fIcolumn\fR]...]... > .br > \fBovsdb\-client help\fR > .IP "Output formatting options:" > @@ -113,12 +111,12 @@ specified, only that table is retrieved. If at > least one \fIcolumn\fR > is specified, only those columns are retrieved. > . > .IP "\fBmonitor\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fItable\fR > [\fIcolumn\fR[\fB,\fIcolumn\fR]...]..." > -.IQ "\fBmonitor2\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fItable\fR > [\fIcolumn\fR[\fB,\fIcolumn\fR]...]..." > -Connects to \fIserver\fR and monitors the contents of \fItable\fR in > -\fIdatabase\fR. By default, the initial contents of \fItable\fR are > -printed, followed by each change as it occurs. If at least one > -\fIcolumn\fR is specified, only those columns are monitored. The > -following \fIcolumn\fR names have special meanings: > +.IQ "\fBmonitor-cond\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fItable\fR > \fIconditions\fR [\fIcolumn\fR[\fB,\fIcolumn\fR]...]..." > Would it be more consistent to have ovsdb-client monitor-cond [server] [database] conditions table [column[.... This should also make sharing command line parsing between monitor and monitor-cond less cumbersome. +Connects to \fIserver\fR and monitors the contents of rows that match > conditions in > +\fItable\fR in \fIdatabase\fR. By default, the initial contents of > \fItable\fR are > +printed, followed by each change as it occurs. If conditions is missing > or emtpy, > +all rows will be monitored. If at least one \fIcolumn\fR is specified, > only those > +columns are monitored. The following \fIcolumn\fR names have special > meanings: > .RS > .IP "\fB!initial\fR" > Do not print the initial contents of the specified columns. > @@ -136,16 +134,18 @@ each group. Whether multiple groups or only a > single group is > specified, any given column may only be mentioned once on the command > line. > .IP > -If \fB\-\-detach\fR is used with \fBmonitor\fR or \fBmointor2\fR, then > +\fBconditions\fR is a JSON array of <condition> as defined in RFC 7047 5.1 > +with the following change: A condition can be either a 3-element JSON > array > +as deescribed in the RFC or a boolean value.. > +.IP > +If \fB\-\-detach\fR is used with \fBmonitor\fR or \fBmointor-cond\fR, then > \fBovsdb\-client\fR detaches after it has successfully received and > printed the initial contents of \fItable\fR. > .IP > The \fBmonitor\fR command uses RFC 7047 "monitor" method to open a monitor > -session with the server. The \fBmonitor2\fR command uses RFC 7047 > -extension "monitor2" method. See \fBovsdb\-server\fR(1) for details. > -. > +session with the server. The \fBmonitor-cond\fR command uses RFC 7047 > +extension "monitor_cond" method. See \fBovsdb\-server\fR(1) for details. > .IP "\fBmonitor\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fBALL\fR" > -.IQ "\fBmonitor2\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fBALL\fR" > Connects to \fIserver\fR and monitors the contents of all tables in > \fIdatabase\fR. Prints initial values and all kinds of changes to all > columns in the database. The \fB\-\-detach\fR option causes > @@ -153,8 +153,7 @@ columns in the database. The \fB\-\-detach\fR option > causes > prints the initial database contents. > .IP > The \fBmonitor\fR command uses RFC 7047 "monitor" method to open a monitor > -session with the server. The \fBmonitor2\fR command uses RFC 7047 > -extension "monitor2" method. See \fBovsdb\-server\fR(1) for details. > +session with the server. > . > .SH OPTIONS > .SS "Output Formatting Options" > @@ -165,13 +164,13 @@ The following options controlling output formatting: > .so lib/table.man > . > .IP "\fB\-\-timestamp\fR" > -For the \fBmonitor\fR and \fBmonitor2\fR commands, add a timestamp to each > +For the \fBmonitor\fR and \fBmonitor-cond\fR commands, add a timestamp to > each > table update. Most output formats add the timestamp on a line of its own > just above the table. The JSON output format puts the timestamp in a > member of the top-level JSON object named \fBtime\fR. > . > .SS "Daemon Options" > -The daemon options apply only to the \fBmonitor\fR and \fBmonitor2\fR > commands. > +The daemon options apply only to the \fBmonitor\fR and \fBmonitor-cond\fR > commands. > With any other command, they have no effect. > .ds DD > .so lib/daemon.man > diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c > index 06155ec..e48677e 100644 > --- a/ovsdb/ovsdb-client.c > +++ b/ovsdb/ovsdb-client.c > @@ -38,6 +38,7 @@ > #include "ovsdb.h" > #include "ovsdb-data.h" > #include "ovsdb-error.h" > +#include "condition.h" > #include "poll-loop.h" > #include "sort.h" > #include "svec.h" > @@ -261,7 +262,10 @@ usage(void) > " in DATBASE on SERVER.\n" > "\n monitor2 [SERVER] [DATABASE] ALL\n" > " same usage as monitor, but uses \"monitor2\" method over" > - " the wire." > + " the wire.\n" > + "\n monitor-cond [SERVER] [DATABASE] TABLE CONDITION > [COLUMN,..]\n" > + " conditionally monitor contents of COLUMNS in TABLE in\n" > + " DATABASE on SERVER.\n" > "\n dump [SERVER] [DATABASE]\n" > " dump contents of DATABASE on SERVER to stdout\n" > "\nThe default SERVER is unix:%s/db.sock.\n" > @@ -734,14 +738,13 @@ add_column(const char *server, const struct > ovsdb_column *column, > static struct json * > parse_monitor_columns(char *arg, const char *server, const char *database, > const struct ovsdb_table_schema *table, > - struct ovsdb_column_set *columns) > + struct ovsdb_column_set *columns, struct json *mr) > { > bool initial, insert, delete, modify; > - struct json *mr, *columns_json; > + struct json *columns_json; > char *save_ptr = NULL; > char *token; > > - mr = json_object_create(); > columns_json = json_array_create_empty(); > json_object_put(mr, "columns", columns_json); > > @@ -841,12 +844,15 @@ static void > add_monitored_table(int argc, char *argv[], > const char *server, const char *database, > struct ovsdb_table_schema *table, > + const bool conditional, > struct json *monitor_requests, > struct monitored_table **mts, > size_t *n_mts, size_t *allocated_mts) > See comments above, It may be nicer to just pass in the 'mr' pointer, after poping the conditions from argc/argv. > { > - struct json *monitor_request_array; > + struct json *monitor_request_array, *condition; > struct monitored_table *mt; > + struct json *mr = json_object_create();; > + char *columns = NULL; > > if (*n_mts >= *allocated_mts) { > *mts = x2nrealloc(*mts, allocated_mts, sizeof **mts); > @@ -856,23 +862,38 @@ add_monitored_table(int argc, char *argv[], > ovsdb_column_set_init(&mt->columns); > > monitor_request_array = json_array_create_empty(); > - if (argc > 1) { > - int i; > > - for (i = 1; i < argc; i++) { > - json_array_add( > - monitor_request_array, > - parse_monitor_columns(argv[i], server, database, table, > - &mt->columns)); > + if (!conditional) { > + if (argc > 1) { > + columns = argv[1]; > } > } else { > + struct ovsdb_condition cnd; > + > + condition = parse_json(argv[1]); > + check_ovsdb_error(ovsdb_condition_from_json(table, condition, > + NULL, &cnd)); > + ovsdb_condition_destroy(&cnd); > + > + json_object_put(mr, "where", condition); > + > + if(argc > 2) { > + columns = argv[2]; > + } > + } > + > + if (columns) { > + json_array_add(monitor_request_array, > + parse_monitor_columns(columns, server, database, > table, > + &mt->columns, mr)); > + } else { > /* Allocate a writable empty string since parse_monitor_columns() > * is going to strtok() it and that's risky with literal "". */ > char empty[] = ""; > json_array_add( > monitor_request_array, > parse_monitor_columns(empty, server, database, > - table, &mt->columns)); > + table, &mt->columns, mr)); > } > > json_object_put(monitor_requests, table->name, monitor_request_array); > @@ -893,7 +914,7 @@ destroy_monitored_table(struct monitored_table *mts, > size_t n) > > static void > do_monitor__(struct jsonrpc *rpc, const char *database, > - enum ovsdb_monitor_version version, > + enum ovsdb_monitor_version version, const bool conditional, > Do we need both version and conditional ? > int argc, char *argv[]) > { > const char *server = jsonrpc_get_name(rpc); > @@ -945,7 +966,7 @@ do_monitor__(struct jsonrpc *rpc, const char *database, > server, database, table_name); > } > > - add_monitored_table(argc, argv, server, database, table, > + add_monitored_table(argc, argv, server, database, table, > conditional, > monitor_requests, &mts, &n_mts, > &allocated_mts); > } else { > size_t n = shash_count(&schema->tables); > @@ -956,7 +977,7 @@ do_monitor__(struct jsonrpc *rpc, const char *database, > struct ovsdb_table_schema *table = nodes[i]->data; > > add_monitored_table(argc, argv, server, database, table, > - monitor_requests, > + conditional, monitor_requests, > &mts, &n_mts, &allocated_mts); > } > free(nodes); > @@ -964,8 +985,13 @@ do_monitor__(struct jsonrpc *rpc, const char > *database, > > monitor = json_array_create_3(json_string_create(database), > json_null_create(), monitor_requests); > - const char *method = version == OVSDB_MONITOR_V2 ? "monitor2" > - : "monitor"; > + const char *method; > + if (!conditional) { > + method = version == OVSDB_MONITOR_V2 ? "monitor2" > + : "monitor"; > + } else { > + method = "monitor_cond"; > + } > > request = jsonrpc_create_request(method, monitor, NULL); > request_id = json_clone(request->id); > @@ -1048,14 +1074,21 @@ static void > do_monitor(struct jsonrpc *rpc, const char *database, > int argc, char *argv[]) > { > - do_monitor__(rpc, database, OVSDB_MONITOR_V1, argc, argv); > + do_monitor__(rpc, database, OVSDB_MONITOR_V1, false, argc, argv); > } > > static void > do_monitor2(struct jsonrpc *rpc, const char *database, > int argc, char *argv[]) > { > - do_monitor__(rpc, database, OVSDB_MONITOR_V2, argc, argv); > + do_monitor__(rpc, database, OVSDB_MONITOR_V2, false, argc, argv); > +} > + > +static void > +do_monitor_cond(struct jsonrpc *rpc, const char *database, > + int argc, char *argv[]) > +{ > + do_monitor__(rpc, database, OVSDB_MONITOR_V2, true, argc, argv); > } > > struct dump_table_aux { > @@ -1329,6 +1362,7 @@ static const struct ovsdb_client_command > all_commands[] = { > { "transact", NEED_RPC, 1, 1, do_transact }, > { "monitor", NEED_DATABASE, 1, INT_MAX, do_monitor }, > { "monitor2", NEED_DATABASE, 1, INT_MAX, do_monitor2 }, > + { "monitor-cond", NEED_DATABASE, 2, 3, do_monitor_cond }, > { "dump", NEED_DATABASE, 0, INT_MAX, do_dump }, > { "help", NEED_NONE, 0, INT_MAX, do_help }, > > diff --git a/tests/ovsdb-monitor.at b/tests/ovsdb-monitor.at > index 0dbf5b0..9646a91 100644 > --- a/tests/ovsdb-monitor.at > +++ b/tests/ovsdb-monitor.at > @@ -44,6 +44,50 @@ m4_define([OVSDB_CHECK_MONITOR], > AT_CHECK([${PERL} $srcdir/ovsdb-monitor-sort.pl < output | ${PERL} > $srcdir/uuidfilt.pl], [0], [$7], [ignore]) > AT_CLEANUP]) > > +# OVSDB_CHECK_MONITOR_COND(TITLE, SCHEMA, [PRE-MONITOR-TXN], DB, TABLE, > +# TRANSACTIONS, OUTPUT, CONDITIONS, [COLUMNS], > [KEYWORDS]) > +# > +# Creates a database with the given SCHEMA, starts an ovsdb-server on > +# that database, and runs each of the TRANSACTIONS (which should be a > +# quoted list of quoted strings) against it with ovsdb-client one at a > +# time. COLUMNS, if specified, is passed to ovsdb-client as the set > +# of columns and operations to select. > +# > +# Checks that the overall output 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_MONITOR_COND], > + [AT_SETUP([$1]) > + AT_KEYWORDS([ovsdb server monitor monitor-cond positive $10]) > + $2 > schema > + AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore]) > + m4_foreach([txn], [$3], > + [AT_CHECK([ovsdb-tool transact db 'txn'], [0], [ignore], [ignore])]) > + AT_CAPTURE_FILE([ovsdb-server-log]) > + AT_CHECK([ovsdb-server --detach --no-chdir > --pidfile="`pwd`"/server-pid --remote=punix:socket > --unixctl="`pwd`"/unixctl --log-file="`pwd`"/ovsdb-server-log db >/dev/null > 2>&1], > + [0], [], []) > + if test "$IS_WIN32" = "yes"; then > + AT_CHECK([ovsdb-client -vjsonrpc --pidfile="`pwd`"/client-pid -d > json monitor-cond --format=csv unix:socket $4 $5 '[$8]' $9 > output &], > + [0], [ignore], [ignore], [kill `cat server-pid`]) > + sleep 1 > + else > + AT_CHECK([ ovsdb-client -vjsonrpc --detach --no-chdir > --pidfile="`pwd`"/client-pid -d json monitor-cond --format=csv unix:socket > $4 $5 '[$8]' $9 > output], > + [0], [ignore], [ignore], [kill `cat server-pid`]) > + fi > + m4_foreach([txn], [$6], > + [AT_CHECK([ovsdb-client transact unix:socket 'txn'], [0], > + [ignore], [ignore], [kill `cat server-pid > client-pid`])]) > + AT_CHECK([ovsdb-client transact unix:socket '[["$4"]]'], [0], > + [ignore], [ignore], [kill `cat server-pid client-pid`]) > + AT_CHECK([ovs-appctl -t "`pwd`"/unixctl -e exit], [0], [ignore], > [ignore]) > + OVS_WAIT_UNTIL([test ! -e server-pid && test ! -e client-pid]) > + AT_CHECK([${PERL} $srcdir/ovsdb-monitor-sort.pl < output | ${PERL} > $srcdir/uuidfilt.pl], [0], [$7], [ignore]) > + AT_CLEANUP]) > + > OVSDB_CHECK_MONITOR([monitor insert into empty table], > [ordinal_schema], > [], > @@ -322,3 +366,137 @@ OVSDB_CHECK_MONITOR([monitor modify only], > <0>,old,"""five""",,"[""uuid"",""<1>""]" > ,new,"""FIVE""",5,"[""uuid"",""<2>""]" > ]], [!initial,!insert,!delete]) > + > +AT_BANNER([ovsdb -- ovsdb-monitor-cond conditional monitor only some > operations]) > + > +OVSDB_CHECK_MONITOR_COND([monitor-cond empty condition], > + [ordinal_schema], > + [[[["ordinals", > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 0, "name": "zero"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 1, "name": "one"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 2, "name": "two"}}]]]], > + [ordinals], [ordinals], > + [[[["ordinals", > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 10, "name": "ten"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 11, "name": "eleven"}}]]]], > + [[row,action,name,number,_version > +<0>,initial,"""one""",1,"[""uuid"",""<1>""]" > +<2>,initial,"""two""",2,"[""uuid"",""<3>""]" > +<4>,initial,"""zero""",,"[""uuid"",""<5>""]" > + > +row,action,name,number,_version > +<6>,insert,"""eleven""",11,"[""uuid"",""<7>""]" > +<8>,insert,"""ten""",10,"[""uuid"",""<9>""]" > +]], > + [[]]) > + > +OVSDB_CHECK_MONITOR_COND([monitor-cond multiple conditions], > + [ordinal_schema], > + [[[["ordinals", > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 0, "name": "zero"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 1, "name": "one"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 2, "name": "two"}}]]]], > + [ordinals], [ordinals], > + [[[["ordinals", > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 10, "name": "ten"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 11, "name": "eleven"}}]]]], > + [[row,action,name,number,_version > +<0>,initial,"""one""",1,"[""uuid"",""<1>""]" > + > +row,action,name,number,_version > +<2>,insert,"""ten""",10,"[""uuid"",""<3>""]" > +]], > + [[["name","==","one"],["name","==","ten"]]]) > + > +OVSDB_CHECK_MONITOR_COND([monitor-cond delete from populated table], > + [ordinal_schema], > + [[[["ordinals", > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 0, "name": "zero"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 1, "name": "one"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 2, "name": "two"}}]]]], > + [ordinals], [ordinals], > + [[[["ordinals", > + {"op": "delete", > + "table": "ordinals", > + "where": []}]]]], > + [[row,action,name,number,_version > +<0>,initial,"""one""",1,"[""uuid"",""<1>""]" > + > +row,action,name,number,_version > +<0>,delete,,, > +]], > + [[["name","==","one"],["name","==","ten"]]]) > + > +OVSDB_CHECK_MONITOR_COND([monitor-cond insert due to modify], > + [ordinal_schema], > + [[[["ordinals", > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 0, "name": "zero"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 1, "name": "one"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 2, "name": "two"}}]]]], > + [ordinals], [ordinals], > + [[[["ordinals", > + {"op": "update", > + "table": "ordinals", > + "where": [["name", "==", "one"]], > + "row": {"name": "ONE"}}]]]], > + [[row,action,name,number,_version > +<0>,insert,"""ONE""",1,"[""uuid"",""<1>""]" > +]], > + [[["name","==","ONE"]]], > + [!initial,!delete,!modify]) > + > +OVSDB_CHECK_MONITOR_COND([monitor-cond delete due to modify], > + [ordinal_schema], > + [[[["ordinals", > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 0, "name": "zero"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 1, "name": "one"}}, > + {"op": "insert", > + "table": "ordinals", > + "row": {"number": 2, "name": "two"}}]]]], > + [ordinals], [ordinals], > + [[[["ordinals", > + {"op": "update", > + "table": "ordinals", > + "where": [["name", "==", "one"]], > + "row": {"name": "ONE"}}]]]], > + [[row,action,name,number,_version > +<0>,delete,,, > +]], > + [[["name","==","one"]]], > + [!initial,!insert,!modify]) > -- > 2.1.4 > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev