2 * Copyright (c) 2009, 2010, 2011 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.
29 #include "command-line.h"
34 #include "dynamic-string.h"
37 #include "lib/table.h"
39 #include "ovsdb-data.h"
40 #include "ovsdb-error.h"
44 #include "stream-ssl.h"
50 VLOG_DEFINE_THIS_MODULE(ovsdb_client
);
53 NEED_NONE
, /* No JSON-RPC connection or database name needed. */
54 NEED_RPC
, /* JSON-RPC connection needed. */
55 NEED_DATABASE
/* JSON-RPC connection and database name needed. */
58 struct ovsdb_client_command
{
60 enum args_needed need
;
63 void (*handler
)(struct jsonrpc
*rpc
, const char *database
,
64 int argc
, char *argv
[]);
67 /* --timestamp: Print a timestamp before each update on "monitor" command? */
68 static bool timestamp
;
70 /* Format for table output. */
71 static struct table_style table_style
= TABLE_STYLE_DEFAULT
;
73 static const struct ovsdb_client_command all_commands
[];
75 static void usage(void) NO_RETURN
;
76 static void parse_options(int argc
, char *argv
[]);
77 static struct jsonrpc
*open_jsonrpc(const char *server
);
78 static void fetch_dbs(struct jsonrpc
*, struct sset
*dbs
);
81 main(int argc
, char *argv
[])
83 const struct ovsdb_client_command
*command
;
87 proctitle_init(argc
, argv
);
88 set_program_name(argv
[0]);
89 parse_options(argc
, argv
);
90 signal(SIGPIPE
, SIG_IGN
);
93 ovs_fatal(0, "missing command name; use --help for help");
96 for (command
= all_commands
; ; command
++) {
98 VLOG_FATAL("unknown command '%s'; use --help for help",
100 } else if (!strcmp(command
->name
, argv
[optind
])) {
106 if (command
->need
!= NEED_NONE
) {
107 if (argc
- optind
> command
->min_args
108 && (isalpha((unsigned char) argv
[optind
][0])
109 && strchr(argv
[optind
], ':'))) {
110 rpc
= open_jsonrpc(argv
[optind
++]);
112 char *sock
= xasprintf("unix:%s/db.sock", ovs_rundir());
113 rpc
= open_jsonrpc(sock
);
120 if (command
->need
== NEED_DATABASE
) {
124 fetch_dbs(rpc
, &dbs
);
125 if (argc
- optind
> command
->min_args
126 && sset_contains(&dbs
, argv
[optind
])) {
127 database
= argv
[optind
++];
128 } else if (sset_count(&dbs
) == 1) {
129 database
= xstrdup(SSET_FIRST(&dbs
));
130 } else if (sset_contains(&dbs
, "Open_vSwitch")) {
131 database
= "Open_vSwitch";
133 ovs_fatal(0, "no default database for `%s' command, please "
134 "specify a database name", command
->name
);
141 if (argc
- optind
< command
->min_args
||
142 argc
- optind
> command
->max_args
) {
143 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
147 command
->handler(rpc
, database
, argc
- optind
, argv
+ optind
);
151 if (ferror(stdout
)) {
152 VLOG_FATAL("write to stdout failed");
154 if (ferror(stderr
)) {
155 VLOG_FATAL("write to stderr failed");
162 parse_options(int argc
, char *argv
[])
165 OPT_BOOTSTRAP_CA_CERT
= UCHAR_MAX
+ 1,
170 static struct option long_options
[] = {
171 {"verbose", optional_argument
, NULL
, 'v'},
172 {"help", no_argument
, NULL
, 'h'},
173 {"version", no_argument
, NULL
, 'V'},
174 {"timestamp", no_argument
, NULL
, OPT_TIMESTAMP
},
177 {"bootstrap-ca-cert", required_argument
, NULL
, OPT_BOOTSTRAP_CA_CERT
},
178 STREAM_SSL_LONG_OPTIONS
,
183 char *short_options
= long_options_to_short_options(long_options
);
188 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
198 ovs_print_version(0, 0);
202 vlog_set_verbosity(optarg
);
205 DAEMON_OPTION_HANDLERS
207 TABLE_OPTION_HANDLERS(&table_style
)
209 STREAM_SSL_OPTION_HANDLERS
211 case OPT_BOOTSTRAP_CA_CERT
:
212 stream_ssl_set_ca_cert_file(optarg
, true);
223 /* getopt_long() already set the value for us. */
236 printf("%s: Open vSwitch database JSON-RPC client\n"
237 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
238 "\nValid commands are:\n"
239 "\n list-dbs [SERVER]\n"
240 " list databases available on SERVER\n"
241 "\n get-schema [SERVER] [DATABASE]\n"
242 " retrieve schema for DATABASE from SERVER\n"
243 "\n get-schema-version [SERVER] [DATABASE]\n"
244 " retrieve schema for DATABASE from SERVER and report only its\n"
245 " version number on stdout\n"
246 "\n list-tables [SERVER] [DATABASE]\n"
247 " list tables for DATABASE on SERVER\n"
248 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
249 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
250 "\n transact [SERVER] TRANSACTION\n"
251 " run TRANSACTION (a JSON array of operations) on SERVER\n"
252 " and print the results as JSON on stdout\n"
253 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
254 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
255 " COLUMNs may include !initial, !insert, !delete, !modify\n"
256 " to avoid seeing the specified kinds of changes.\n"
257 "\n dump [SERVER] [DATABASE]\n"
258 " dump contents of DATABASE on SERVER to stdout\n"
259 "\nThe default SERVER is unix:%s/db.sock.\n"
260 "The default DATABASE is Open_vSwitch.\n",
261 program_name
, program_name
, ovs_rundir());
262 stream_usage("SERVER", true, true, true);
263 printf("\nOutput formatting options:\n"
264 " -f, --format=FORMAT set output formatting to FORMAT\n"
265 " (\"table\", \"html\", \"csv\", "
267 " --no-headings omit table heading row\n"
268 " --pretty pretty-print JSON in output\n"
269 " --timestamp timestamp \"monitor\" output");
272 printf("\nOther options:\n"
273 " -h, --help display this help message\n"
274 " -V, --version display version information\n");
279 parse_json(const char *s
)
281 struct json
*json
= json_from_string(s
);
282 if (json
->type
== JSON_STRING
) {
283 ovs_fatal(0, "\"%s\": %s", s
, json
->u
.string
);
288 static struct jsonrpc
*
289 open_jsonrpc(const char *server
)
291 struct stream
*stream
;
294 error
= stream_open_block(jsonrpc_stream_open(server
, &stream
), &stream
);
295 if (error
== EAFNOSUPPORT
) {
296 struct pstream
*pstream
;
298 error
= jsonrpc_pstream_open(server
, &pstream
);
300 ovs_fatal(error
, "failed to connect or listen to \"%s\"", server
);
303 VLOG_INFO("%s: waiting for connection...", server
);
304 error
= pstream_accept_block(pstream
, &stream
);
306 ovs_fatal(error
, "failed to accept connection on \"%s\"", server
);
309 pstream_close(pstream
);
311 ovs_fatal(error
, "failed to connect to \"%s\"", server
);
314 return jsonrpc_open(stream
);
318 print_json(struct json
*json
)
320 char *string
= json_to_string(json
, table_style
.json_flags
);
321 fputs(string
, stdout
);
326 print_and_free_json(struct json
*json
)
333 check_ovsdb_error(struct ovsdb_error
*error
)
336 ovs_fatal(0, "%s", ovsdb_error_to_string(error
));
340 static struct ovsdb_schema
*
341 fetch_schema(struct jsonrpc
*rpc
, const char *database
)
343 struct jsonrpc_msg
*request
, *reply
;
344 struct ovsdb_schema
*schema
;
347 request
= jsonrpc_create_request("get_schema",
349 json_string_create(database
)),
351 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
353 ovs_fatal(error
, "transaction failed");
355 check_ovsdb_error(ovsdb_schema_from_json(reply
->result
, &schema
));
356 jsonrpc_msg_destroy(reply
);
362 fetch_dbs(struct jsonrpc
*rpc
, struct sset
*dbs
)
364 struct jsonrpc_msg
*request
, *reply
;
368 request
= jsonrpc_create_request("list_dbs", json_array_create_empty(),
370 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
372 ovs_fatal(error
, "transaction failed");
375 if (reply
->result
->type
!= JSON_ARRAY
) {
376 ovs_fatal(0, "list_dbs response is not array");
379 for (i
= 0; i
< reply
->result
->u
.array
.n
; i
++) {
380 const struct json
*name
= reply
->result
->u
.array
.elems
[i
];
382 if (name
->type
!= JSON_STRING
) {
383 ovs_fatal(0, "list_dbs response %zu is not string", i
);
385 sset_add(dbs
, name
->u
.string
);
387 jsonrpc_msg_destroy(reply
);
391 do_list_dbs(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
392 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
398 fetch_dbs(rpc
, &dbs
);
399 SSET_FOR_EACH (db_name
, &dbs
) {
406 do_get_schema(struct jsonrpc
*rpc
, const char *database
,
407 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
409 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
410 print_and_free_json(ovsdb_schema_to_json(schema
));
411 ovsdb_schema_destroy(schema
);
415 do_get_schema_version(struct jsonrpc
*rpc
, const char *database
,
416 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
418 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
419 puts(schema
->version
);
420 ovsdb_schema_destroy(schema
);
424 do_list_tables(struct jsonrpc
*rpc
, const char *database
,
425 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
427 struct ovsdb_schema
*schema
;
428 struct shash_node
*node
;
431 schema
= fetch_schema(rpc
, database
);
433 table_add_column(&t
, "Table");
434 SHASH_FOR_EACH (node
, &schema
->tables
) {
435 struct ovsdb_table_schema
*ts
= node
->data
;
438 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
440 ovsdb_schema_destroy(schema
);
441 table_print(&t
, &table_style
);
445 do_list_columns(struct jsonrpc
*rpc
, const char *database
,
446 int argc OVS_UNUSED
, char *argv
[])
448 const char *table_name
= argv
[0];
449 struct ovsdb_schema
*schema
;
450 struct shash_node
*table_node
;
453 schema
= fetch_schema(rpc
, database
);
456 table_add_column(&t
, "Table");
458 table_add_column(&t
, "Column");
459 table_add_column(&t
, "Type");
460 SHASH_FOR_EACH (table_node
, &schema
->tables
) {
461 struct ovsdb_table_schema
*ts
= table_node
->data
;
463 if (!table_name
|| !strcmp(table_name
, ts
->name
)) {
464 struct shash_node
*column_node
;
466 SHASH_FOR_EACH (column_node
, &ts
->columns
) {
467 const struct ovsdb_column
*column
= column_node
->data
;
471 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
473 table_add_cell(&t
)->text
= xstrdup(column
->name
);
474 table_add_cell(&t
)->json
= ovsdb_type_to_json(&column
->type
);
478 ovsdb_schema_destroy(schema
);
479 table_print(&t
, &table_style
);
483 do_transact(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
484 int argc OVS_UNUSED
, char *argv
[])
486 struct jsonrpc_msg
*request
, *reply
;
487 struct json
*transaction
;
490 transaction
= parse_json(argv
[0]);
492 request
= jsonrpc_create_request("transact", transaction
, NULL
);
493 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
495 ovs_fatal(error
, "transaction failed");
498 ovs_fatal(error
, "transaction returned error: %s",
499 json_to_string(reply
->error
, table_style
.json_flags
));
501 print_json(reply
->result
);
503 jsonrpc_msg_destroy(reply
);
507 monitor_print_row(struct json
*row
, const char *type
, const char *uuid
,
508 const struct ovsdb_column_set
*columns
, struct table
*t
)
513 ovs_error(0, "missing %s row", type
);
515 } else if (row
->type
!= JSON_OBJECT
) {
516 ovs_error(0, "<row> is not object");
521 table_add_cell(t
)->text
= xstrdup(uuid
);
522 table_add_cell(t
)->text
= xstrdup(type
);
523 for (i
= 0; i
< columns
->n_columns
; i
++) {
524 const struct ovsdb_column
*column
= columns
->columns
[i
];
525 struct json
*value
= shash_find_data(json_object(row
), column
->name
);
526 struct cell
*cell
= table_add_cell(t
);
528 cell
->json
= json_clone(value
);
529 cell
->type
= &column
->type
;
535 monitor_print(struct json
*table_updates
,
536 const struct ovsdb_table_schema
*table
,
537 const struct ovsdb_column_set
*columns
, bool initial
)
539 struct json
*table_update
;
540 struct shash_node
*node
;
545 table_set_timestamp(&t
, timestamp
);
547 if (table_updates
->type
!= JSON_OBJECT
) {
548 ovs_error(0, "<table-updates> is not object");
551 table_update
= shash_find_data(json_object(table_updates
), table
->name
);
555 if (table_update
->type
!= JSON_OBJECT
) {
556 ovs_error(0, "<table-update> is not object");
560 table_add_column(&t
, "row");
561 table_add_column(&t
, "action");
562 for (i
= 0; i
< columns
->n_columns
; i
++) {
563 table_add_column(&t
, "%s", columns
->columns
[i
]->name
);
565 SHASH_FOR_EACH (node
, json_object(table_update
)) {
566 struct json
*row_update
= node
->data
;
567 struct json
*old
, *new;
569 if (row_update
->type
!= JSON_OBJECT
) {
570 ovs_error(0, "<row-update> is not object");
573 old
= shash_find_data(json_object(row_update
), "old");
574 new = shash_find_data(json_object(row_update
), "new");
576 monitor_print_row(new, "initial", node
->name
, columns
, &t
);
578 monitor_print_row(new, "insert", node
->name
, columns
, &t
);
580 monitor_print_row(old
, "delete", node
->name
, columns
, &t
);
582 monitor_print_row(old
, "old", node
->name
, columns
, &t
);
583 monitor_print_row(new, "new", "", columns
, &t
);
586 table_print(&t
, &table_style
);
591 add_column(const char *server
, const struct ovsdb_column
*column
,
592 struct ovsdb_column_set
*columns
, struct json
*columns_json
)
594 if (ovsdb_column_set_contains(columns
, column
->index
)) {
595 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
596 server
, column
->name
);
598 ovsdb_column_set_add(columns
, column
);
599 json_array_add(columns_json
, json_string_create(column
->name
));
603 parse_monitor_columns(char *arg
, const char *server
, const char *database
,
604 const struct ovsdb_table_schema
*table
,
605 struct ovsdb_column_set
*columns
)
607 bool initial
, insert
, delete, modify
;
608 struct json
*mr
, *columns_json
;
609 char *save_ptr
= NULL
;
612 mr
= json_object_create();
613 columns_json
= json_array_create_empty();
614 json_object_put(mr
, "columns", columns_json
);
616 initial
= insert
= delete = modify
= true;
617 for (token
= strtok_r(arg
, ",", &save_ptr
); token
!= NULL
;
618 token
= strtok_r(NULL
, ",", &save_ptr
)) {
619 if (!strcmp(token
, "!initial")) {
621 } else if (!strcmp(token
, "!insert")) {
623 } else if (!strcmp(token
, "!delete")) {
625 } else if (!strcmp(token
, "!modify")) {
628 const struct ovsdb_column
*column
;
630 column
= ovsdb_table_schema_get_column(table
, token
);
632 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
633 "column named \"%s\"",
634 server
, table
->name
, database
, token
);
636 add_column(server
, column
, columns
, columns_json
);
640 if (columns_json
->u
.array
.n
== 0) {
641 const struct shash_node
**nodes
;
644 n
= shash_count(&table
->columns
);
645 nodes
= shash_sort(&table
->columns
);
646 for (i
= 0; i
< n
; i
++) {
647 const struct ovsdb_column
*column
= nodes
[i
]->data
;
648 if (column
->index
!= OVSDB_COL_UUID
649 && column
->index
!= OVSDB_COL_VERSION
) {
650 add_column(server
, column
, columns
, columns_json
);
655 add_column(server
, ovsdb_table_schema_get_column(table
,"_version"),
656 columns
, columns_json
);
659 if (!initial
|| !insert
|| !delete || !modify
) {
660 struct json
*select
= json_object_create();
661 json_object_put(select
, "initial", json_boolean_create(initial
));
662 json_object_put(select
, "insert", json_boolean_create(insert
));
663 json_object_put(select
, "delete", json_boolean_create(delete));
664 json_object_put(select
, "modify", json_boolean_create(modify
));
665 json_object_put(mr
, "select", select
);
672 do_monitor(struct jsonrpc
*rpc
, const char *database
,
673 int argc
, char *argv
[])
675 const char *server
= jsonrpc_get_name(rpc
);
676 const char *table_name
= argv
[0];
677 struct ovsdb_column_set columns
= OVSDB_COLUMN_SET_INITIALIZER
;
678 struct ovsdb_table_schema
*table
;
679 struct ovsdb_schema
*schema
;
680 struct jsonrpc_msg
*request
;
681 struct json
*monitor
, *monitor_request_array
,
682 *monitor_requests
, *request_id
;
684 schema
= fetch_schema(rpc
, database
);
685 table
= shash_find_data(&schema
->tables
, table_name
);
687 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
688 server
, database
, table_name
);
691 monitor_request_array
= json_array_create_empty();
695 for (i
= 1; i
< argc
; i
++) {
697 monitor_request_array
,
698 parse_monitor_columns(argv
[i
], server
, database
, table
,
702 /* Allocate a writable empty string since parse_monitor_columns() is
703 * going to strtok() it and that's risky with literal "". */
706 monitor_request_array
,
707 parse_monitor_columns(empty
, server
, database
, table
, &columns
));
710 monitor_requests
= json_object_create();
711 json_object_put(monitor_requests
, table_name
, monitor_request_array
);
713 monitor
= json_array_create_3(json_string_create(database
),
714 json_null_create(), monitor_requests
);
715 request
= jsonrpc_create_request("monitor", monitor
, NULL
);
716 request_id
= json_clone(request
->id
);
717 jsonrpc_send(rpc
, request
);
719 struct jsonrpc_msg
*msg
;
722 error
= jsonrpc_recv_block(rpc
, &msg
);
724 ovsdb_schema_destroy(schema
);
725 ovs_fatal(error
, "%s: receive failed", server
);
728 if (msg
->type
== JSONRPC_REQUEST
&& !strcmp(msg
->method
, "echo")) {
729 jsonrpc_send(rpc
, jsonrpc_create_reply(json_clone(msg
->params
),
731 } else if (msg
->type
== JSONRPC_REPLY
732 && json_equal(msg
->id
, request_id
)) {
733 monitor_print(msg
->result
, table
, &columns
, true);
736 /* daemonize() closes the standard file descriptors. We output
737 * to stdout, so we need to save and restore STDOUT_FILENO. */
738 int fd
= dup(STDOUT_FILENO
);
740 dup2(fd
, STDOUT_FILENO
);
743 } else if (msg
->type
== JSONRPC_NOTIFY
744 && !strcmp(msg
->method
, "update")) {
745 struct json
*params
= msg
->params
;
746 if (params
->type
== JSON_ARRAY
747 && params
->u
.array
.n
== 2
748 && params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
749 monitor_print(params
->u
.array
.elems
[1],
750 table
, &columns
, false);
754 jsonrpc_msg_destroy(msg
);
758 struct dump_table_aux
{
759 struct ovsdb_datum
**data
;
760 const struct ovsdb_column
**columns
;
765 compare_data(size_t a_y
, size_t b_y
, size_t x
,
766 const struct dump_table_aux
*aux
)
768 return ovsdb_datum_compare_3way(&aux
->data
[a_y
][x
],
770 &aux
->columns
[x
]->type
);
774 compare_rows(size_t a_y
, size_t b_y
, void *aux_
)
776 struct dump_table_aux
*aux
= aux_
;
779 /* Skip UUID columns on the first pass, since their values tend to be
780 * random and make our results less reproducible. */
781 for (x
= 0; x
< aux
->n_columns
; x
++) {
782 if (aux
->columns
[x
]->type
.key
.type
!= OVSDB_TYPE_UUID
) {
783 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
790 /* Use UUID columns as tie-breakers. */
791 for (x
= 0; x
< aux
->n_columns
; x
++) {
792 if (aux
->columns
[x
]->type
.key
.type
== OVSDB_TYPE_UUID
) {
793 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
804 swap_rows(size_t a_y
, size_t b_y
, void *aux_
)
806 struct dump_table_aux
*aux
= aux_
;
807 struct ovsdb_datum
*tmp
= aux
->data
[a_y
];
808 aux
->data
[a_y
] = aux
->data
[b_y
];
809 aux
->data
[b_y
] = tmp
;
813 compare_columns(const void *a_
, const void *b_
)
815 const struct ovsdb_column
*const *ap
= a_
;
816 const struct ovsdb_column
*const *bp
= b_
;
817 const struct ovsdb_column
*a
= *ap
;
818 const struct ovsdb_column
*b
= *bp
;
820 return strcmp(a
->name
, b
->name
);
824 dump_table(const struct ovsdb_table_schema
*ts
, struct json_array
*rows
)
826 const struct ovsdb_column
**columns
;
829 struct ovsdb_datum
**data
;
831 struct dump_table_aux aux
;
832 struct shash_node
*node
;
836 /* Sort columns by name, for reproducibility. */
837 columns
= xmalloc(shash_count(&ts
->columns
) * sizeof *columns
);
839 SHASH_FOR_EACH (node
, &ts
->columns
) {
840 struct ovsdb_column
*column
= node
->data
;
841 if (strcmp(column
->name
, "_version")) {
842 columns
[n_columns
++] = column
;
845 qsort(columns
, n_columns
, sizeof *columns
, compare_columns
);
847 /* Extract data from table. */
848 data
= xmalloc(rows
->n
* sizeof *data
);
849 for (y
= 0; y
< rows
->n
; y
++) {
852 if (rows
->elems
[y
]->type
!= JSON_OBJECT
) {
853 ovs_fatal(0, "row %zu in table %s response is not a JSON object: "
854 "%s", y
, ts
->name
, json_to_string(rows
->elems
[y
], 0));
856 row
= json_object(rows
->elems
[y
]);
858 data
[y
] = xmalloc(n_columns
* sizeof **data
);
859 for (x
= 0; x
< n_columns
; x
++) {
860 const struct json
*json
= shash_find_data(row
, columns
[x
]->name
);
862 ovs_fatal(0, "row %zu in table %s response lacks %s column",
863 y
, ts
->name
, columns
[x
]->name
);
866 check_ovsdb_error(ovsdb_datum_from_json(&data
[y
][x
],
872 /* Sort rows by column values, for reproducibility. */
874 aux
.columns
= columns
;
875 aux
.n_columns
= n_columns
;
876 sort(rows
->n
, compare_rows
, swap_rows
, &aux
);
878 /* Add column headings. */
880 table_set_caption(&t
, xasprintf("%s table", ts
->name
));
881 for (x
= 0; x
< n_columns
; x
++) {
882 table_add_column(&t
, "%s", columns
[x
]->name
);
886 for (y
= 0; y
< rows
->n
; y
++) {
888 for (x
= 0; x
< n_columns
; x
++) {
889 struct cell
*cell
= table_add_cell(&t
);
890 cell
->json
= ovsdb_datum_to_json(&data
[y
][x
], &columns
[x
]->type
);
891 cell
->type
= &columns
[x
]->type
;
894 table_print(&t
, &table_style
);
899 do_dump(struct jsonrpc
*rpc
, const char *database
,
900 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
902 struct jsonrpc_msg
*request
, *reply
;
903 struct ovsdb_schema
*schema
;
904 struct json
*transaction
;
907 const struct shash_node
**tables
;
912 schema
= fetch_schema(rpc
, database
);
913 tables
= shash_sort(&schema
->tables
);
914 n_tables
= shash_count(&schema
->tables
);
916 /* Construct transaction to retrieve entire database. */
917 transaction
= json_array_create_1(json_string_create(database
));
918 for (i
= 0; i
< n_tables
; i
++) {
919 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
920 struct json
*op
, *columns
;
921 struct shash_node
*node
;
923 columns
= json_array_create_empty();
924 SHASH_FOR_EACH (node
, &ts
->columns
) {
925 const struct ovsdb_column
*column
= node
->data
;
927 if (strcmp(column
->name
, "_version")) {
928 json_array_add(columns
, json_string_create(column
->name
));
932 op
= json_object_create();
933 json_object_put_string(op
, "op", "select");
934 json_object_put_string(op
, "table", tables
[i
]->name
);
935 json_object_put(op
, "where", json_array_create_empty());
936 json_object_put(op
, "columns", columns
);
937 json_array_add(transaction
, op
);
940 /* Send request, get reply. */
941 request
= jsonrpc_create_request("transact", transaction
, NULL
);
942 error
= jsonrpc_transact_block(rpc
, request
, &reply
);
944 ovs_fatal(error
, "transaction failed");
947 /* Print database contents. */
948 if (reply
->result
->type
!= JSON_ARRAY
949 || reply
->result
->u
.array
.n
!= n_tables
) {
950 ovs_fatal(0, "reply is not array of %zu elements: %s",
951 n_tables
, json_to_string(reply
->result
, 0));
953 for (i
= 0; i
< n_tables
; i
++) {
954 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
955 const struct json
*op_result
= reply
->result
->u
.array
.elems
[i
];
958 if (op_result
->type
!= JSON_OBJECT
959 || !(rows
= shash_find_data(json_object(op_result
), "rows"))
960 || rows
->type
!= JSON_ARRAY
) {
961 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
963 ts
->name
, json_to_string(op_result
, 0));
966 dump_table(ts
, &rows
->u
.array
);
971 do_help(struct jsonrpc
*rpc OVS_UNUSED
, const char *database OVS_UNUSED
,
972 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
977 /* All command handlers (except for "help") are expected to take an optional
978 * server socket name (e.g. "unix:...") as their first argument. The socket
979 * name argument must be included in max_args (but left out of min_args). The
980 * command name and socket name are not included in the arguments passed to the
981 * handler: the argv[0] passed to the handler is the first argument after the
982 * optional server socket name. The connection to the server is available as
983 * global variable 'rpc'. */
984 static const struct ovsdb_client_command all_commands
[] = {
985 { "list-dbs", NEED_RPC
, 0, 0, do_list_dbs
},
986 { "get-schema", NEED_DATABASE
, 0, 0, do_get_schema
},
987 { "get-schema-version", NEED_DATABASE
, 0, 0, do_get_schema_version
},
988 { "list-tables", NEED_DATABASE
, 0, 0, do_list_tables
},
989 { "list-columns", NEED_DATABASE
, 0, 1, do_list_columns
},
990 { "transact", NEED_RPC
, 1, 1, do_transact
},
991 { "monitor", NEED_DATABASE
, 1, INT_MAX
, do_monitor
},
992 { "dump", NEED_DATABASE
, 0, 0, do_dump
},
994 { "help", NEED_NONE
, 0, INT_MAX
, do_help
},
996 { NULL
, 0, 0, 0, NULL
},