From patchwork Tue Nov 24 22:16:04 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Zhou X-Patchwork-Id: 548318 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (unknown [IPv6:2600:3c00::f03c:91ff:fe6e:bdf7]) by ozlabs.org (Postfix) with ESMTP id 2CE6C1402A8 for ; Wed, 25 Nov 2015 09:17:05 +1100 (AEDT) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id E922410A42; Tue, 24 Nov 2015 14:16:33 -0800 (PST) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 5499510A20 for ; Tue, 24 Nov 2015 14:16:32 -0800 (PST) Received: from bar4.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id DE606161156 for ; Tue, 24 Nov 2015 15:16:31 -0700 (MST) X-ASG-Debug-ID: 1448403391-03dc21603e8ce40001-byXFYA Received: from mx3-pf2.cudamail.com ([192.168.14.1]) by bar4.cudamail.com with ESMTP id 8fmrLwToknYnByFZ (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 24 Nov 2015 15:16:31 -0700 (MST) X-Barracuda-Envelope-From: azhou.ovn@gmail.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.1 Received: from unknown (HELO mail-pa0-f46.google.com) (209.85.220.46) by mx3-pf2.cudamail.com with ESMTPS (RC4-SHA encrypted); 24 Nov 2015 22:16:31 -0000 Received-SPF: pass (mx3-pf2.cudamail.com: SPF record at _netblocks.google.com designates 209.85.220.46 as permitted sender) X-Barracuda-Apparent-Source-IP: 209.85.220.46 X-Barracuda-RBL-IP: 209.85.220.46 Received: by pacdm15 with SMTP id dm15so34870009pac.3 for ; Tue, 24 Nov 2015 14:16:29 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=QZOk+asaa8PiPQdCN66u+SrtK1GWyfblddtzwvkSczM=; b=ainsvuTmhTccSMklUSOtwlqGX2L2ssF5rfLQxD12d3kahSx1LjJFkba2Kb/XS+S+LK 5HqzKaQJiOu8tbKs8qTTQfgVqql9enKBPiAQUQ8jEFF41H9ICDXKiOGEGqKKysliYWp3 Cw4JqKFIjbdrQG/j5KeadkcYcS90lDVgHkuj/O7wxYAGgwYsLizmq+DLKX1VAnAGb7C7 TqY+lFk302pn3Azgik/qSOVTKjx6w45VC9PCon9ComS1xqIshr6z+Wmqub8NmmUHtbKB I+QHVdOJKB/DOrkNEFCXX6WlUGpBaUHor9i1gjRUkhKNhZaNYy83SJ1P/mTxSmtHcxLr N+mA== X-Received: by 10.67.6.1 with SMTP id cq1mr35605512pad.78.1448403389671; Tue, 24 Nov 2015 14:16:29 -0800 (PST) Received: from ubuntu.localdomain ([208.91.1.34]) by smtp.gmail.com with ESMTPSA id b15sm16374570pfj.7.2015.11.24.14.16.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 24 Nov 2015 14:16:28 -0800 (PST) X-CudaMail-Envelope-Sender: azhou.ovn@gmail.com From: Andy Zhou To: dev@openvswitch.org X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V2-1123060689 X-CudaMail-DTE: 112415 X-CudaMail-Originating-IP: 209.85.220.46 Date: Tue, 24 Nov 2015 14:16:04 -0800 X-ASG-Orig-Subj: [##CM-V2-1123060689##][monitor2 v2 7/9] ovsdb-client: support monitor2 Message-Id: <1448403366-21460-7-git-send-email-azhou@ovn.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1448403366-21460-1-git-send-email-azhou@ovn.org> References: <1448403366-21460-1-git-send-email-azhou@ovn.org> X-Barracuda-Connect: UNKNOWN[192.168.14.1] X-Barracuda-Start-Time: 1448403391 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 Subject: [ovs-dev] [monitor2 v2 7/9] ovsdb-client: support monitor2 X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" From: Andy Zhou Add monitor2 option to ovsdb-client. See ovsdb-client(1) manpage patch for details. Signed-off-by: Andy Zhou Acked-by: Ben Pfaff --- v1->v2: * style fixes --- ovsdb/monitor.h | 1 + ovsdb/ovsdb-client.1.in | 29 +++++++--- ovsdb/ovsdb-client.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 11 deletions(-) diff --git a/ovsdb/monitor.h b/ovsdb/monitor.h index b1a5146..d6e9635 100644 --- a/ovsdb/monitor.h +++ b/ovsdb/monitor.h @@ -18,6 +18,7 @@ #define OVSDB_MONITOR_H struct ovsdb_monitor; +struct ovsdb_jsonrpc_monitor; enum ovsdb_monitor_selection { OJMS_INITIAL = 1 << 0, /* All rows when monitor is created. */ diff --git a/ovsdb/ovsdb-client.1.in b/ovsdb/ovsdb-client.1.in index fbb7148..422f6e1 100644 --- a/ovsdb/ovsdb-client.1.in +++ b/ovsdb/ovsdb-client.1.in @@ -32,6 +32,11 @@ 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 +.br \fBovsdb\-client help\fR .IP "Output formatting options:" [\fB\-\-format=\fIformat\fR] @@ -105,6 +110,7 @@ Connects to \fIserver\fR, retrieves all of the data in \fIdatabase\fR, and prints it on stdout as a series of tables. . .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 @@ -127,16 +133,25 @@ 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, then \fBovsdb\-client\fR -detaches after it has successfully received and printed the initial -contents of \fItable\fR. +If \fB\-\-detach\fR is used with \fBmonitor\fR or \fBmointor2\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. . .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 \fBovsdb\-client\fR to detach after it successfully receives and 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. . .SH OPTIONS .SS "Output Formatting Options" @@ -147,14 +162,14 @@ The following options controlling output formatting: .so lib/table.man . .IP "\fB\-\-timestamp\fR" -For the \fBmonitor\fR command, adds a timestamp to each table -update. Most output formats add the timestamp on a line of its own +For the \fBmonitor\fR and \fBmonitor2\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 command. With any -other command, they have no effect. +The daemon options apply only to the \fBmonitor\fR and \fBmonitor2\fR commands. +With any other command, they have no effect. .ds DD .so lib/daemon.man .SS "Logging Options" diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c index b59388f..d676f78 100644 --- a/ovsdb/ovsdb-client.c +++ b/ovsdb/ovsdb-client.c @@ -44,6 +44,7 @@ #include "stream.h" #include "stream-ssl.h" #include "table.h" +#include "monitor.h" #include "timeval.h" #include "unixctl.h" #include "util.h" @@ -256,6 +257,9 @@ usage(void) "\n monitor [SERVER] [DATABASE] ALL\n" " monitor all changes to all columns in all tables\n" " in DATBASE on SERVER.\n" + "\n monitor2 [SERVER] [DATABASE] ALL\n" + " same usage as monitor, but uses \"monitor2\" method over" + " the wire." "\n dump [SERVER] [DATABASE]\n" " dump contents of DATABASE on SERVER to stdout\n" "\nThe default SERVER is unix:%s/db.sock.\n" @@ -617,6 +621,101 @@ monitor_print(struct json *table_updates, } static void +monitor2_print_row(struct json *row, const char *type, const char *uuid, + const struct ovsdb_column_set *columns, struct table *t) +{ + if (!strcmp(type, "delete")) { + if (row->type != JSON_NULL) { + ovs_error(0, "delete method does not expect "); + return; + } + + table_add_row(t); + table_add_cell(t)->text = xstrdup(uuid); + table_add_cell(t)->text = xstrdup(type); + } else { + if (!row || row->type != JSON_OBJECT) { + ovs_error(0, " is not object"); + return; + } + monitor_print_row(row, type, uuid, columns, t); + } +} + +static void +monitor2_print_table(struct json *table_update2, + const struct monitored_table *mt, char *caption) +{ + const struct ovsdb_table_schema *table = mt->table; + const struct ovsdb_column_set *columns = &mt->columns; + struct shash_node *node; + struct table t; + size_t i; + + if (table_update2->type != JSON_OBJECT) { + ovs_error(0, " for table %s is not object", table->name); + return; + } + + table_init(&t); + table_set_timestamp(&t, timestamp); + table_set_caption(&t, caption); + + table_add_column(&t, "row"); + table_add_column(&t, "action"); + for (i = 0; i < columns->n_columns; i++) { + table_add_column(&t, "%s", columns->columns[i]->name); + } + SHASH_FOR_EACH (node, json_object(table_update2)) { + struct json *row_update2 = node->data; + const char *operation; + struct json *row; + const char *ops[] = {"delete", "initial", "modify", "insert"}; + + if (row_update2->type != JSON_OBJECT) { + ovs_error(0, " is not object"); + continue; + } + + /* row_update2 contains one of objects indexed by ops[] */ + for (int i = 0; i < ARRAY_SIZE(ops); i++) { + operation = ops[i]; + row = shash_find_data(json_object(row_update2), operation); + + if (row) { + monitor2_print_row(row, operation, node->name, columns, &t); + break; + } + } + } + table_print(&t, &table_style); + table_destroy(&t); +} + +static void +monitor2_print(struct json *table_updates2, + const struct monitored_table *mts, size_t n_mts) +{ + size_t i; + + if (table_updates2->type != JSON_OBJECT) { + ovs_error(0, " is not object"); + return; + } + + for (i = 0; i < n_mts; i++) { + const struct monitored_table *mt = &mts[i]; + struct json *table_update = shash_find_data( + json_object(table_updates2), + mt->table->name); + if (table_update) { + monitor2_print_table(table_update, mt, + n_mts > 1 ? xstrdup(mt->table->name) : NULL); + } + } +} + +static void add_column(const char *server, const struct ovsdb_column *column, struct ovsdb_column_set *columns, struct json *columns_json) { @@ -776,8 +875,9 @@ add_monitored_table(int argc, char *argv[], } static void -do_monitor(struct jsonrpc *rpc, const char *database, - int argc, char *argv[]) +do_monitor__(struct jsonrpc *rpc, const char *database, + enum ovsdb_monitor_version version, + int argc, char *argv[]) { const char *server = jsonrpc_get_name(rpc); const char *table_name = argv[0]; @@ -791,6 +891,8 @@ do_monitor(struct jsonrpc *rpc, const char *database, struct monitored_table *mts; size_t n_mts, allocated_mts; + ovs_assert(version < OVSDB_MONITOR_VERSION_MAX); + daemon_save_fd(STDOUT_FILENO); daemonize_start(false); if (get_detach()) { @@ -845,7 +947,10 @@ do_monitor(struct jsonrpc *rpc, const char *database, monitor = json_array_create_3(json_string_create(database), json_null_create(), monitor_requests); - request = jsonrpc_create_request("monitor", monitor, NULL); + const char *method = version == OVSDB_MONITOR_V2 ? "monitor2" + : "monitor"; + + request = jsonrpc_create_request(method, monitor, NULL); request_id = json_clone(request->id); jsonrpc_send(rpc, request); @@ -867,7 +972,17 @@ do_monitor(struct jsonrpc *rpc, const char *database, msg->id)); } else if (msg->type == JSONRPC_REPLY && json_equal(msg->id, request_id)) { - monitor_print(msg->result, mts, n_mts, true); + switch(version) { + case OVSDB_MONITOR_V1: + monitor_print(msg->result, mts, n_mts, true); + break; + case OVSDB_MONITOR_V2: + monitor2_print(msg->result, mts, n_mts); + break; + case OVSDB_MONITOR_VERSION_MAX: + default: + OVS_NOT_REACHED(); + } fflush(stdout); daemonize_complete(); } else if (msg->type == JSONRPC_NOTIFY @@ -879,6 +994,16 @@ do_monitor(struct jsonrpc *rpc, const char *database, monitor_print(params->u.array.elems[1], mts, n_mts, false); fflush(stdout); } + } else if (msg->type == JSONRPC_NOTIFY + && version == OVSDB_MONITOR_V2 + && !strcmp(msg->method, "update2")) { + struct json *params = msg->params; + if (params->type == JSON_ARRAY + && params->u.array.n == 2 + && params->u.array.elems[0]->type == JSON_NULL) { + monitor2_print(params->u.array.elems[1], mts, n_mts); + fflush(stdout); + } } jsonrpc_msg_destroy(msg); } @@ -897,6 +1022,20 @@ do_monitor(struct jsonrpc *rpc, const char *database, } } +static void +do_monitor(struct jsonrpc *rpc, const char *database, + int argc, char *argv[]) +{ + do_monitor__(rpc, database, OVSDB_MONITOR_V1, 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); +} + struct dump_table_aux { struct ovsdb_datum **data; const struct ovsdb_column **columns; @@ -1136,6 +1275,7 @@ static const struct ovsdb_client_command all_commands[] = { { "list-columns", NEED_DATABASE, 0, 1, do_list_columns }, { "transact", NEED_RPC, 1, 1, do_transact }, { "monitor", NEED_DATABASE, 1, INT_MAX, do_monitor }, + { "monitor2", NEED_DATABASE, 1, INT_MAX, do_monitor2 }, { "dump", NEED_DATABASE, 0, 0, do_dump }, { "help", NEED_NONE, 0, INT_MAX, do_help },