2 * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
28 #include "command-line.h"
33 #include "dynamic-string.h"
36 #include "lib/table.h"
38 #include "ovsdb-data.h"
39 #include "ovsdb-error.h"
40 #include "poll-loop.h"
44 #include "stream-ssl.h"
51 VLOG_DEFINE_THIS_MODULE(ovsdb_client
);
54 NEED_NONE
, /* No JSON-RPC connection or database name needed. */
55 NEED_RPC
, /* JSON-RPC connection needed. */
56 NEED_DATABASE
/* JSON-RPC connection and database name needed. */
59 struct ovsdb_client_command
{
61 enum args_needed need
;
64 void (*handler
)(struct jsonrpc
*rpc
, const char *database
,
65 int argc
, char *argv
[]);
68 /* --timestamp: Print a timestamp before each update on "monitor" command? */
69 static bool timestamp
;
71 /* Format for table output. */
72 static struct table_style table_style
= TABLE_STYLE_DEFAULT
;
74 static const struct ovsdb_client_command
*get_all_commands(void);
76 static void usage(void) NO_RETURN
;
77 static void parse_options(int argc
, char *argv
[]);
78 static struct jsonrpc
*open_jsonrpc(const char *server
);
79 static void fetch_dbs(struct jsonrpc
*, struct svec
*dbs
);
82 main(int argc
, char *argv
[])
84 const struct ovsdb_client_command
*command
;
88 proctitle_init(argc
, argv
);
89 set_program_name(argv
[0]);
90 parse_options(argc
, argv
);
91 signal(SIGPIPE
, SIG_IGN
);
94 ovs_fatal(0, "missing command name; use --help for help");
97 for (command
= get_all_commands(); ; command
++) {
99 VLOG_FATAL("unknown command '%s'; use --help for help",
101 } else if (!strcmp(command
->name
, argv
[optind
])) {
107 if (command
->need
!= NEED_NONE
) {
108 if (argc
- optind
> command
->min_args
109 && (isalpha((unsigned char) argv
[optind
][0])
110 && strchr(argv
[optind
], ':'))) {
111 rpc
= open_jsonrpc(argv
[optind
++]);
113 char *sock
= xasprintf("unix:%s/db.sock", ovs_rundir());
114 rpc
= open_jsonrpc(sock
);
121 if (command
->need
== NEED_DATABASE
) {
125 fetch_dbs(rpc
, &dbs
);
126 if (argc
- optind
> command
->min_args
127 && svec_contains(&dbs
, argv
[optind
])) {
128 database
= argv
[optind
++];
129 } else if (dbs
.n
== 1) {
130 database
= xstrdup(dbs
.names
[0]);
131 } else if (svec_contains(&dbs
, "Open_vSwitch")) {
132 database
= "Open_vSwitch";
134 ovs_fatal(0, "no default database for `%s' command, please "
135 "specify a database name", command
->name
);
142 if (argc
- optind
< command
->min_args
||
143 argc
- optind
> command
->max_args
) {
144 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
148 command
->handler(rpc
, database
, argc
- optind
, argv
+ optind
);
152 if (ferror(stdout
)) {
153 VLOG_FATAL("write to stdout failed");
155 if (ferror(stderr
)) {
156 VLOG_FATAL("write to stderr failed");
163 parse_options(int argc
, char *argv
[])
166 OPT_BOOTSTRAP_CA_CERT
= UCHAR_MAX
+ 1,
171 static const struct option long_options
[] = {
172 {"verbose", optional_argument
, NULL
, 'v'},
173 {"help", no_argument
, NULL
, 'h'},
174 {"version", no_argument
, NULL
, 'V'},
175 {"timestamp", no_argument
, NULL
, OPT_TIMESTAMP
},
178 {"bootstrap-ca-cert", required_argument
, NULL
, OPT_BOOTSTRAP_CA_CERT
},
179 STREAM_SSL_LONG_OPTIONS
,
184 char *short_options
= long_options_to_short_options(long_options
);
189 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
199 ovs_print_version(0, 0);
203 vlog_set_verbosity(optarg
);
206 DAEMON_OPTION_HANDLERS
208 TABLE_OPTION_HANDLERS(&table_style
)
210 STREAM_SSL_OPTION_HANDLERS
212 case OPT_BOOTSTRAP_CA_CERT
:
213 stream_ssl_set_ca_cert_file(optarg
, true);
224 /* getopt_long() already set the value for us. */
237 printf("%s: Open vSwitch database JSON-RPC client\n"
238 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
239 "\nValid commands are:\n"
240 "\n list-dbs [SERVER]\n"
241 " list databases available on SERVER\n"
242 "\n get-schema [SERVER] [DATABASE]\n"
243 " retrieve schema for DATABASE from SERVER\n"
244 "\n get-schema-version [SERVER] [DATABASE]\n"
245 " retrieve schema for DATABASE from SERVER and report only its\n"
246 " version number on stdout\n"
247 "\n list-tables [SERVER] [DATABASE]\n"
248 " list tables for DATABASE on SERVER\n"
249 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
250 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
251 "\n transact [SERVER] TRANSACTION\n"
252 " run TRANSACTION (a JSON array of operations) on SERVER\n"
253 " and print the results as JSON on stdout\n"
254 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
255 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
256 " COLUMNs may include !initial, !insert, !delete, !modify\n"
257 " to avoid seeing the specified kinds of changes.\n"
258 "\n monitor [SERVER] [DATABASE] ALL\n"
259 " monitor all changes to all columns in all tables\n"
260 " in DATBASE on SERVER.\n"
261 "\n dump [SERVER] [DATABASE]\n"
262 " dump contents of DATABASE on SERVER to stdout\n"
263 "\nThe default SERVER is unix:%s/db.sock.\n"
264 "The default DATABASE is Open_vSwitch.\n",
265 program_name
, program_name
, ovs_rundir());
266 stream_usage("SERVER", true, true, true);
267 printf("\nOutput formatting options:\n"
268 " -f, --format=FORMAT set output formatting to FORMAT\n"
269 " (\"table\", \"html\", \"csv\", "
271 " --no-headings omit table heading row\n"
272 " --pretty pretty-print JSON in output\n"
273 " --timestamp timestamp \"monitor\" output");
276 printf("\nOther options:\n"
277 " -h, --help display this help message\n"
278 " -V, --version display version information\n");
283 check_txn(int error
, struct jsonrpc_msg
**reply_
)
285 struct jsonrpc_msg
*reply
= *reply_
;
288 ovs_fatal(error
, "transaction failed");
292 ovs_fatal(error
, "transaction returned error: %s",
293 json_to_string(reply
->error
, table_style
.json_flags
));
298 parse_json(const char *s
)
300 struct json
*json
= json_from_string(s
);
301 if (json
->type
== JSON_STRING
) {
302 ovs_fatal(0, "\"%s\": %s", s
, json
->u
.string
);
307 static struct jsonrpc
*
308 open_jsonrpc(const char *server
)
310 struct stream
*stream
;
313 error
= stream_open_block(jsonrpc_stream_open(server
, &stream
,
314 DSCP_DEFAULT
), &stream
);
315 if (error
== EAFNOSUPPORT
) {
316 struct pstream
*pstream
;
318 error
= jsonrpc_pstream_open(server
, &pstream
, DSCP_DEFAULT
);
320 ovs_fatal(error
, "failed to connect or listen to \"%s\"", server
);
323 VLOG_INFO("%s: waiting for connection...", server
);
324 error
= pstream_accept_block(pstream
, &stream
);
326 ovs_fatal(error
, "failed to accept connection on \"%s\"", server
);
329 pstream_close(pstream
);
331 ovs_fatal(error
, "failed to connect to \"%s\"", server
);
334 return jsonrpc_open(stream
);
338 print_json(struct json
*json
)
340 char *string
= json_to_string(json
, table_style
.json_flags
);
341 fputs(string
, stdout
);
346 print_and_free_json(struct json
*json
)
353 check_ovsdb_error(struct ovsdb_error
*error
)
356 ovs_fatal(0, "%s", ovsdb_error_to_string(error
));
360 static struct ovsdb_schema
*
361 fetch_schema(struct jsonrpc
*rpc
, const char *database
)
363 struct jsonrpc_msg
*request
, *reply
;
364 struct ovsdb_schema
*schema
;
366 request
= jsonrpc_create_request("get_schema",
368 json_string_create(database
)),
370 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
371 check_ovsdb_error(ovsdb_schema_from_json(reply
->result
, &schema
));
372 jsonrpc_msg_destroy(reply
);
378 fetch_dbs(struct jsonrpc
*rpc
, struct svec
*dbs
)
380 struct jsonrpc_msg
*request
, *reply
;
383 request
= jsonrpc_create_request("list_dbs", json_array_create_empty(),
386 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
387 if (reply
->result
->type
!= JSON_ARRAY
) {
388 ovs_fatal(0, "list_dbs response is not array");
391 for (i
= 0; i
< reply
->result
->u
.array
.n
; i
++) {
392 const struct json
*name
= reply
->result
->u
.array
.elems
[i
];
394 if (name
->type
!= JSON_STRING
) {
395 ovs_fatal(0, "list_dbs response %"PRIuSIZE
" is not string", i
);
397 svec_add(dbs
, name
->u
.string
);
399 jsonrpc_msg_destroy(reply
);
404 do_list_dbs(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
405 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
412 fetch_dbs(rpc
, &dbs
);
413 SVEC_FOR_EACH (i
, db_name
, &dbs
) {
420 do_get_schema(struct jsonrpc
*rpc
, const char *database
,
421 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
423 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
424 print_and_free_json(ovsdb_schema_to_json(schema
));
425 ovsdb_schema_destroy(schema
);
429 do_get_schema_version(struct jsonrpc
*rpc
, const char *database
,
430 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
432 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
433 puts(schema
->version
);
434 ovsdb_schema_destroy(schema
);
438 do_list_tables(struct jsonrpc
*rpc
, const char *database
,
439 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
441 struct ovsdb_schema
*schema
;
442 struct shash_node
*node
;
445 schema
= fetch_schema(rpc
, database
);
447 table_add_column(&t
, "Table");
448 SHASH_FOR_EACH (node
, &schema
->tables
) {
449 struct ovsdb_table_schema
*ts
= node
->data
;
452 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
454 ovsdb_schema_destroy(schema
);
455 table_print(&t
, &table_style
);
459 do_list_columns(struct jsonrpc
*rpc
, const char *database
,
460 int argc OVS_UNUSED
, char *argv
[])
462 const char *table_name
= argv
[0];
463 struct ovsdb_schema
*schema
;
464 struct shash_node
*table_node
;
467 schema
= fetch_schema(rpc
, database
);
470 table_add_column(&t
, "Table");
472 table_add_column(&t
, "Column");
473 table_add_column(&t
, "Type");
474 SHASH_FOR_EACH (table_node
, &schema
->tables
) {
475 struct ovsdb_table_schema
*ts
= table_node
->data
;
477 if (!table_name
|| !strcmp(table_name
, ts
->name
)) {
478 struct shash_node
*column_node
;
480 SHASH_FOR_EACH (column_node
, &ts
->columns
) {
481 const struct ovsdb_column
*column
= column_node
->data
;
485 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
487 table_add_cell(&t
)->text
= xstrdup(column
->name
);
488 table_add_cell(&t
)->json
= ovsdb_type_to_json(&column
->type
);
492 ovsdb_schema_destroy(schema
);
493 table_print(&t
, &table_style
);
497 do_transact(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
498 int argc OVS_UNUSED
, char *argv
[])
500 struct jsonrpc_msg
*request
, *reply
;
501 struct json
*transaction
;
503 transaction
= parse_json(argv
[0]);
505 request
= jsonrpc_create_request("transact", transaction
, NULL
);
506 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
507 print_json(reply
->result
);
509 jsonrpc_msg_destroy(reply
);
512 /* "monitor" command. */
514 struct monitored_table
{
515 struct ovsdb_table_schema
*table
;
516 struct ovsdb_column_set columns
;
520 monitor_print_row(struct json
*row
, const char *type
, const char *uuid
,
521 const struct ovsdb_column_set
*columns
, struct table
*t
)
526 ovs_error(0, "missing %s row", type
);
528 } else if (row
->type
!= JSON_OBJECT
) {
529 ovs_error(0, "<row> is not object");
534 table_add_cell(t
)->text
= xstrdup(uuid
);
535 table_add_cell(t
)->text
= xstrdup(type
);
536 for (i
= 0; i
< columns
->n_columns
; i
++) {
537 const struct ovsdb_column
*column
= columns
->columns
[i
];
538 struct json
*value
= shash_find_data(json_object(row
), column
->name
);
539 struct cell
*cell
= table_add_cell(t
);
541 cell
->json
= json_clone(value
);
542 cell
->type
= &column
->type
;
548 monitor_print_table(struct json
*table_update
,
549 const struct monitored_table
*mt
, char *caption
,
552 const struct ovsdb_table_schema
*table
= mt
->table
;
553 const struct ovsdb_column_set
*columns
= &mt
->columns
;
554 struct shash_node
*node
;
558 if (table_update
->type
!= JSON_OBJECT
) {
559 ovs_error(0, "<table-update> for table %s is not object", table
->name
);
564 table_set_timestamp(&t
, timestamp
);
565 table_set_caption(&t
, caption
);
567 table_add_column(&t
, "row");
568 table_add_column(&t
, "action");
569 for (i
= 0; i
< columns
->n_columns
; i
++) {
570 table_add_column(&t
, "%s", columns
->columns
[i
]->name
);
572 SHASH_FOR_EACH (node
, json_object(table_update
)) {
573 struct json
*row_update
= node
->data
;
574 struct json
*old
, *new;
576 if (row_update
->type
!= JSON_OBJECT
) {
577 ovs_error(0, "<row-update> is not object");
580 old
= shash_find_data(json_object(row_update
), "old");
581 new = shash_find_data(json_object(row_update
), "new");
583 monitor_print_row(new, "initial", node
->name
, columns
, &t
);
585 monitor_print_row(new, "insert", node
->name
, columns
, &t
);
587 monitor_print_row(old
, "delete", node
->name
, columns
, &t
);
589 monitor_print_row(old
, "old", node
->name
, columns
, &t
);
590 monitor_print_row(new, "new", "", columns
, &t
);
593 table_print(&t
, &table_style
);
598 monitor_print(struct json
*table_updates
,
599 const struct monitored_table
*mts
, size_t n_mts
,
604 if (table_updates
->type
!= JSON_OBJECT
) {
605 ovs_error(0, "<table-updates> is not object");
609 for (i
= 0; i
< n_mts
; i
++) {
610 const struct monitored_table
*mt
= &mts
[i
];
611 struct json
*table_update
= shash_find_data(json_object(table_updates
),
614 monitor_print_table(table_update
, mt
,
615 n_mts
> 1 ? xstrdup(mt
->table
->name
) : NULL
,
622 add_column(const char *server
, const struct ovsdb_column
*column
,
623 struct ovsdb_column_set
*columns
, struct json
*columns_json
)
625 if (ovsdb_column_set_contains(columns
, column
->index
)) {
626 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
627 server
, column
->name
);
629 ovsdb_column_set_add(columns
, column
);
630 json_array_add(columns_json
, json_string_create(column
->name
));
634 parse_monitor_columns(char *arg
, const char *server
, const char *database
,
635 const struct ovsdb_table_schema
*table
,
636 struct ovsdb_column_set
*columns
)
638 bool initial
, insert
, delete, modify
;
639 struct json
*mr
, *columns_json
;
640 char *save_ptr
= NULL
;
643 mr
= json_object_create();
644 columns_json
= json_array_create_empty();
645 json_object_put(mr
, "columns", columns_json
);
647 initial
= insert
= delete = modify
= true;
648 for (token
= strtok_r(arg
, ",", &save_ptr
); token
!= NULL
;
649 token
= strtok_r(NULL
, ",", &save_ptr
)) {
650 if (!strcmp(token
, "!initial")) {
652 } else if (!strcmp(token
, "!insert")) {
654 } else if (!strcmp(token
, "!delete")) {
656 } else if (!strcmp(token
, "!modify")) {
659 const struct ovsdb_column
*column
;
661 column
= ovsdb_table_schema_get_column(table
, token
);
663 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
664 "column named \"%s\"",
665 server
, table
->name
, database
, token
);
667 add_column(server
, column
, columns
, columns_json
);
671 if (columns_json
->u
.array
.n
== 0) {
672 const struct shash_node
**nodes
;
675 n
= shash_count(&table
->columns
);
676 nodes
= shash_sort(&table
->columns
);
677 for (i
= 0; i
< n
; i
++) {
678 const struct ovsdb_column
*column
= nodes
[i
]->data
;
679 if (column
->index
!= OVSDB_COL_UUID
680 && column
->index
!= OVSDB_COL_VERSION
) {
681 add_column(server
, column
, columns
, columns_json
);
686 add_column(server
, ovsdb_table_schema_get_column(table
, "_version"),
687 columns
, columns_json
);
690 if (!initial
|| !insert
|| !delete || !modify
) {
691 struct json
*select
= json_object_create();
692 json_object_put(select
, "initial", json_boolean_create(initial
));
693 json_object_put(select
, "insert", json_boolean_create(insert
));
694 json_object_put(select
, "delete", json_boolean_create(delete));
695 json_object_put(select
, "modify", json_boolean_create(modify
));
696 json_object_put(mr
, "select", select
);
703 ovsdb_client_exit(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
704 const char *argv
[] OVS_UNUSED
, void *exiting_
)
706 bool *exiting
= exiting_
;
708 unixctl_command_reply(conn
, NULL
);
712 ovsdb_client_block(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
713 const char *argv
[] OVS_UNUSED
, void *blocked_
)
715 bool *blocked
= blocked_
;
719 unixctl_command_reply(conn
, NULL
);
721 unixctl_command_reply(conn
, "already blocking");
726 ovsdb_client_unblock(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
727 const char *argv
[] OVS_UNUSED
, void *blocked_
)
729 bool *blocked
= blocked_
;
733 unixctl_command_reply(conn
, NULL
);
735 unixctl_command_reply(conn
, "already unblocked");
740 add_monitored_table(int argc
, char *argv
[],
741 const char *server
, const char *database
,
742 struct ovsdb_table_schema
*table
,
743 struct json
*monitor_requests
,
744 struct monitored_table
**mts
,
745 size_t *n_mts
, size_t *allocated_mts
)
747 struct json
*monitor_request_array
;
748 struct monitored_table
*mt
;
750 if (*n_mts
>= *allocated_mts
) {
751 *mts
= x2nrealloc(*mts
, allocated_mts
, sizeof **mts
);
753 mt
= &(*mts
)[(*n_mts
)++];
755 ovsdb_column_set_init(&mt
->columns
);
757 monitor_request_array
= json_array_create_empty();
761 for (i
= 1; i
< argc
; i
++) {
763 monitor_request_array
,
764 parse_monitor_columns(argv
[i
], server
, database
, table
,
768 /* Allocate a writable empty string since parse_monitor_columns()
769 * is going to strtok() it and that's risky with literal "". */
772 monitor_request_array
,
773 parse_monitor_columns(empty
, server
, database
,
774 table
, &mt
->columns
));
777 json_object_put(monitor_requests
, table
->name
, monitor_request_array
);
781 do_monitor(struct jsonrpc
*rpc
, const char *database
,
782 int argc
, char *argv
[])
784 const char *server
= jsonrpc_get_name(rpc
);
785 const char *table_name
= argv
[0];
786 struct unixctl_server
*unixctl
;
787 struct ovsdb_schema
*schema
;
788 struct jsonrpc_msg
*request
;
789 struct json
*monitor
, *monitor_requests
, *request_id
;
790 bool exiting
= false;
791 bool blocked
= false;
793 struct monitored_table
*mts
;
794 size_t n_mts
, allocated_mts
;
796 daemon_save_fd(STDOUT_FILENO
);
801 error
= unixctl_server_create(NULL
, &unixctl
);
803 ovs_fatal(error
, "failed to create unixctl server");
806 unixctl_command_register("exit", "", 0, 0,
807 ovsdb_client_exit
, &exiting
);
808 unixctl_command_register("ovsdb-client/block", "", 0, 0,
809 ovsdb_client_block
, &blocked
);
810 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
811 ovsdb_client_unblock
, &blocked
);
816 schema
= fetch_schema(rpc
, database
);
818 monitor_requests
= json_object_create();
821 n_mts
= allocated_mts
= 0;
822 if (strcmp(table_name
, "ALL")) {
823 struct ovsdb_table_schema
*table
;
825 table
= shash_find_data(&schema
->tables
, table_name
);
827 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
828 server
, database
, table_name
);
831 add_monitored_table(argc
, argv
, server
, database
, table
,
832 monitor_requests
, &mts
, &n_mts
, &allocated_mts
);
834 size_t n
= shash_count(&schema
->tables
);
835 const struct shash_node
**nodes
= shash_sort(&schema
->tables
);
838 for (i
= 0; i
< n
; i
++) {
839 struct ovsdb_table_schema
*table
= nodes
[i
]->data
;
841 add_monitored_table(argc
, argv
, server
, database
, table
,
843 &mts
, &n_mts
, &allocated_mts
);
848 monitor
= json_array_create_3(json_string_create(database
),
849 json_null_create(), monitor_requests
);
850 request
= jsonrpc_create_request("monitor", monitor
, NULL
);
851 request_id
= json_clone(request
->id
);
852 jsonrpc_send(rpc
, request
);
855 unixctl_server_run(unixctl
);
857 struct jsonrpc_msg
*msg
;
860 error
= jsonrpc_recv(rpc
, &msg
);
861 if (error
== EAGAIN
) {
864 ovs_fatal(error
, "%s: receive failed", server
);
867 if (msg
->type
== JSONRPC_REQUEST
&& !strcmp(msg
->method
, "echo")) {
868 jsonrpc_send(rpc
, jsonrpc_create_reply(json_clone(msg
->params
),
870 } else if (msg
->type
== JSONRPC_REPLY
871 && json_equal(msg
->id
, request_id
)) {
872 monitor_print(msg
->result
, mts
, n_mts
, true);
874 daemonize_complete();
875 } else if (msg
->type
== JSONRPC_NOTIFY
876 && !strcmp(msg
->method
, "update")) {
877 struct json
*params
= msg
->params
;
878 if (params
->type
== JSON_ARRAY
879 && params
->u
.array
.n
== 2
880 && params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
881 monitor_print(params
->u
.array
.elems
[1], mts
, n_mts
, false);
885 jsonrpc_msg_destroy(msg
);
895 jsonrpc_recv_wait(rpc
);
897 unixctl_server_wait(unixctl
);
902 struct dump_table_aux
{
903 struct ovsdb_datum
**data
;
904 const struct ovsdb_column
**columns
;
909 compare_data(size_t a_y
, size_t b_y
, size_t x
,
910 const struct dump_table_aux
*aux
)
912 return ovsdb_datum_compare_3way(&aux
->data
[a_y
][x
],
914 &aux
->columns
[x
]->type
);
918 compare_rows(size_t a_y
, size_t b_y
, void *aux_
)
920 struct dump_table_aux
*aux
= aux_
;
923 /* Skip UUID columns on the first pass, since their values tend to be
924 * random and make our results less reproducible. */
925 for (x
= 0; x
< aux
->n_columns
; x
++) {
926 if (aux
->columns
[x
]->type
.key
.type
!= OVSDB_TYPE_UUID
) {
927 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
934 /* Use UUID columns as tie-breakers. */
935 for (x
= 0; x
< aux
->n_columns
; x
++) {
936 if (aux
->columns
[x
]->type
.key
.type
== OVSDB_TYPE_UUID
) {
937 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
948 swap_rows(size_t a_y
, size_t b_y
, void *aux_
)
950 struct dump_table_aux
*aux
= aux_
;
951 struct ovsdb_datum
*tmp
= aux
->data
[a_y
];
952 aux
->data
[a_y
] = aux
->data
[b_y
];
953 aux
->data
[b_y
] = tmp
;
957 compare_columns(const void *a_
, const void *b_
)
959 const struct ovsdb_column
*const *ap
= a_
;
960 const struct ovsdb_column
*const *bp
= b_
;
961 const struct ovsdb_column
*a
= *ap
;
962 const struct ovsdb_column
*b
= *bp
;
964 return strcmp(a
->name
, b
->name
);
968 dump_table(const struct ovsdb_table_schema
*ts
, struct json_array
*rows
)
970 const struct ovsdb_column
**columns
;
973 struct ovsdb_datum
**data
;
975 struct dump_table_aux aux
;
976 struct shash_node
*node
;
980 /* Sort columns by name, for reproducibility. */
981 columns
= xmalloc(shash_count(&ts
->columns
) * sizeof *columns
);
983 SHASH_FOR_EACH (node
, &ts
->columns
) {
984 struct ovsdb_column
*column
= node
->data
;
985 if (strcmp(column
->name
, "_version")) {
986 columns
[n_columns
++] = column
;
989 qsort(columns
, n_columns
, sizeof *columns
, compare_columns
);
991 /* Extract data from table. */
992 data
= xmalloc(rows
->n
* sizeof *data
);
993 for (y
= 0; y
< rows
->n
; y
++) {
996 if (rows
->elems
[y
]->type
!= JSON_OBJECT
) {
997 ovs_fatal(0, "row %"PRIuSIZE
" in table %s response is not a JSON object: "
998 "%s", y
, ts
->name
, json_to_string(rows
->elems
[y
], 0));
1000 row
= json_object(rows
->elems
[y
]);
1002 data
[y
] = xmalloc(n_columns
* sizeof **data
);
1003 for (x
= 0; x
< n_columns
; x
++) {
1004 const struct json
*json
= shash_find_data(row
, columns
[x
]->name
);
1006 ovs_fatal(0, "row %"PRIuSIZE
" in table %s response lacks %s column",
1007 y
, ts
->name
, columns
[x
]->name
);
1010 check_ovsdb_error(ovsdb_datum_from_json(&data
[y
][x
],
1016 /* Sort rows by column values, for reproducibility. */
1018 aux
.columns
= columns
;
1019 aux
.n_columns
= n_columns
;
1020 sort(rows
->n
, compare_rows
, swap_rows
, &aux
);
1022 /* Add column headings. */
1024 table_set_caption(&t
, xasprintf("%s table", ts
->name
));
1025 for (x
= 0; x
< n_columns
; x
++) {
1026 table_add_column(&t
, "%s", columns
[x
]->name
);
1030 for (y
= 0; y
< rows
->n
; y
++) {
1032 for (x
= 0; x
< n_columns
; x
++) {
1033 struct cell
*cell
= table_add_cell(&t
);
1034 cell
->json
= ovsdb_datum_to_json(&data
[y
][x
], &columns
[x
]->type
);
1035 cell
->type
= &columns
[x
]->type
;
1036 ovsdb_datum_destroy(&data
[y
][x
], &columns
[x
]->type
);
1040 table_print(&t
, &table_style
);
1048 do_dump(struct jsonrpc
*rpc
, const char *database
,
1049 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1051 struct jsonrpc_msg
*request
, *reply
;
1052 struct ovsdb_schema
*schema
;
1053 struct json
*transaction
;
1055 const struct shash_node
**tables
;
1060 schema
= fetch_schema(rpc
, database
);
1061 tables
= shash_sort(&schema
->tables
);
1062 n_tables
= shash_count(&schema
->tables
);
1064 /* Construct transaction to retrieve entire database. */
1065 transaction
= json_array_create_1(json_string_create(database
));
1066 for (i
= 0; i
< n_tables
; i
++) {
1067 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1068 struct json
*op
, *columns
;
1069 struct shash_node
*node
;
1071 columns
= json_array_create_empty();
1072 SHASH_FOR_EACH (node
, &ts
->columns
) {
1073 const struct ovsdb_column
*column
= node
->data
;
1075 if (strcmp(column
->name
, "_version")) {
1076 json_array_add(columns
, json_string_create(column
->name
));
1080 op
= json_object_create();
1081 json_object_put_string(op
, "op", "select");
1082 json_object_put_string(op
, "table", tables
[i
]->name
);
1083 json_object_put(op
, "where", json_array_create_empty());
1084 json_object_put(op
, "columns", columns
);
1085 json_array_add(transaction
, op
);
1088 /* Send request, get reply. */
1089 request
= jsonrpc_create_request("transact", transaction
, NULL
);
1090 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
1092 /* Print database contents. */
1093 if (reply
->result
->type
!= JSON_ARRAY
1094 || reply
->result
->u
.array
.n
!= n_tables
) {
1095 ovs_fatal(0, "reply is not array of %"PRIuSIZE
" elements: %s",
1096 n_tables
, json_to_string(reply
->result
, 0));
1098 for (i
= 0; i
< n_tables
; i
++) {
1099 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1100 const struct json
*op_result
= reply
->result
->u
.array
.elems
[i
];
1103 if (op_result
->type
!= JSON_OBJECT
1104 || !(rows
= shash_find_data(json_object(op_result
), "rows"))
1105 || rows
->type
!= JSON_ARRAY
) {
1106 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1108 ts
->name
, json_to_string(op_result
, 0));
1111 dump_table(ts
, &rows
->u
.array
);
1114 jsonrpc_msg_destroy(reply
);
1116 ovsdb_schema_destroy(schema
);
1120 do_help(struct jsonrpc
*rpc OVS_UNUSED
, const char *database OVS_UNUSED
,
1121 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1126 /* All command handlers (except for "help") are expected to take an optional
1127 * server socket name (e.g. "unix:...") as their first argument. The socket
1128 * name argument must be included in max_args (but left out of min_args). The
1129 * command name and socket name are not included in the arguments passed to the
1130 * handler: the argv[0] passed to the handler is the first argument after the
1131 * optional server socket name. The connection to the server is available as
1132 * global variable 'rpc'. */
1133 static const struct ovsdb_client_command all_commands
[] = {
1134 { "list-dbs", NEED_RPC
, 0, 0, do_list_dbs
},
1135 { "get-schema", NEED_DATABASE
, 0, 0, do_get_schema
},
1136 { "get-schema-version", NEED_DATABASE
, 0, 0, do_get_schema_version
},
1137 { "list-tables", NEED_DATABASE
, 0, 0, do_list_tables
},
1138 { "list-columns", NEED_DATABASE
, 0, 1, do_list_columns
},
1139 { "transact", NEED_RPC
, 1, 1, do_transact
},
1140 { "monitor", NEED_DATABASE
, 1, INT_MAX
, do_monitor
},
1141 { "dump", NEED_DATABASE
, 0, 0, do_dump
},
1143 { "help", NEED_NONE
, 0, INT_MAX
, do_help
},
1145 { NULL
, 0, 0, 0, NULL
},
1148 static const struct ovsdb_client_command
*get_all_commands(void)
1150 return all_commands
;