2 * Copyright (c) 2009, 2010 Nicira Networks.
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"
32 #include "dynamic-string.h"
36 #include "ovsdb-data.h"
37 #include "ovsdb-error.h"
40 #include "stream-ssl.h"
46 VLOG_DEFINE_THIS_MODULE(ovsdb_client
);
48 /* --format: Output formatting. */
50 FMT_TABLE
, /* Textual table. */
51 FMT_HTML
, /* HTML table. */
52 FMT_CSV
, /* Comma-separated lines. */
56 /* --no-headings: Whether table output should include headings. */
57 static int output_headings
= true;
59 /* --pretty: Flags to pass to json_to_string(). */
60 static int json_flags
= JSSF_SORT
;
62 /* --data: Format of data in output tables. */
64 DF_STRING
, /* String format. */
68 static const struct command all_commands
[];
70 static void usage(void) NO_RETURN
;
71 static void parse_options(int argc
, char *argv
[]);
74 main(int argc
, char *argv
[])
76 proctitle_init(argc
, argv
);
77 set_program_name(argv
[0]);
78 parse_options(argc
, argv
);
79 signal(SIGPIPE
, SIG_IGN
);
80 run_command(argc
- optind
, argv
+ optind
, all_commands
);
85 parse_options(int argc
, char *argv
[])
88 OPT_BOOTSTRAP_CA_CERT
= UCHAR_MAX
+ 1,
91 static struct option long_options
[] = {
92 {"format", required_argument
, 0, 'f'},
93 {"data", required_argument
, 0, 'd'},
94 {"no-headings", no_argument
, &output_headings
, 0},
95 {"pretty", no_argument
, &json_flags
, JSSF_PRETTY
| JSSF_SORT
},
96 {"verbose", optional_argument
, 0, 'v'},
97 {"help", no_argument
, 0, 'h'},
98 {"version", no_argument
, 0, 'V'},
101 {"bootstrap-ca-cert", required_argument
, 0, OPT_BOOTSTRAP_CA_CERT
},
102 STREAM_SSL_LONG_OPTIONS
106 char *short_options
= long_options_to_short_options(long_options
);
111 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
118 if (!strcmp(optarg
, "table")) {
119 output_format
= FMT_TABLE
;
120 } else if (!strcmp(optarg
, "html")) {
121 output_format
= FMT_HTML
;
122 } else if (!strcmp(optarg
, "csv")) {
123 output_format
= FMT_CSV
;
124 } else if (!strcmp(optarg
, "json")) {
125 output_format
= FMT_JSON
;
127 ovs_fatal(0, "unknown output format \"%s\"", optarg
);
132 if (!strcmp(optarg
, "string")) {
133 data_format
= DF_STRING
;
134 } else if (!strcmp(optarg
, "json")) {
135 data_format
= DF_JSON
;
137 ovs_fatal(0, "unknown data format \"%s\"", optarg
);
145 OVS_PRINT_VERSION(0, 0);
149 vlog_set_verbosity(optarg
);
152 DAEMON_OPTION_HANDLERS
155 STREAM_SSL_OPTION_HANDLERS
157 case OPT_BOOTSTRAP_CA_CERT
:
158 stream_ssl_set_ca_cert_file(optarg
, true);
166 /* getopt_long() already set the value for us. */
179 printf("%s: Open vSwitch database JSON-RPC client\n"
180 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
181 "\nValid commands are:\n"
182 "\n list-dbs SERVER\n"
183 " list databases available on SERVER\n"
184 "\n get-schema SERVER DATABASE\n"
185 " retrieve schema for DATABASE from SERVER\n"
186 "\n get-schema-version SERVER DATABASE\n"
187 " retrieve schema for DATABASE from SERVER and report only its\n"
188 " version number on stdout\n"
189 "\n list-tables SERVER DATABASE\n"
190 " list tables for DATABASE on SERVER\n"
191 "\n list-columns SERVER DATABASE [TABLE]\n"
192 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
193 "\n transact SERVER TRANSACTION\n"
194 " run TRANSACTION (a JSON array of operations) on SERVER\n"
195 " and print the results as JSON on stdout\n"
196 "\n monitor SERVER DATABASE TABLE [COLUMN,...]...\n"
197 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
198 " COLUMNs may include !initial, !insert, !delete, !modify\n"
199 " to avoid seeing the specified kinds of changes.\n"
200 "\n dump SERVER DATABASE\n"
201 " dump contents of DATABASE on SERVER to stdout\n",
202 program_name
, program_name
);
203 stream_usage("SERVER", true, true, true);
204 printf("\nOutput formatting options:\n"
205 " -f, --format=FORMAT set output formatting to FORMAT\n"
206 " (\"table\", \"html\", \"csv\", "
208 " --no-headings omit table heading row\n"
209 " --pretty pretty-print JSON in output");
212 printf("\nOther options:\n"
213 " -h, --help display this help message\n"
214 " -V, --version display version information\n");
219 parse_json(const char *s
)
221 struct json
*json
= json_from_string(s
);
222 if (json
->type
== JSON_STRING
) {
223 ovs_fatal(0, "\"%s\": %s", s
, json
->u
.string
);
228 static struct jsonrpc
*
229 open_jsonrpc(const char *server
)
231 struct stream
*stream
;
234 error
= stream_open_block(jsonrpc_stream_open(server
, &stream
), &stream
);
235 if (error
== EAFNOSUPPORT
) {
236 struct pstream
*pstream
;
238 error
= jsonrpc_pstream_open(server
, &pstream
);
240 ovs_fatal(error
, "failed to connect or listen to \"%s\"", server
);
243 VLOG_INFO("%s: waiting for connection...", server
);
244 error
= pstream_accept_block(pstream
, &stream
);
246 ovs_fatal(error
, "failed to accept connection on \"%s\"", server
);
249 pstream_close(pstream
);
251 ovs_fatal(error
, "failed to connect to \"%s\"", server
);
254 return jsonrpc_open(stream
);
258 print_json(struct json
*json
)
260 char *string
= json_to_string(json
, json_flags
);
261 fputs(string
, stdout
);
266 print_and_free_json(struct json
*json
)
273 check_ovsdb_error(struct ovsdb_error
*error
)
276 ovs_fatal(0, "%s", ovsdb_error_to_string(error
));
280 static struct ovsdb_schema
*
281 fetch_schema_from_rpc(struct jsonrpc
*rpc
, const char *database
)
283 struct jsonrpc_msg
*request
, *reply
;
284 struct ovsdb_schema
*schema
;
287 request
= jsonrpc_create_request("get_schema",
289 json_string_create(database
)),
291 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
293 ovs_fatal(error
, "transaction failed");
295 check_ovsdb_error(ovsdb_schema_from_json(reply
->result
, &schema
));
296 jsonrpc_msg_destroy(reply
);
301 static struct ovsdb_schema
*
302 fetch_schema(const char *server
, const char *database
)
304 struct ovsdb_schema
*schema
;
307 rpc
= open_jsonrpc(server
);
308 schema
= fetch_schema_from_rpc(rpc
, database
);
324 const struct ovsdb_type
*type
;
328 cell_to_text(const struct cell
*cell_
)
330 struct cell
*cell
= (struct cell
*) cell_
;
333 if (data_format
== DF_JSON
|| !cell
->type
) {
334 cell
->text
= json_to_string(cell
->json
, JSSF_SORT
);
335 } else if (data_format
== DF_STRING
) {
336 struct ovsdb_datum datum
;
337 struct ovsdb_error
*error
;
340 error
= ovsdb_datum_from_json(&datum
, cell
->type
, cell
->json
,
344 ovsdb_datum_to_string(&datum
, cell
->type
, &s
);
345 ovsdb_datum_destroy(&datum
, cell
->type
);
346 cell
->text
= ds_steal_cstr(&s
);
348 cell
->text
= json_to_string(cell
->json
, JSSF_SORT
);
354 cell
->text
= xstrdup("");
362 cell_destroy(struct cell
*cell
)
365 json_destroy(cell
->json
);
370 struct column
*columns
;
371 size_t n_columns
, allocated_columns
;
372 size_t n_rows
, allocated_rows
;
373 size_t current_column
;
378 table_init(struct table
*table
)
380 memset(table
, 0, sizeof *table
);
384 table_destroy(struct table
*table
)
388 for (i
= 0; i
< table
->n_columns
; i
++) {
389 free(table
->columns
[i
].heading
);
391 free(table
->columns
);
393 for (i
= 0; i
< table
->n_columns
* table
->n_rows
; i
++) {
394 cell_destroy(&table
->cells
[i
]);
398 free(table
->caption
);
402 table_set_caption(struct table
*table
, char *caption
)
404 free(table
->caption
);
405 table
->caption
= caption
;
409 table_add_column(struct table
*table
, const char *heading
, ...)
413 table_add_column(struct table
*table
, const char *heading
, ...)
415 struct column
*column
;
418 assert(!table
->n_rows
);
419 if (table
->n_columns
>= table
->allocated_columns
) {
420 table
->columns
= x2nrealloc(table
->columns
, &table
->allocated_columns
,
421 sizeof *table
->columns
);
423 column
= &table
->columns
[table
->n_columns
++];
425 va_start(args
, heading
);
426 column
->heading
= xvasprintf(heading
, args
);
431 table_cell__(const struct table
*table
, size_t row
, size_t column
)
433 return &table
->cells
[column
+ row
* table
->n_columns
];
437 table_add_row(struct table
*table
)
441 if (table
->n_rows
>= table
->allocated_rows
) {
442 table
->cells
= x2nrealloc(table
->cells
, &table
->allocated_rows
,
443 table
->n_columns
* sizeof *table
->cells
);
447 table
->current_column
= 0;
448 for (x
= 0; x
< table
->n_columns
; x
++) {
449 struct cell
*cell
= table_cell__(table
, y
, x
);
450 memset(cell
, 0, sizeof *cell
);
455 table_add_cell(struct table
*table
)
459 assert(table
->n_rows
> 0);
460 assert(table
->current_column
< table
->n_columns
);
462 x
= table
->current_column
++;
463 y
= table
->n_rows
- 1;
465 return table_cell__(table
, y
, x
);
469 table_print_table_line__(struct ds
*line
)
476 table_print_table__(const struct table
*table
)
479 struct ds line
= DS_EMPTY_INITIALIZER
;
487 if (table
->caption
) {
488 puts(table
->caption
);
491 widths
= xmalloc(table
->n_columns
* sizeof *widths
);
492 for (x
= 0; x
< table
->n_columns
; x
++) {
493 const struct column
*column
= &table
->columns
[x
];
495 widths
[x
] = strlen(column
->heading
);
496 for (y
= 0; y
< table
->n_rows
; y
++) {
497 const char *text
= cell_to_text(table_cell__(table
, y
, x
));
498 size_t length
= strlen(text
);
500 if (length
> widths
[x
])
505 if (output_headings
) {
506 for (x
= 0; x
< table
->n_columns
; x
++) {
507 const struct column
*column
= &table
->columns
[x
];
509 ds_put_char(&line
, ' ');
511 ds_put_format(&line
, "%-*s", widths
[x
], column
->heading
);
513 table_print_table_line__(&line
);
515 for (x
= 0; x
< table
->n_columns
; x
++) {
517 ds_put_char(&line
, ' ');
519 ds_put_char_multiple(&line
, '-', widths
[x
]);
521 table_print_table_line__(&line
);
524 for (y
= 0; y
< table
->n_rows
; y
++) {
525 for (x
= 0; x
< table
->n_columns
; x
++) {
526 const char *text
= cell_to_text(table_cell__(table
, y
, x
));
528 ds_put_char(&line
, ' ');
530 ds_put_format(&line
, "%-*s", widths
[x
], text
);
532 table_print_table_line__(&line
);
540 table_escape_html_text__(const char *s
, size_t n
)
544 for (i
= 0; i
< n
; i
++) {
549 fputs("&", stdout
);
552 fputs("<", stdout
);
555 fputs(">", stdout
);
558 fputs(""", stdout
);
568 table_print_html_cell__(const char *element
, const char *content
)
572 printf(" <%s>", element
);
573 for (p
= content
; *p
; ) {
576 if (uuid_from_string_prefix(&uuid
, p
)) {
577 printf("<a href=\"#%.*s\">%.*s</a>", UUID_LEN
, p
, 8, p
);
580 table_escape_html_text__(p
, 1);
584 printf("</%s>\n", element
);
588 table_print_html__(const struct table
*table
)
592 fputs("<table border=1>\n", stdout
);
594 if (table
->caption
) {
595 table_print_html_cell__("caption", table
->caption
);
598 if (output_headings
) {
599 fputs(" <tr>\n", stdout
);
600 for (x
= 0; x
< table
->n_columns
; x
++) {
601 const struct column
*column
= &table
->columns
[x
];
602 table_print_html_cell__("th", column
->heading
);
604 fputs(" </tr>\n", stdout
);
607 for (y
= 0; y
< table
->n_rows
; y
++) {
608 fputs(" <tr>\n", stdout
);
609 for (x
= 0; x
< table
->n_columns
; x
++) {
610 const char *content
= cell_to_text(table_cell__(table
, y
, x
));
612 if (!strcmp(table
->columns
[x
].heading
, "_uuid")) {
613 fputs(" <td><a name=\"", stdout
);
614 table_escape_html_text__(content
, strlen(content
));
615 fputs("\">", stdout
);
616 table_escape_html_text__(content
, 8);
617 fputs("</a></td>\n", stdout
);
619 table_print_html_cell__("td", content
);
622 fputs(" </tr>\n", stdout
);
625 fputs("</table>\n", stdout
);
629 table_print_csv_cell__(const char *content
)
633 if (!strpbrk(content
, "\n\",")) {
634 fputs(content
, stdout
);
637 for (p
= content
; *p
!= '\0'; p
++) {
640 fputs("\"\"", stdout
);
652 table_print_csv__(const struct table
*table
)
661 if (table
->caption
) {
662 puts(table
->caption
);
665 if (output_headings
) {
666 for (x
= 0; x
< table
->n_columns
; x
++) {
667 const struct column
*column
= &table
->columns
[x
];
671 table_print_csv_cell__(column
->heading
);
676 for (y
= 0; y
< table
->n_rows
; y
++) {
677 for (x
= 0; x
< table
->n_columns
; x
++) {
681 table_print_csv_cell__(cell_to_text(table_cell__(table
, y
, x
)));
688 table_print_json__(const struct table
*table
)
690 struct json
*json
, *headings
, *data
;
694 json
= json_object_create();
695 if (table
->caption
) {
696 json_object_put_string(json
, "caption", table
->caption
);
699 headings
= json_array_create_empty();
700 for (x
= 0; x
< table
->n_columns
; x
++) {
701 const struct column
*column
= &table
->columns
[x
];
702 json_array_add(headings
, json_string_create(column
->heading
));
704 json_object_put(json
, "headings", headings
);
706 data
= json_array_create_empty();
707 for (y
= 0; y
< table
->n_rows
; y
++) {
708 struct json
*row
= json_array_create_empty();
709 for (x
= 0; x
< table
->n_columns
; x
++) {
710 const struct cell
*cell
= table_cell__(table
, y
, x
);
712 json_array_add(row
, json_string_create(cell
->text
));
714 json_array_add(row
, json_clone(cell
->json
));
717 json_array_add(data
, row
);
719 json_object_put(json
, "data", data
);
721 s
= json_to_string(json
, json_flags
);
728 table_print(const struct table
*table
)
730 switch (output_format
) {
732 table_print_table__(table
);
736 table_print_html__(table
);
740 table_print_csv__(table
);
744 table_print_json__(table
);
750 do_list_dbs(int argc OVS_UNUSED
, char *argv
[])
752 struct jsonrpc_msg
*request
, *reply
;
757 rpc
= open_jsonrpc(argv
[1]);
758 request
= jsonrpc_create_request("list_dbs", json_array_create_empty(),
760 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
762 ovs_fatal(error
, "transaction failed");
765 if (reply
->result
->type
!= JSON_ARRAY
) {
766 ovs_fatal(0, "list_dbs response is not array");
769 for (i
= 0; i
< reply
->result
->u
.array
.n
; i
++) {
770 const struct json
*name
= reply
->result
->u
.array
.elems
[i
];
772 if (name
->type
!= JSON_STRING
) {
773 ovs_fatal(0, "list_dbs response %zu is not string", i
);
775 puts(name
->u
.string
);
777 jsonrpc_msg_destroy(reply
);
781 do_get_schema(int argc OVS_UNUSED
, char *argv
[])
783 struct ovsdb_schema
*schema
= fetch_schema(argv
[1], argv
[2]);
784 print_and_free_json(ovsdb_schema_to_json(schema
));
785 ovsdb_schema_destroy(schema
);
789 do_get_schema_version(int argc OVS_UNUSED
, char *argv
[])
791 struct ovsdb_schema
*schema
= fetch_schema(argv
[1], argv
[2]);
792 puts(schema
->version
);
793 ovsdb_schema_destroy(schema
);
797 do_list_tables(int argc OVS_UNUSED
, char *argv
[])
799 struct ovsdb_schema
*schema
;
800 struct shash_node
*node
;
803 schema
= fetch_schema(argv
[1], argv
[2]);
805 table_add_column(&t
, "Table");
806 SHASH_FOR_EACH (node
, &schema
->tables
) {
807 struct ovsdb_table_schema
*ts
= node
->data
;
810 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
812 ovsdb_schema_destroy(schema
);
817 do_list_columns(int argc OVS_UNUSED
, char *argv
[])
819 const char *table_name
= argv
[3];
820 struct ovsdb_schema
*schema
;
821 struct shash_node
*table_node
;
824 schema
= fetch_schema(argv
[1], argv
[2]);
827 table_add_column(&t
, "Table");
829 table_add_column(&t
, "Column");
830 table_add_column(&t
, "Type");
831 SHASH_FOR_EACH (table_node
, &schema
->tables
) {
832 struct ovsdb_table_schema
*ts
= table_node
->data
;
834 if (!table_name
|| !strcmp(table_name
, ts
->name
)) {
835 struct shash_node
*column_node
;
837 SHASH_FOR_EACH (column_node
, &ts
->columns
) {
838 const struct ovsdb_column
*column
= column_node
->data
;
842 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
844 table_add_cell(&t
)->text
= xstrdup(column
->name
);
845 table_add_cell(&t
)->json
= ovsdb_type_to_json(&column
->type
);
849 ovsdb_schema_destroy(schema
);
854 do_transact(int argc OVS_UNUSED
, char *argv
[])
856 struct jsonrpc_msg
*request
, *reply
;
857 struct json
*transaction
;
861 transaction
= parse_json(argv
[2]);
863 rpc
= open_jsonrpc(argv
[1]);
864 request
= jsonrpc_create_request("transact", transaction
, NULL
);
865 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
867 ovs_fatal(error
, "transaction failed");
870 ovs_fatal(error
, "transaction returned error: %s",
871 json_to_string(reply
->error
, json_flags
));
873 print_json(reply
->result
);
875 jsonrpc_msg_destroy(reply
);
880 monitor_print_row(struct json
*row
, const char *type
, const char *uuid
,
881 const struct ovsdb_column_set
*columns
, struct table
*t
)
886 ovs_error(0, "missing %s row", type
);
888 } else if (row
->type
!= JSON_OBJECT
) {
889 ovs_error(0, "<row> is not object");
894 table_add_cell(t
)->text
= xstrdup(uuid
);
895 table_add_cell(t
)->text
= xstrdup(type
);
896 for (i
= 0; i
< columns
->n_columns
; i
++) {
897 const struct ovsdb_column
*column
= columns
->columns
[i
];
898 struct json
*value
= shash_find_data(json_object(row
), column
->name
);
899 struct cell
*cell
= table_add_cell(t
);
901 cell
->json
= json_clone(value
);
902 cell
->type
= &column
->type
;
908 monitor_print(struct json
*table_updates
,
909 const struct ovsdb_table_schema
*table
,
910 const struct ovsdb_column_set
*columns
, bool initial
)
912 struct json
*table_update
;
913 struct shash_node
*node
;
919 if (table_updates
->type
!= JSON_OBJECT
) {
920 ovs_error(0, "<table-updates> is not object");
923 table_update
= shash_find_data(json_object(table_updates
), table
->name
);
927 if (table_update
->type
!= JSON_OBJECT
) {
928 ovs_error(0, "<table-update> is not object");
932 table_add_column(&t
, "row");
933 table_add_column(&t
, "action");
934 for (i
= 0; i
< columns
->n_columns
; i
++) {
935 table_add_column(&t
, "%s", columns
->columns
[i
]->name
);
937 SHASH_FOR_EACH (node
, json_object(table_update
)) {
938 struct json
*row_update
= node
->data
;
939 struct json
*old
, *new;
941 if (row_update
->type
!= JSON_OBJECT
) {
942 ovs_error(0, "<row-update> is not object");
945 old
= shash_find_data(json_object(row_update
), "old");
946 new = shash_find_data(json_object(row_update
), "new");
948 monitor_print_row(new, "initial", node
->name
, columns
, &t
);
950 monitor_print_row(new, "insert", node
->name
, columns
, &t
);
952 monitor_print_row(old
, "delete", node
->name
, columns
, &t
);
954 monitor_print_row(old
, "old", node
->name
, columns
, &t
);
955 monitor_print_row(new, "new", "", columns
, &t
);
963 add_column(const char *server
, const struct ovsdb_column
*column
,
964 struct ovsdb_column_set
*columns
, struct json
*columns_json
)
966 if (ovsdb_column_set_contains(columns
, column
->index
)) {
967 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
968 server
, column
->name
);
970 ovsdb_column_set_add(columns
, column
);
971 json_array_add(columns_json
, json_string_create(column
->name
));
975 parse_monitor_columns(char *arg
, const char *server
, const char *database
,
976 const struct ovsdb_table_schema
*table
,
977 struct ovsdb_column_set
*columns
)
979 bool initial
, insert
, delete, modify
;
980 struct json
*mr
, *columns_json
;
981 char *save_ptr
= NULL
;
984 mr
= json_object_create();
985 columns_json
= json_array_create_empty();
986 json_object_put(mr
, "columns", columns_json
);
988 initial
= insert
= delete = modify
= true;
989 for (token
= strtok_r(arg
, ",", &save_ptr
); token
!= NULL
;
990 token
= strtok_r(NULL
, ",", &save_ptr
)) {
991 if (!strcmp(token
, "!initial")) {
993 } else if (!strcmp(token
, "!insert")) {
995 } else if (!strcmp(token
, "!delete")) {
997 } else if (!strcmp(token
, "!modify")) {
1000 const struct ovsdb_column
*column
;
1002 column
= ovsdb_table_schema_get_column(table
, token
);
1004 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
1005 "column named \"%s\"",
1006 server
, table
->name
, database
, token
);
1008 add_column(server
, column
, columns
, columns_json
);
1012 if (columns_json
->u
.array
.n
== 0) {
1013 const struct shash_node
**nodes
;
1016 n
= shash_count(&table
->columns
);
1017 nodes
= shash_sort(&table
->columns
);
1018 for (i
= 0; i
< n
; i
++) {
1019 const struct ovsdb_column
*column
= nodes
[i
]->data
;
1020 if (column
->index
!= OVSDB_COL_UUID
1021 && column
->index
!= OVSDB_COL_VERSION
) {
1022 add_column(server
, column
, columns
, columns_json
);
1027 add_column(server
, ovsdb_table_schema_get_column(table
,"_version"),
1028 columns
, columns_json
);
1031 if (!initial
|| !insert
|| !delete || !modify
) {
1032 struct json
*select
= json_object_create();
1033 json_object_put(select
, "initial", json_boolean_create(initial
));
1034 json_object_put(select
, "insert", json_boolean_create(insert
));
1035 json_object_put(select
, "delete", json_boolean_create(delete));
1036 json_object_put(select
, "modify", json_boolean_create(modify
));
1037 json_object_put(mr
, "select", select
);
1044 do_monitor(int argc
, char *argv
[])
1046 const char *server
= argv
[1];
1047 const char *database
= argv
[2];
1048 const char *table_name
= argv
[3];
1049 struct ovsdb_column_set columns
= OVSDB_COLUMN_SET_INITIALIZER
;
1050 struct ovsdb_table_schema
*table
;
1051 struct ovsdb_schema
*schema
;
1052 struct jsonrpc_msg
*request
;
1053 struct jsonrpc
*rpc
;
1054 struct json
*monitor
, *monitor_request_array
,
1055 *monitor_requests
, *request_id
;
1057 rpc
= open_jsonrpc(server
);
1059 schema
= fetch_schema_from_rpc(rpc
, database
);
1060 table
= shash_find_data(&schema
->tables
, table_name
);
1062 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
1063 server
, database
, table_name
);
1066 monitor_request_array
= json_array_create_empty();
1070 for (i
= 4; i
< argc
; i
++) {
1072 monitor_request_array
,
1073 parse_monitor_columns(argv
[i
], server
, database
, table
,
1077 /* Allocate a writable empty string since parse_monitor_columns() is
1078 * going to strtok() it and that's risky with literal "". */
1081 monitor_request_array
,
1082 parse_monitor_columns(empty
, server
, database
, table
, &columns
));
1085 monitor_requests
= json_object_create();
1086 json_object_put(monitor_requests
, table_name
, monitor_request_array
);
1088 monitor
= json_array_create_3(json_string_create(database
),
1089 json_null_create(), monitor_requests
);
1090 request
= jsonrpc_create_request("monitor", monitor
, NULL
);
1091 request_id
= json_clone(request
->id
);
1092 jsonrpc_send(rpc
, request
);
1094 struct jsonrpc_msg
*msg
;
1097 error
= jsonrpc_recv_block(rpc
, &msg
);
1099 ovsdb_schema_destroy(schema
);
1100 ovs_fatal(error
, "%s: receive failed", server
);
1103 if (msg
->type
== JSONRPC_REQUEST
&& !strcmp(msg
->method
, "echo")) {
1104 jsonrpc_send(rpc
, jsonrpc_create_reply(json_clone(msg
->params
),
1106 } else if (msg
->type
== JSONRPC_REPLY
1107 && json_equal(msg
->id
, request_id
)) {
1108 monitor_print(msg
->result
, table
, &columns
, true);
1111 /* daemonize() closes the standard file descriptors. We output
1112 * to stdout, so we need to save and restore STDOUT_FILENO. */
1113 int fd
= dup(STDOUT_FILENO
);
1115 dup2(fd
, STDOUT_FILENO
);
1118 } else if (msg
->type
== JSONRPC_NOTIFY
1119 && !strcmp(msg
->method
, "update")) {
1120 struct json
*params
= msg
->params
;
1121 if (params
->type
== JSON_ARRAY
1122 && params
->u
.array
.n
== 2
1123 && params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
1124 monitor_print(params
->u
.array
.elems
[1],
1125 table
, &columns
, false);
1129 jsonrpc_msg_destroy(msg
);
1133 struct dump_table_aux
{
1134 struct ovsdb_datum
**data
;
1135 const struct ovsdb_column
**columns
;
1140 compare_data(size_t a_y
, size_t b_y
, size_t x
,
1141 const struct dump_table_aux
*aux
)
1143 return ovsdb_datum_compare_3way(&aux
->data
[a_y
][x
],
1145 &aux
->columns
[x
]->type
);
1149 compare_rows(size_t a_y
, size_t b_y
, void *aux_
)
1151 struct dump_table_aux
*aux
= aux_
;
1154 /* Skip UUID columns on the first pass, since their values tend to be
1155 * random and make our results less reproducible. */
1156 for (x
= 0; x
< aux
->n_columns
; x
++) {
1157 if (aux
->columns
[x
]->type
.key
.type
!= OVSDB_TYPE_UUID
) {
1158 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
1165 /* Use UUID columns as tie-breakers. */
1166 for (x
= 0; x
< aux
->n_columns
; x
++) {
1167 if (aux
->columns
[x
]->type
.key
.type
== OVSDB_TYPE_UUID
) {
1168 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
1179 swap_rows(size_t a_y
, size_t b_y
, void *aux_
)
1181 struct dump_table_aux
*aux
= aux_
;
1182 struct ovsdb_datum
*tmp
= aux
->data
[a_y
];
1183 aux
->data
[a_y
] = aux
->data
[b_y
];
1184 aux
->data
[b_y
] = tmp
;
1188 compare_columns(const void *a_
, const void *b_
)
1190 const struct ovsdb_column
*const *ap
= a_
;
1191 const struct ovsdb_column
*const *bp
= b_
;
1192 const struct ovsdb_column
*a
= *ap
;
1193 const struct ovsdb_column
*b
= *bp
;
1195 return strcmp(a
->name
, b
->name
);
1199 dump_table(const struct ovsdb_table_schema
*ts
, struct json_array
*rows
)
1201 const struct ovsdb_column
**columns
;
1204 struct ovsdb_datum
**data
;
1206 struct dump_table_aux aux
;
1207 struct shash_node
*node
;
1211 /* Sort columns by name, for reproducibility. */
1212 columns
= xmalloc(shash_count(&ts
->columns
) * sizeof *columns
);
1214 SHASH_FOR_EACH (node
, &ts
->columns
) {
1215 struct ovsdb_column
*column
= node
->data
;
1216 if (strcmp(column
->name
, "_version")) {
1217 columns
[n_columns
++] = column
;
1220 qsort(columns
, n_columns
, sizeof *columns
, compare_columns
);
1222 /* Extract data from table. */
1223 data
= xmalloc(rows
->n
* sizeof *data
);
1224 for (y
= 0; y
< rows
->n
; y
++) {
1227 if (rows
->elems
[y
]->type
!= JSON_OBJECT
) {
1228 ovs_fatal(0, "row %zu in table %s response is not a JSON object: "
1229 "%s", y
, ts
->name
, json_to_string(rows
->elems
[y
], 0));
1231 row
= json_object(rows
->elems
[y
]);
1233 data
[y
] = xmalloc(n_columns
* sizeof **data
);
1234 for (x
= 0; x
< n_columns
; x
++) {
1235 const struct json
*json
= shash_find_data(row
, columns
[x
]->name
);
1237 ovs_fatal(0, "row %zu in table %s response lacks %s column",
1238 y
, ts
->name
, columns
[x
]->name
);
1241 check_ovsdb_error(ovsdb_datum_from_json(&data
[y
][x
],
1247 /* Sort rows by column values, for reproducibility. */
1249 aux
.columns
= columns
;
1250 aux
.n_columns
= n_columns
;
1251 sort(rows
->n
, compare_rows
, swap_rows
, &aux
);
1253 /* Add column headings. */
1255 table_set_caption(&t
, xasprintf("%s table", ts
->name
));
1256 for (x
= 0; x
< n_columns
; x
++) {
1257 table_add_column(&t
, "%s", columns
[x
]->name
);
1261 for (y
= 0; y
< rows
->n
; y
++) {
1263 for (x
= 0; x
< n_columns
; x
++) {
1264 struct cell
*cell
= table_add_cell(&t
);
1265 cell
->json
= ovsdb_datum_to_json(&data
[y
][x
], &columns
[x
]->type
);
1266 cell
->type
= &columns
[x
]->type
;
1274 do_dump(int argc OVS_UNUSED
, char *argv
[])
1276 const char *server
= argv
[1];
1277 const char *database
= argv
[2];
1279 struct jsonrpc_msg
*request
, *reply
;
1280 struct ovsdb_schema
*schema
;
1281 struct json
*transaction
;
1282 struct jsonrpc
*rpc
;
1285 const struct shash_node
**tables
;
1290 rpc
= open_jsonrpc(server
);
1292 schema
= fetch_schema_from_rpc(rpc
, database
);
1293 tables
= shash_sort(&schema
->tables
);
1294 n_tables
= shash_count(&schema
->tables
);
1296 /* Construct transaction to retrieve entire database. */
1297 transaction
= json_array_create_1(json_string_create(database
));
1298 for (i
= 0; i
< n_tables
; i
++) {
1299 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1300 struct json
*op
, *columns
;
1301 struct shash_node
*node
;
1303 columns
= json_array_create_empty();
1304 SHASH_FOR_EACH (node
, &ts
->columns
) {
1305 const struct ovsdb_column
*column
= node
->data
;
1307 if (strcmp(column
->name
, "_version")) {
1308 json_array_add(columns
, json_string_create(column
->name
));
1312 op
= json_object_create();
1313 json_object_put_string(op
, "op", "select");
1314 json_object_put_string(op
, "table", tables
[i
]->name
);
1315 json_object_put(op
, "where", json_array_create_empty());
1316 json_object_put(op
, "columns", columns
);
1317 json_array_add(transaction
, op
);
1320 /* Send request, get reply. */
1321 request
= jsonrpc_create_request("transact", transaction
, NULL
);
1322 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
1324 ovs_fatal(error
, "transaction failed");
1327 /* Print database contents. */
1328 if (reply
->result
->type
!= JSON_ARRAY
1329 || reply
->result
->u
.array
.n
!= n_tables
) {
1330 ovs_fatal(0, "reply is not array of %zu elements: %s",
1331 n_tables
, json_to_string(reply
->result
, 0));
1333 for (i
= 0; i
< n_tables
; i
++) {
1334 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1335 const struct json
*op_result
= reply
->result
->u
.array
.elems
[i
];
1338 if (op_result
->type
!= JSON_OBJECT
1339 || !(rows
= shash_find_data(json_object(op_result
), "rows"))
1340 || rows
->type
!= JSON_ARRAY
) {
1341 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1343 ts
->name
, json_to_string(op_result
, 0));
1346 dump_table(ts
, &rows
->u
.array
);
1351 do_help(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1356 static const struct command all_commands
[] = {
1357 { "list-dbs", 1, 1, do_list_dbs
},
1358 { "get-schema", 2, 2, do_get_schema
},
1359 { "get-schema-version", 2, 2, do_get_schema_version
},
1360 { "list-tables", 2, 2, do_list_tables
},
1361 { "list-columns", 2, 3, do_list_columns
},
1362 { "transact", 2, 2, do_transact
},
1363 { "monitor", 3, INT_MAX
, do_monitor
},
1364 { "dump", 2, 2, do_dump
},
1365 { "help", 0, INT_MAX
, do_help
},
1366 { NULL
, 0, 0, NULL
},