2 * Copyright (c) 2009-2017 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 "openvswitch/dynamic-string.h"
34 #include "fatal-signal.h"
36 #include "openvswitch/json.h"
38 #include "lib/table.h"
41 #include "ovsdb-data.h"
42 #include "ovsdb-error.h"
43 #include "openvswitch/poll-loop.h"
48 #include "stream-ssl.h"
51 #include "condition.h"
55 #include "openvswitch/vlog.h"
57 VLOG_DEFINE_THIS_MODULE(ovsdb_client
);
60 NEED_NONE
, /* No JSON-RPC connection or database name needed. */
61 NEED_RPC
, /* JSON-RPC connection needed. */
62 NEED_DATABASE
/* JSON-RPC connection and database name needed. */
65 struct ovsdb_client_command
{
67 enum args_needed need
;
70 void (*handler
)(struct jsonrpc
*rpc
, const char *database
,
71 int argc
, char *argv
[]);
74 /* --timestamp: Print a timestamp before each update on "monitor" command? */
75 static bool timestamp
;
77 /* --force: Ignore schema differences for "restore" command? */
80 /* Format for table output. */
81 static struct table_style table_style
= TABLE_STYLE_DEFAULT
;
83 static const struct ovsdb_client_command
*get_all_commands(void);
85 OVS_NO_RETURN
static void usage(void);
86 static void parse_options(int argc
, char *argv
[]);
87 static struct jsonrpc
*open_jsonrpc(const char *server
);
88 static void fetch_dbs(struct jsonrpc
*, struct svec
*dbs
);
91 main(int argc
, char *argv
[])
93 const struct ovsdb_client_command
*command
;
97 ovs_cmdl_proctitle_init(argc
, argv
);
98 set_program_name(argv
[0]);
99 service_start(&argc
, &argv
);
100 parse_options(argc
, argv
);
101 fatal_ignore_sigpipe();
103 daemon_become_new_user(false);
104 if (optind
>= argc
) {
105 ovs_fatal(0, "missing command name; use --help for help");
108 for (command
= get_all_commands(); ; command
++) {
109 if (!command
->name
) {
110 VLOG_FATAL("unknown command '%s'; use --help for help",
112 } else if (!strcmp(command
->name
, argv
[optind
])) {
118 if (command
->need
!= NEED_NONE
) {
119 if (argc
- optind
> command
->min_args
120 && (isalpha((unsigned char) argv
[optind
][0])
121 && strchr(argv
[optind
], ':'))) {
122 rpc
= open_jsonrpc(argv
[optind
++]);
124 char *sock
= xasprintf("unix:%s/db.sock", ovs_rundir());
125 rpc
= open_jsonrpc(sock
);
132 if (command
->need
== NEED_DATABASE
) {
136 fetch_dbs(rpc
, &dbs
);
137 if (argc
- optind
> command
->min_args
138 && svec_contains(&dbs
, argv
[optind
])) {
139 database
= xstrdup(argv
[optind
++]);
140 } else if (svec_contains(&dbs
, "Open_vSwitch")) {
141 database
= xstrdup("Open_vSwitch");
144 const char *best
= NULL
;
145 for (size_t i
= 0; i
< dbs
.n
; i
++) {
146 if (dbs
.names
[i
][0] != '_') {
153 ovs_fatal(0, "no default database for `%s' command, please "
154 "specify a database name", command
->name
);
156 database
= xstrdup(best
);
163 if (argc
- optind
< command
->min_args
||
164 argc
- optind
> command
->max_args
) {
166 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
170 command
->handler(rpc
, database
, argc
- optind
, argv
+ optind
);
175 if (ferror(stdout
)) {
176 VLOG_FATAL("write to stdout failed");
178 if (ferror(stderr
)) {
179 VLOG_FATAL("write to stderr failed");
186 parse_options(int argc
, char *argv
[])
189 OPT_BOOTSTRAP_CA_CERT
= UCHAR_MAX
+ 1,
197 static const struct option long_options
[] = {
198 {"help", no_argument
, NULL
, 'h'},
199 {"version", no_argument
, NULL
, 'V'},
200 {"timestamp", no_argument
, NULL
, OPT_TIMESTAMP
},
201 {"force", no_argument
, NULL
, OPT_FORCE
},
205 {"bootstrap-ca-cert", required_argument
, NULL
, OPT_BOOTSTRAP_CA_CERT
},
206 STREAM_SSL_LONG_OPTIONS
,
211 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
213 table_style
.format
= TF_TABLE
;
218 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
228 ovs_print_version(0, 0);
232 DAEMON_OPTION_HANDLERS
233 TABLE_OPTION_HANDLERS(&table_style
)
234 STREAM_SSL_OPTION_HANDLERS
236 case OPT_BOOTSTRAP_CA_CERT
:
237 stream_ssl_set_ca_cert_file(optarg
, true);
252 /* getopt_long() already set the value for us. */
265 printf("%s: Open vSwitch database JSON-RPC client\n"
266 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
267 "\nValid commands are:\n"
268 "\n list-dbs [SERVER]\n"
269 " list databases available on SERVER\n"
270 "\n get-schema [SERVER] [DATABASE]\n"
271 " retrieve schema for DATABASE from SERVER\n"
272 "\n get-schema-version [SERVER] [DATABASE]\n"
273 " retrieve schema for DATABASE from SERVER and report only its\n"
274 " version number on stdout\n"
275 "\n get-schema-cksum [SERVER] [DATABASE]\n"
276 " retrieve schema for DATABASE from SERVER and report only its\n"
277 " checksum on stdout\n"
278 "\n list-tables [SERVER] [DATABASE]\n"
279 " list tables for DATABASE on SERVER\n"
280 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
281 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
282 "\n transact [SERVER] TRANSACTION\n"
283 " run TRANSACTION (params for \"transact\" request) on SERVER\n"
284 " and print the results as JSON on stdout\n"
285 "\n query [SERVER] TRANSACTION\n"
286 " run TRANSACTION (params for \"transact\" request) on SERVER,\n"
287 " as read-only, and print the results as JSON on stdout\n"
288 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
289 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
290 " COLUMNs may include !initial, !insert, !delete, !modify\n"
291 " to avoid seeing the specified kinds of changes.\n"
292 "\n monitor-cond [SERVER] [DATABASE] CONDITION TABLE [COLUMN,...]...\n"
293 " monitor contents that match CONDITION of COLUMNs in TABLE in\n"
294 " DATABASE on SERVER.\n"
295 " COLUMNs may include !initial, !insert, !delete, !modify\n"
296 " to avoid seeing the specified kinds of changes.\n"
297 "\n monitor [SERVER] [DATABASE] ALL\n"
298 " monitor all changes to all columns in all tables\n"
299 " in DATBASE on SERVER.\n"
300 "\n dump [SERVER] [DATABASE]\n"
301 " dump contents of DATABASE on SERVER to stdout\n"
302 "\n backup [SERVER] [DATABASE] > SNAPSHOT\n"
303 " dump database contents in the form of a database file\n"
304 "\n [--force] restore [SERVER] [DATABASE] < SNAPSHOT\n"
305 " restore database contents from a database file\n"
306 "\n lock [SERVER] LOCK\n"
307 " create or wait for LOCK in SERVER\n"
308 "\n steal [SERVER] LOCK\n"
309 " steal LOCK from SERVER\n"
310 "\n unlock [SERVER] LOCK\n"
311 " unlock LOCK from SERVER\n"
312 "\nThe default SERVER is unix:%s/db.sock.\n"
313 "The default DATABASE is Open_vSwitch.\n",
314 program_name
, program_name
, ovs_rundir());
315 stream_usage("SERVER", true, true, true);
317 printf(" --timestamp timestamp \"monitor\" output");
320 printf("\nOther options:\n"
321 " -h, --help display this help message\n"
322 " -V, --version display version information\n");
327 check_txn(int error
, struct jsonrpc_msg
**reply_
)
329 struct jsonrpc_msg
*reply
= *reply_
;
332 ovs_fatal(error
, "transaction failed");
336 ovs_fatal(error
, "transaction returned error: %s",
337 json_to_string(reply
->error
, table_style
.json_flags
));
342 parse_json(const char *s
)
344 struct json
*json
= json_from_string(s
);
345 if (json
->type
== JSON_STRING
) {
346 ovs_fatal(0, "\"%s\": %s", s
, json
->u
.string
);
351 static struct jsonrpc
*
352 open_jsonrpc(const char *server
)
354 struct stream
*stream
;
357 error
= stream_open_block(jsonrpc_stream_open(server
, &stream
,
358 DSCP_DEFAULT
), &stream
);
359 if (error
== EAFNOSUPPORT
) {
360 struct pstream
*pstream
;
362 error
= jsonrpc_pstream_open(server
, &pstream
, DSCP_DEFAULT
);
364 ovs_fatal(error
, "failed to connect or listen to \"%s\"", server
);
367 VLOG_INFO("%s: waiting for connection...", server
);
368 error
= pstream_accept_block(pstream
, &stream
);
370 ovs_fatal(error
, "failed to accept connection on \"%s\"", server
);
373 pstream_close(pstream
);
375 ovs_fatal(error
, "failed to connect to \"%s\"", server
);
378 return jsonrpc_open(stream
);
382 print_json(struct json
*json
)
384 char *string
= json_to_string(json
, table_style
.json_flags
);
390 print_and_free_json(struct json
*json
)
397 check_ovsdb_error(struct ovsdb_error
*error
)
400 ovs_fatal(0, "%s", ovsdb_error_to_string(error
));
404 static struct ovsdb_schema
*
405 fetch_schema(struct jsonrpc
*rpc
, const char *database
)
407 struct jsonrpc_msg
*request
, *reply
;
408 struct ovsdb_schema
*schema
;
410 request
= jsonrpc_create_request("get_schema",
412 json_string_create(database
)),
414 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
415 check_ovsdb_error(ovsdb_schema_from_json(reply
->result
, &schema
));
416 jsonrpc_msg_destroy(reply
);
422 fetch_dbs(struct jsonrpc
*rpc
, struct svec
*dbs
)
424 struct jsonrpc_msg
*request
, *reply
;
427 request
= jsonrpc_create_request("list_dbs", json_array_create_empty(),
430 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
431 if (reply
->result
->type
!= JSON_ARRAY
) {
432 ovs_fatal(0, "list_dbs response is not array");
435 for (i
= 0; i
< reply
->result
->u
.array
.n
; i
++) {
436 const struct json
*name
= reply
->result
->u
.array
.elems
[i
];
438 if (name
->type
!= JSON_STRING
) {
439 ovs_fatal(0, "list_dbs response %"PRIuSIZE
" is not string", i
);
441 svec_add(dbs
, name
->u
.string
);
443 jsonrpc_msg_destroy(reply
);
448 do_list_dbs(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
449 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
456 fetch_dbs(rpc
, &dbs
);
457 SVEC_FOR_EACH (i
, db_name
, &dbs
) {
464 do_get_schema(struct jsonrpc
*rpc
, const char *database
,
465 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
467 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
468 print_and_free_json(ovsdb_schema_to_json(schema
));
469 ovsdb_schema_destroy(schema
);
473 do_get_schema_version(struct jsonrpc
*rpc
, const char *database
,
474 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
476 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
477 puts(schema
->version
);
478 ovsdb_schema_destroy(schema
);
482 do_get_schema_cksum(struct jsonrpc
*rpc
, const char *database
,
483 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
485 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
487 ovsdb_schema_destroy(schema
);
491 do_list_tables(struct jsonrpc
*rpc
, const char *database
,
492 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
494 struct ovsdb_schema
*schema
;
495 struct shash_node
*node
;
498 schema
= fetch_schema(rpc
, database
);
500 table_add_column(&t
, "Table");
501 SHASH_FOR_EACH (node
, &schema
->tables
) {
502 struct ovsdb_table_schema
*ts
= node
->data
;
505 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
507 ovsdb_schema_destroy(schema
);
508 table_print(&t
, &table_style
);
513 do_list_columns(struct jsonrpc
*rpc
, const char *database
,
514 int argc OVS_UNUSED
, char *argv
[])
516 const char *table_name
= argv
[0];
517 struct ovsdb_schema
*schema
;
518 struct shash_node
*table_node
;
521 schema
= fetch_schema(rpc
, database
);
524 table_add_column(&t
, "Table");
526 table_add_column(&t
, "Column");
527 table_add_column(&t
, "Type");
528 SHASH_FOR_EACH (table_node
, &schema
->tables
) {
529 struct ovsdb_table_schema
*ts
= table_node
->data
;
531 if (!table_name
|| !strcmp(table_name
, ts
->name
)) {
532 struct shash_node
*column_node
;
534 SHASH_FOR_EACH (column_node
, &ts
->columns
) {
535 const struct ovsdb_column
*column
= column_node
->data
;
539 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
541 table_add_cell(&t
)->text
= xstrdup(column
->name
);
542 table_add_cell(&t
)->json
= ovsdb_type_to_json(&column
->type
);
546 ovsdb_schema_destroy(schema
);
547 table_print(&t
, &table_style
);
552 do_transact__(struct jsonrpc
*rpc
, struct json
*transaction
)
554 struct jsonrpc_msg
*request
, *reply
;
556 request
= jsonrpc_create_request("transact", transaction
, NULL
);
557 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
558 struct json
*result
= json_clone(reply
->result
);
559 jsonrpc_msg_destroy(reply
);
565 do_transact(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
566 int argc OVS_UNUSED
, char *argv
[])
568 print_and_free_json(do_transact__(rpc
, parse_json(argv
[0])));
572 do_query(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
573 int argc OVS_UNUSED
, char *argv
[])
575 struct json
*transaction
= parse_json(argv
[0]);
577 if (transaction
->type
!= JSON_ARRAY
) {
578 ovs_fatal(0, "not a valid OVSDB query");
581 /* Append an "abort" operation to the query. */
582 struct json
*abort_op
= json_object_create();
583 json_object_put_string(abort_op
, "op", "abort");
584 json_array_add(transaction
, abort_op
);
585 size_t abort_idx
= transaction
->u
.array
.n
- 2;
588 struct json
*result
= do_transact__(rpc
, transaction
);
590 /* If the "abort" operation ended the transaction, remove its result. */
591 if (result
->type
== JSON_ARRAY
592 && result
->u
.array
.n
== abort_idx
+ 1
593 && result
->u
.array
.elems
[abort_idx
]->type
== JSON_OBJECT
) {
594 struct json
*op_result
= result
->u
.array
.elems
[abort_idx
];
595 struct json
*error
= shash_find_data(json_object(op_result
), "error");
597 && error
->type
== JSON_STRING
598 && !strcmp(json_string(error
), "aborted")) {
600 json_destroy(op_result
);
604 /* Print the result. */
605 print_and_free_json(result
);
608 /* "monitor" command. */
610 struct monitored_table
{
611 struct ovsdb_table_schema
*table
;
612 struct ovsdb_column_set columns
;
616 monitor_print_row(struct json
*row
, const char *type
, const char *uuid
,
617 const struct ovsdb_column_set
*columns
, struct table
*t
)
622 ovs_error(0, "missing %s row", type
);
624 } else if (row
->type
!= JSON_OBJECT
) {
625 ovs_error(0, "<row> is not object");
630 table_add_cell(t
)->text
= xstrdup(uuid
);
631 table_add_cell(t
)->text
= xstrdup(type
);
632 for (i
= 0; i
< columns
->n_columns
; i
++) {
633 const struct ovsdb_column
*column
= columns
->columns
[i
];
634 struct json
*value
= shash_find_data(json_object(row
), column
->name
);
635 struct cell
*cell
= table_add_cell(t
);
637 cell
->json
= json_clone(value
);
638 cell
->type
= &column
->type
;
644 monitor_print_table(struct json
*table_update
,
645 const struct monitored_table
*mt
, char *caption
,
648 const struct ovsdb_table_schema
*table
= mt
->table
;
649 const struct ovsdb_column_set
*columns
= &mt
->columns
;
650 struct shash_node
*node
;
654 if (table_update
->type
!= JSON_OBJECT
) {
655 ovs_error(0, "<table-update> for table %s is not object", table
->name
);
660 table_set_timestamp(&t
, timestamp
);
661 table_set_caption(&t
, caption
);
663 table_add_column(&t
, "row");
664 table_add_column(&t
, "action");
665 for (i
= 0; i
< columns
->n_columns
; i
++) {
666 table_add_column(&t
, "%s", columns
->columns
[i
]->name
);
668 SHASH_FOR_EACH (node
, json_object(table_update
)) {
669 struct json
*row_update
= node
->data
;
670 struct json
*old
, *new;
672 if (row_update
->type
!= JSON_OBJECT
) {
673 ovs_error(0, "<row-update> is not object");
676 old
= shash_find_data(json_object(row_update
), "old");
677 new = shash_find_data(json_object(row_update
), "new");
679 monitor_print_row(new, "initial", node
->name
, columns
, &t
);
681 monitor_print_row(new, "insert", node
->name
, columns
, &t
);
683 monitor_print_row(old
, "delete", node
->name
, columns
, &t
);
685 monitor_print_row(old
, "old", node
->name
, columns
, &t
);
686 monitor_print_row(new, "new", "", columns
, &t
);
689 table_print(&t
, &table_style
);
694 monitor_print(struct json
*table_updates
,
695 const struct monitored_table
*mts
, size_t n_mts
,
700 if (table_updates
->type
!= JSON_OBJECT
) {
701 ovs_error(0, "<table-updates> is not object");
705 for (i
= 0; i
< n_mts
; i
++) {
706 const struct monitored_table
*mt
= &mts
[i
];
707 struct json
*table_update
= shash_find_data(json_object(table_updates
),
710 monitor_print_table(table_update
, mt
,
711 n_mts
> 1 ? xstrdup(mt
->table
->name
) : NULL
,
718 monitor2_print_row(struct json
*row
, const char *type
, const char *uuid
,
719 const struct ovsdb_column_set
*columns
, struct table
*t
)
721 if (!strcmp(type
, "delete")) {
722 if (row
->type
!= JSON_NULL
) {
723 ovs_error(0, "delete method does not expect <row>");
728 table_add_cell(t
)->text
= xstrdup(uuid
);
729 table_add_cell(t
)->text
= xstrdup(type
);
731 if (!row
|| row
->type
!= JSON_OBJECT
) {
732 ovs_error(0, "<row> is not object");
735 monitor_print_row(row
, type
, uuid
, columns
, t
);
740 monitor2_print_table(struct json
*table_update2
,
741 const struct monitored_table
*mt
, char *caption
)
743 const struct ovsdb_table_schema
*table
= mt
->table
;
744 const struct ovsdb_column_set
*columns
= &mt
->columns
;
745 struct shash_node
*node
;
748 if (table_update2
->type
!= JSON_OBJECT
) {
749 ovs_error(0, "<table-update> for table %s is not object", table
->name
);
754 table_set_timestamp(&t
, timestamp
);
755 table_set_caption(&t
, caption
);
757 table_add_column(&t
, "row");
758 table_add_column(&t
, "action");
759 for (size_t i
= 0; i
< columns
->n_columns
; i
++) {
760 table_add_column(&t
, "%s", columns
->columns
[i
]->name
);
762 SHASH_FOR_EACH (node
, json_object(table_update2
)) {
763 struct json
*row_update2
= node
->data
;
764 const char *operation
;
766 const char *ops
[] = {"delete", "initial", "modify", "insert"};
768 if (row_update2
->type
!= JSON_OBJECT
) {
769 ovs_error(0, "<row-update2> is not object");
773 /* row_update2 contains one of objects indexed by ops[] */
774 for (int i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
776 row
= shash_find_data(json_object(row_update2
), operation
);
779 monitor2_print_row(row
, operation
, node
->name
, columns
, &t
);
784 table_print(&t
, &table_style
);
789 monitor2_print(struct json
*table_updates2
,
790 const struct monitored_table
*mts
, size_t n_mts
)
794 if (table_updates2
->type
!= JSON_OBJECT
) {
795 ovs_error(0, "<table-updates2> is not object");
799 for (i
= 0; i
< n_mts
; i
++) {
800 const struct monitored_table
*mt
= &mts
[i
];
801 struct json
*table_update
= shash_find_data(
802 json_object(table_updates2
),
805 monitor2_print_table(table_update
, mt
,
806 n_mts
> 1 ? xstrdup(mt
->table
->name
) : NULL
);
812 add_column(const char *server
, const struct ovsdb_column
*column
,
813 struct ovsdb_column_set
*columns
, struct json
*columns_json
)
815 if (ovsdb_column_set_contains(columns
, column
->index
)) {
816 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
817 server
, column
->name
);
819 ovsdb_column_set_add(columns
, column
);
820 json_array_add(columns_json
, json_string_create(column
->name
));
824 parse_monitor_columns(char *arg
, const char *server
, const char *database
,
825 const struct ovsdb_table_schema
*table
,
826 struct ovsdb_column_set
*columns
)
828 bool initial
, insert
, delete, modify
;
829 struct json
*mr
, *columns_json
;
830 char *save_ptr
= NULL
;
833 mr
= json_object_create();
834 columns_json
= json_array_create_empty();
835 json_object_put(mr
, "columns", columns_json
);
837 initial
= insert
= delete = modify
= true;
838 for (token
= strtok_r(arg
, ",", &save_ptr
); token
!= NULL
;
839 token
= strtok_r(NULL
, ",", &save_ptr
)) {
840 if (!strcmp(token
, "!initial")) {
842 } else if (!strcmp(token
, "!insert")) {
844 } else if (!strcmp(token
, "!delete")) {
846 } else if (!strcmp(token
, "!modify")) {
849 const struct ovsdb_column
*column
;
851 column
= ovsdb_table_schema_get_column(table
, token
);
853 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
854 "column named \"%s\"",
855 server
, table
->name
, database
, token
);
857 add_column(server
, column
, columns
, columns_json
);
861 if (columns_json
->u
.array
.n
== 0) {
862 const struct shash_node
**nodes
;
865 n
= shash_count(&table
->columns
);
866 nodes
= shash_sort(&table
->columns
);
867 for (i
= 0; i
< n
; i
++) {
868 const struct ovsdb_column
*column
= nodes
[i
]->data
;
869 if (column
->index
!= OVSDB_COL_UUID
870 && column
->index
!= OVSDB_COL_VERSION
) {
871 add_column(server
, column
, columns
, columns_json
);
876 add_column(server
, ovsdb_table_schema_get_column(table
, "_version"),
877 columns
, columns_json
);
880 if (!initial
|| !insert
|| !delete || !modify
) {
881 struct json
*select
= json_object_create();
882 json_object_put(select
, "initial", json_boolean_create(initial
));
883 json_object_put(select
, "insert", json_boolean_create(insert
));
884 json_object_put(select
, "delete", json_boolean_create(delete));
885 json_object_put(select
, "modify", json_boolean_create(modify
));
886 json_object_put(mr
, "select", select
);
893 ovsdb_client_exit(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
894 const char *argv
[] OVS_UNUSED
, void *exiting_
)
896 bool *exiting
= exiting_
;
898 unixctl_command_reply(conn
, NULL
);
902 ovsdb_client_block(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
903 const char *argv
[] OVS_UNUSED
, void *blocked_
)
905 bool *blocked
= blocked_
;
909 unixctl_command_reply(conn
, NULL
);
911 unixctl_command_reply(conn
, "already blocking");
916 ovsdb_client_unblock(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
917 const char *argv
[] OVS_UNUSED
, void *blocked_
)
919 bool *blocked
= blocked_
;
923 unixctl_command_reply(conn
, NULL
);
925 unixctl_command_reply(conn
, "already unblocked");
930 ovsdb_client_cond_change(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
931 const char *argv
[], void *rpc_
)
933 struct jsonrpc
*rpc
= rpc_
;
934 struct json
*monitor_cond_update_requests
= json_object_create();
935 struct json
*monitor_cond_update_request
= json_object_create();
937 struct jsonrpc_msg
*request
;
939 json_object_put(monitor_cond_update_request
, "where",
940 json_from_string(argv
[2]));
941 json_object_put(monitor_cond_update_requests
,
943 json_array_create_1(monitor_cond_update_request
));
945 params
= json_array_create_3(json_null_create(),json_null_create(),
946 monitor_cond_update_requests
);
948 request
= jsonrpc_create_request("monitor_cond_change", params
, NULL
);
949 jsonrpc_send(rpc
, request
);
951 VLOG_DBG("cond change %s %s", argv
[1], argv
[2]);
952 unixctl_command_reply(conn
, "condiiton changed");
956 add_monitored_table(int argc
, char *argv
[],
957 const char *server
, const char *database
,
958 struct json
*condition
,
959 struct ovsdb_table_schema
*table
,
960 struct json
*monitor_requests
,
961 struct monitored_table
**mts
,
962 size_t *n_mts
, size_t *allocated_mts
)
964 struct json
*monitor_request_array
, *mr
;
965 struct monitored_table
*mt
;
967 if (*n_mts
>= *allocated_mts
) {
968 *mts
= x2nrealloc(*mts
, allocated_mts
, sizeof **mts
);
970 mt
= &(*mts
)[(*n_mts
)++];
972 ovsdb_column_set_init(&mt
->columns
);
974 monitor_request_array
= json_array_create_empty();
978 for (i
= 1; i
< argc
; i
++) {
979 mr
= parse_monitor_columns(argv
[i
], server
, database
, table
,
981 if (i
== 1 && condition
) {
982 json_object_put(mr
, "where", condition
);
984 json_array_add(monitor_request_array
, mr
);
987 /* Allocate a writable empty string since parse_monitor_columns()
988 * is going to strtok() it and that's risky with literal "". */
991 mr
= parse_monitor_columns(empty
, server
, database
,
992 table
, &mt
->columns
);
994 json_object_put(mr
, "where", condition
);
996 json_array_add(monitor_request_array
, mr
);
999 json_object_put(monitor_requests
, table
->name
, monitor_request_array
);
1003 destroy_monitored_table(struct monitored_table
*mts
, size_t n
)
1007 for (i
= 0; i
< n
; i
++) {
1008 struct monitored_table
*mt
= &mts
[i
];
1009 ovsdb_column_set_destroy(&mt
->columns
);
1016 do_monitor__(struct jsonrpc
*rpc
, const char *database
,
1017 enum ovsdb_monitor_version version
,
1018 int argc
, char *argv
[], struct json
*condition
)
1020 const char *server
= jsonrpc_get_name(rpc
);
1021 const char *table_name
= argv
[0];
1022 struct unixctl_server
*unixctl
;
1023 struct ovsdb_schema
*schema
;
1024 struct jsonrpc_msg
*request
;
1025 struct json
*monitor
, *monitor_requests
, *request_id
;
1026 bool exiting
= false;
1027 bool blocked
= false;
1029 struct monitored_table
*mts
;
1030 size_t n_mts
, allocated_mts
;
1032 ovs_assert(version
< OVSDB_MONITOR_VERSION_MAX
);
1034 daemon_save_fd(STDOUT_FILENO
);
1035 daemonize_start(false);
1039 error
= unixctl_server_create(NULL
, &unixctl
);
1041 ovs_fatal(error
, "failed to create unixctl server");
1044 unixctl_command_register("exit", "", 0, 0,
1045 ovsdb_client_exit
, &exiting
);
1046 unixctl_command_register("ovsdb-client/block", "", 0, 0,
1047 ovsdb_client_block
, &blocked
);
1048 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
1049 ovsdb_client_unblock
, &blocked
);
1050 unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
1051 ovsdb_client_cond_change
, rpc
);
1056 schema
= fetch_schema(rpc
, database
);
1058 monitor_requests
= json_object_create();
1061 n_mts
= allocated_mts
= 0;
1062 if (strcmp(table_name
, "ALL")) {
1063 struct ovsdb_table_schema
*table
;
1065 table
= shash_find_data(&schema
->tables
, table_name
);
1067 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
1068 server
, database
, table_name
);
1071 add_monitored_table(argc
, argv
, server
, database
, condition
, table
,
1072 monitor_requests
, &mts
, &n_mts
, &allocated_mts
);
1074 size_t n
= shash_count(&schema
->tables
);
1075 const struct shash_node
**nodes
= shash_sort(&schema
->tables
);
1079 ovs_fatal(0, "ALL tables are not allowed with condition");
1082 for (i
= 0; i
< n
; i
++) {
1083 struct ovsdb_table_schema
*table
= nodes
[i
]->data
;
1085 add_monitored_table(argc
, argv
, server
, database
, NULL
, table
,
1087 &mts
, &n_mts
, &allocated_mts
);
1092 monitor
= json_array_create_3(json_string_create(database
),
1093 json_null_create(), monitor_requests
);
1094 const char *method
= version
== OVSDB_MONITOR_V2
? "monitor_cond"
1097 request
= jsonrpc_create_request(method
, monitor
, NULL
);
1098 request_id
= json_clone(request
->id
);
1099 jsonrpc_send(rpc
, request
);
1102 unixctl_server_run(unixctl
);
1104 struct jsonrpc_msg
*msg
;
1107 error
= jsonrpc_recv(rpc
, &msg
);
1108 if (error
== EAGAIN
) {
1111 ovs_fatal(error
, "%s: receive failed", server
);
1114 if (msg
->type
== JSONRPC_REQUEST
&& !strcmp(msg
->method
, "echo")) {
1115 jsonrpc_send(rpc
, jsonrpc_create_reply(json_clone(msg
->params
),
1117 } else if (msg
->type
== JSONRPC_REPLY
1118 && json_equal(msg
->id
, request_id
)) {
1120 case OVSDB_MONITOR_V1
:
1121 monitor_print(msg
->result
, mts
, n_mts
, true);
1123 case OVSDB_MONITOR_V2
:
1124 monitor2_print(msg
->result
, mts
, n_mts
);
1126 case OVSDB_MONITOR_VERSION_MAX
:
1131 daemonize_complete();
1132 } else if (msg
->type
== JSONRPC_NOTIFY
1133 && !strcmp(msg
->method
, "update")) {
1134 struct json
*params
= msg
->params
;
1135 if (params
->type
== JSON_ARRAY
1136 && params
->u
.array
.n
== 2
1137 && params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
1138 monitor_print(params
->u
.array
.elems
[1], mts
, n_mts
, false);
1141 } else if (msg
->type
== JSONRPC_NOTIFY
1142 && version
== OVSDB_MONITOR_V2
1143 && !strcmp(msg
->method
, "update2")) {
1144 struct json
*params
= msg
->params
;
1145 if (params
->type
== JSON_ARRAY
1146 && params
->u
.array
.n
== 2
1147 && params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
1148 monitor2_print(params
->u
.array
.elems
[1], mts
, n_mts
);
1152 jsonrpc_msg_destroy(msg
);
1162 jsonrpc_recv_wait(rpc
);
1164 unixctl_server_wait(unixctl
);
1168 json_destroy(request_id
);
1169 unixctl_server_destroy(unixctl
);
1170 ovsdb_schema_destroy(schema
);
1171 destroy_monitored_table(mts
, n_mts
);
1175 do_monitor(struct jsonrpc
*rpc
, const char *database
,
1176 int argc
, char *argv
[])
1178 do_monitor__(rpc
, database
, OVSDB_MONITOR_V1
, argc
, argv
, NULL
);
1182 do_monitor_cond(struct jsonrpc
*rpc
, const char *database
,
1183 int argc
, char *argv
[])
1185 struct ovsdb_condition cnd
;
1186 struct json
*condition
= NULL
;
1187 struct ovsdb_schema
*schema
;
1188 struct ovsdb_table_schema
*table
;
1189 const char *table_name
= argv
[1];
1191 ovs_assert(argc
> 1);
1192 schema
= fetch_schema(rpc
, database
);
1193 table
= shash_find_data(&schema
->tables
, table_name
);
1195 ovs_fatal(0, "%s does not have a table named \"%s\"",
1196 database
, table_name
);
1198 condition
= parse_json(argv
[0]);
1199 check_ovsdb_error(ovsdb_condition_from_json(table
, condition
,
1201 ovsdb_condition_destroy(&cnd
);
1202 do_monitor__(rpc
, database
, OVSDB_MONITOR_V2
, --argc
, ++argv
, condition
);
1203 ovsdb_schema_destroy(schema
);
1206 struct dump_table_aux
{
1207 struct ovsdb_datum
**data
;
1208 const struct ovsdb_column
**columns
;
1213 compare_data(size_t a_y
, size_t b_y
, size_t x
,
1214 const struct dump_table_aux
*aux
)
1216 return ovsdb_datum_compare_3way(&aux
->data
[a_y
][x
],
1218 &aux
->columns
[x
]->type
);
1222 compare_rows(size_t a_y
, size_t b_y
, void *aux_
)
1224 struct dump_table_aux
*aux
= aux_
;
1227 /* Skip UUID columns on the first pass, since their values tend to be
1228 * random and make our results less reproducible. */
1229 for (x
= 0; x
< aux
->n_columns
; x
++) {
1230 if (aux
->columns
[x
]->type
.key
.type
!= OVSDB_TYPE_UUID
) {
1231 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
1238 /* Use UUID columns as tie-breakers. */
1239 for (x
= 0; x
< aux
->n_columns
; x
++) {
1240 if (aux
->columns
[x
]->type
.key
.type
== OVSDB_TYPE_UUID
) {
1241 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
1252 swap_rows(size_t a_y
, size_t b_y
, void *aux_
)
1254 struct dump_table_aux
*aux
= aux_
;
1255 struct ovsdb_datum
*tmp
= aux
->data
[a_y
];
1256 aux
->data
[a_y
] = aux
->data
[b_y
];
1257 aux
->data
[b_y
] = tmp
;
1261 compare_columns(const void *a_
, const void *b_
)
1263 const struct ovsdb_column
*const *ap
= a_
;
1264 const struct ovsdb_column
*const *bp
= b_
;
1265 const struct ovsdb_column
*a
= *ap
;
1266 const struct ovsdb_column
*b
= *bp
;
1268 return strcmp(a
->name
, b
->name
);
1272 dump_table(const char *table_name
, const struct shash
*cols
,
1273 struct json_array
*rows
)
1275 const struct ovsdb_column
**columns
;
1278 struct ovsdb_datum
**data
;
1280 struct dump_table_aux aux
;
1281 struct shash_node
*node
;
1285 /* Sort columns by name, for reproducibility. */
1286 columns
= xmalloc(shash_count(cols
) * sizeof *columns
);
1288 SHASH_FOR_EACH (node
, cols
) {
1289 struct ovsdb_column
*column
= node
->data
;
1290 if (strcmp(column
->name
, "_version")) {
1291 columns
[n_columns
++] = column
;
1294 qsort(columns
, n_columns
, sizeof *columns
, compare_columns
);
1296 /* Extract data from table. */
1297 data
= xmalloc(rows
->n
* sizeof *data
);
1298 for (y
= 0; y
< rows
->n
; y
++) {
1301 if (rows
->elems
[y
]->type
!= JSON_OBJECT
) {
1302 ovs_fatal(0, "row %"PRIuSIZE
" in table %s response is not a JSON object: "
1303 "%s", y
, table_name
, json_to_string(rows
->elems
[y
], 0));
1305 row
= json_object(rows
->elems
[y
]);
1307 data
[y
] = xmalloc(n_columns
* sizeof **data
);
1308 for (x
= 0; x
< n_columns
; x
++) {
1309 const struct json
*json
= shash_find_data(row
, columns
[x
]->name
);
1311 ovs_fatal(0, "row %"PRIuSIZE
" in table %s response lacks %s column",
1312 y
, table_name
, columns
[x
]->name
);
1315 check_ovsdb_error(ovsdb_unconstrained_datum_from_json(
1316 &data
[y
][x
], &columns
[x
]->type
, json
));
1320 /* Sort rows by column values, for reproducibility. */
1322 aux
.columns
= columns
;
1323 aux
.n_columns
= n_columns
;
1324 sort(rows
->n
, compare_rows
, swap_rows
, &aux
);
1326 /* Add column headings. */
1328 table_set_caption(&t
, xasprintf("%s table", table_name
));
1329 for (x
= 0; x
< n_columns
; x
++) {
1330 table_add_column(&t
, "%s", columns
[x
]->name
);
1334 for (y
= 0; y
< rows
->n
; y
++) {
1336 for (x
= 0; x
< n_columns
; x
++) {
1337 struct cell
*cell
= table_add_cell(&t
);
1338 cell
->json
= ovsdb_datum_to_json(&data
[y
][x
], &columns
[x
]->type
);
1339 cell
->type
= &columns
[x
]->type
;
1340 ovsdb_datum_destroy(&data
[y
][x
], &columns
[x
]->type
);
1344 table_print(&t
, &table_style
);
1352 do_dump(struct jsonrpc
*rpc
, const char *database
,
1353 int argc
, char *argv
[])
1355 struct jsonrpc_msg
*request
, *reply
;
1356 struct ovsdb_schema
*schema
;
1357 struct json
*transaction
;
1359 const struct shash_node
*node
, **tables
;
1361 struct ovsdb_table_schema
*tschema
;
1362 const struct shash
*columns
;
1363 struct shash custom_columns
;
1367 shash_init(&custom_columns
);
1368 schema
= fetch_schema(rpc
, database
);
1370 node
= shash_find(&schema
->tables
, argv
[0]);
1372 ovs_fatal(0, "No table \"%s\" found.", argv
[0]);
1374 tables
= xmemdup(&node
, sizeof node
);
1376 tschema
= tables
[0]->data
;
1377 for (i
= 1; i
< argc
; i
++) {
1378 node
= shash_find(&tschema
->columns
, argv
[i
]);
1380 ovs_fatal(0, "Table \"%s\" has no column %s.", argv
[0], argv
[1]);
1382 shash_add(&custom_columns
, argv
[1], node
->data
);
1385 tables
= shash_sort(&schema
->tables
);
1386 n_tables
= shash_count(&schema
->tables
);
1389 /* Construct transaction to retrieve entire database. */
1390 transaction
= json_array_create_1(json_string_create(database
));
1391 for (i
= 0; i
< n_tables
; i
++) {
1392 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1393 struct json
*op
, *jcolumns
;
1396 columns
= &custom_columns
;
1398 columns
= &ts
->columns
;
1400 jcolumns
= json_array_create_empty();
1401 SHASH_FOR_EACH (node
, columns
) {
1402 const struct ovsdb_column
*column
= node
->data
;
1404 if (strcmp(column
->name
, "_version")) {
1405 json_array_add(jcolumns
, json_string_create(column
->name
));
1409 op
= json_object_create();
1410 json_object_put_string(op
, "op", "select");
1411 json_object_put_string(op
, "table", tables
[i
]->name
);
1412 json_object_put(op
, "where", json_array_create_empty());
1413 json_object_put(op
, "columns", jcolumns
);
1414 json_array_add(transaction
, op
);
1417 /* Send request, get reply. */
1418 request
= jsonrpc_create_request("transact", transaction
, NULL
);
1419 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
1421 /* Print database contents. */
1422 if (reply
->result
->type
!= JSON_ARRAY
1423 || reply
->result
->u
.array
.n
!= n_tables
) {
1424 ovs_fatal(0, "reply is not array of %"PRIuSIZE
" elements: %s",
1425 n_tables
, json_to_string(reply
->result
, 0));
1427 for (i
= 0; i
< n_tables
; i
++) {
1428 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1429 const struct json
*op_result
= reply
->result
->u
.array
.elems
[i
];
1432 if (op_result
->type
!= JSON_OBJECT
1433 || !(rows
= shash_find_data(json_object(op_result
), "rows"))
1434 || rows
->type
!= JSON_ARRAY
) {
1435 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1437 ts
->name
, json_to_string(op_result
, 0));
1441 dump_table(tables
[i
]->name
, &custom_columns
, &rows
->u
.array
);
1443 dump_table(tables
[i
]->name
, &ts
->columns
, &rows
->u
.array
);
1447 jsonrpc_msg_destroy(reply
);
1448 shash_destroy(&custom_columns
);
1450 ovsdb_schema_destroy(schema
);
1454 print_and_free_log_record(struct json
*record
)
1456 struct ds header
= DS_EMPTY_INITIALIZER
;
1457 struct ds data
= DS_EMPTY_INITIALIZER
;
1458 ovsdb_log_compose_record(record
, OVSDB_MAGIC
, &header
, &data
);
1459 fwrite(header
.string
, header
.length
, 1, stdout
);
1460 fwrite(data
.string
, data
.length
, 1, stdout
);
1462 ds_destroy(&header
);
1463 json_destroy(record
);
1467 do_backup(struct jsonrpc
*rpc
, const char *database
,
1468 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1470 if (isatty(STDOUT_FILENO
)) {
1471 ovs_fatal(0, "not writing backup to a terminal; "
1472 "please redirect stdout to a file");
1476 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
1478 /* Construct transaction to retrieve all tables. */
1479 struct json
*txn
= json_array_create_1(json_string_create(database
));
1480 struct shash_node
*node
;
1481 SHASH_FOR_EACH (node
, &schema
->tables
) {
1482 const char *table_name
= node
->name
;
1483 const struct ovsdb_table_schema
*table
= node
->data
;
1485 /* Get all the columns except _version and the ephemeral ones.
1487 * We don't omit tables that only have ephemeral columns because of the
1488 * possibility that other tables references rows in those tables; that
1489 * is, even if all the columns are ephemeral, the rows themselves are
1491 struct json
*columns
= json_array_create_empty();
1492 struct shash_node
*node2
;
1493 SHASH_FOR_EACH (node2
, &table
->columns
) {
1494 const struct ovsdb_column
*column
= node2
->data
;
1496 if (column
->persistent
) {
1498 columns
= json_array_create_empty();
1500 json_array_add(columns
, json_string_create(column
->name
));
1504 struct json
*op
= json_object_create();
1505 json_object_put_string(op
, "op", "select");
1506 json_object_put_string(op
, "table", table_name
);
1507 json_object_put(op
, "where", json_array_create_empty());
1508 json_object_put(op
, "columns", columns
);
1509 json_array_add(txn
, op
);
1512 /* Send request, get reply. */
1513 struct jsonrpc_msg
*rq
= jsonrpc_create_request("transact", txn
, NULL
);
1514 struct jsonrpc_msg
*reply
;
1515 check_txn(jsonrpc_transact_block(rpc
, rq
, &reply
), &reply
);
1517 /* Print schema record. */
1518 print_and_free_log_record(ovsdb_schema_to_json(schema
));
1520 /* Print database transaction record. */
1521 if (reply
->result
->type
!= JSON_ARRAY
1522 || reply
->result
->u
.array
.n
!= shash_count(&schema
->tables
)) {
1523 ovs_fatal(0, "reply is not array of %"PRIuSIZE
" elements: %s",
1524 shash_count(&schema
->tables
),
1525 json_to_string(reply
->result
, 0));
1527 struct json
*output_txn
= json_object_create();
1530 SHASH_FOR_EACH (node
, &schema
->tables
) {
1531 const char *table_name
= node
->name
;
1532 const struct ovsdb_table_schema
*table
= node
->data
;
1533 const struct json
*op_result
= reply
->result
->u
.array
.elems
[i
++];
1536 if (op_result
->type
!= JSON_OBJECT
1537 || !(rows
= shash_find_data(json_object(op_result
), "rows"))
1538 || rows
->type
!= JSON_ARRAY
) {
1539 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1541 table
->name
, json_to_string(op_result
, 0));
1544 if (!rows
->u
.array
.n
) {
1548 struct json
*output_rows
= json_object_create();
1549 for (size_t j
= 0; j
< rows
->u
.array
.n
; j
++) {
1550 struct json
*row
= rows
->u
.array
.elems
[j
];
1551 if (row
->type
!= JSON_OBJECT
) {
1552 ovs_fatal(0, "%s table reply row is not an object: %s",
1553 table_name
, json_to_string(row
, 0));
1556 struct json
*uuid_json
= shash_find_and_delete(json_object(row
),
1559 ovs_fatal(0, "%s table reply row lacks _uuid member: %s",
1560 table_name
, json_to_string(row
, 0));
1563 const struct ovsdb_base_type uuid_base
= OVSDB_BASE_UUID_INIT
;
1564 union ovsdb_atom atom
;
1565 check_ovsdb_error(ovsdb_atom_from_json(&atom
, &uuid_base
,
1568 char uuid_s
[UUID_LEN
+ 1];
1569 snprintf(uuid_s
, sizeof uuid_s
, UUID_FMT
, UUID_ARGS(&atom
.uuid
));
1570 json_object_put(output_rows
, uuid_s
, json_clone(row
));
1572 json_object_put(output_txn
, table_name
, output_rows
);
1574 output_txn
= ovsdb_file_txn_annotate(
1575 output_txn
, "produced by \"ovsdb-client backup\"");
1576 print_and_free_log_record(output_txn
);
1578 ovsdb_schema_destroy(schema
);
1579 jsonrpc_msg_destroy(reply
);
1583 do_restore(struct jsonrpc
*rpc
, const char *database
,
1584 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1586 if (isatty(STDIN_FILENO
)) {
1587 ovs_fatal(0, "not reading backup from a terminal; "
1588 "please redirect stdin from a file");
1591 struct ovsdb
*backup
;
1592 check_ovsdb_error(ovsdb_file_open("/dev/stdin", true, &backup
, NULL
));
1594 const struct ovsdb_schema
*schema
= backup
->schema
;
1595 struct ovsdb_schema
*schema2
= fetch_schema(rpc
, database
);
1596 if (!ovsdb_schema_equal(schema
, schema2
)) {
1597 struct ds s
= DS_EMPTY_INITIALIZER
;
1598 if (strcmp(schema
->version
, schema2
->version
)) {
1599 ds_put_format(&s
, "backup schema has version \"%s\" but "
1600 "database schema has version \"%s\"",
1601 schema
->version
, schema2
->version
);
1603 ds_put_format(&s
, "backup schema and database schema are "
1604 "both version %s but still differ",
1608 ovs_fatal(0, "%s (use --force to override differences, or "
1609 "\"ovsdb-client convert\" to change the schema)",
1612 VLOG_INFO("%s", ds_cstr(&s
));
1615 ovsdb_schema_destroy(schema2
);
1617 struct json
*txn
= json_array_create_empty();
1618 json_array_add(txn
, json_string_create(schema
->name
));
1619 struct shash_node
*node
;
1620 SHASH_FOR_EACH (node
, &backup
->tables
) {
1621 const char *table_name
= node
->name
;
1622 struct ovsdb_table
*table
= node
->data
;
1624 struct json
*del_op
= json_object_create();
1625 json_object_put_string(del_op
, "op", "delete");
1626 json_object_put_string(del_op
, "table", table_name
);
1627 json_object_put(del_op
, "where", json_array_create_empty());
1628 json_array_add(txn
, del_op
);
1630 const struct ovsdb_row
*row
;
1631 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
1632 struct json
*ins_op
= json_object_create();
1633 json_object_put_string(ins_op
, "op", "insert");
1634 json_object_put_string(ins_op
, "table", table_name
);
1635 json_object_put(ins_op
, "uuid-name",
1636 json_string_create_nocopy(
1637 ovsdb_data_row_name(ovsdb_row_get_uuid(row
))));
1638 struct json
*row_json
= json_object_create();
1639 json_object_put(ins_op
, "row", row_json
);
1641 struct shash_node
*node2
;
1642 SHASH_FOR_EACH (node2
, &table
->schema
->columns
) {
1643 const struct ovsdb_column
*column
= node2
->data
;
1644 const struct ovsdb_datum
*datum
= &row
->fields
[column
->index
];
1645 const struct ovsdb_type
*type
= &column
->type
;
1646 if (column
->persistent
1647 && column
->index
>= OVSDB_N_STD_COLUMNS
1648 && !ovsdb_datum_is_default(datum
, type
)) {
1649 struct json
*value
= ovsdb_datum_to_json_with_row_names(
1651 json_object_put(row_json
, column
->name
, value
);
1654 json_array_add(txn
, ins_op
);
1657 ovsdb_destroy(backup
);
1658 struct jsonrpc_msg
*rq
= jsonrpc_create_request("transact", txn
, NULL
);
1659 struct jsonrpc_msg
*reply
;
1660 check_txn(jsonrpc_transact_block(rpc
, rq
, &reply
), &reply
);
1661 if (reply
->result
->type
!= JSON_ARRAY
) {
1662 ovs_fatal(0, "result is not array");
1664 for (size_t i
= 0; i
< json_array(reply
->result
)->n
; i
++) {
1665 struct json
*json
= json_array(reply
->result
)->elems
[i
];
1666 if (json
->type
!= JSON_OBJECT
) {
1667 ovs_fatal(0, "result array element is not object");
1669 struct shash
*object
= json_object(json
);
1670 if (shash_find(object
, "error")) {
1671 ovs_fatal(0, "server returned error reply: %s",
1672 json_to_string(json
, JSSF_SORT
));
1675 jsonrpc_msg_destroy(reply
);
1680 do_help(struct jsonrpc
*rpc OVS_UNUSED
, const char *database OVS_UNUSED
,
1681 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1687 /* "lock" command. */
1689 struct ovsdb_client_lock_req
{
1695 lock_req_init(struct ovsdb_client_lock_req
*lock_req
,
1696 const char *method
, const char *lock_name
)
1698 if (lock_req
->method
|| lock_req
->lock
) {
1701 lock_req
->method
= method
;
1702 lock_req
->lock
= xstrdup(lock_name
);
1706 lock_req_is_set(struct ovsdb_client_lock_req
*lock_req
)
1708 return lock_req
->method
;
1712 lock_req_destroy(struct ovsdb_client_lock_req
*lock_req
)
1714 free(lock_req
->lock
);
1715 lock_req
->method
= NULL
;
1716 lock_req
->lock
= NULL
;
1719 /* Create a lock class request. Caller is responsible for free
1720 * the 'request' message. */
1721 static struct jsonrpc_msg
*
1722 create_lock_request(struct ovsdb_client_lock_req
*lock_req
)
1724 struct json
*locks
, *lock
;
1726 locks
= json_array_create_empty();
1727 lock
= json_string_create(lock_req
->lock
);
1728 json_array_add(locks
, lock
);
1730 return jsonrpc_create_request(lock_req
->method
, locks
, NULL
);
1734 ovsdb_client_lock(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1735 const char *argv
[], void *lock_req_
)
1737 struct ovsdb_client_lock_req
*lock_req
= lock_req_
;
1738 lock_req_init(lock_req
, "lock", argv
[1]);
1739 unixctl_command_reply(conn
, NULL
);
1743 ovsdb_client_unlock(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1744 const char *argv
[], void *lock_req_
)
1746 struct ovsdb_client_lock_req
*lock_req
= lock_req_
;
1747 lock_req_init(lock_req
, "unlock", argv
[1]);
1748 unixctl_command_reply(conn
, NULL
);
1752 ovsdb_client_steal(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1753 const char *argv
[], void *lock_req_
)
1755 struct ovsdb_client_lock_req
*lock_req
= lock_req_
;
1756 lock_req_init(lock_req
, "steal", argv
[1]);
1757 unixctl_command_reply(conn
, NULL
);
1761 do_lock(struct jsonrpc
*rpc
, const char *method
, const char *lock
)
1763 struct ovsdb_client_lock_req lock_req
= {NULL
, NULL
};
1764 struct unixctl_server
*unixctl
;
1765 struct jsonrpc_msg
*request
;
1766 struct json
*request_id
= NULL
;
1767 bool exiting
= false;
1768 bool enable_lock_request
= true; /* Don't send another request before
1769 getting a reply of the previous
1771 daemon_save_fd(STDOUT_FILENO
);
1772 daemonize_start(false);
1773 lock_req_init(&lock_req
, method
, lock
);
1778 error
= unixctl_server_create(NULL
, &unixctl
);
1780 ovs_fatal(error
, "failed to create unixctl server");
1783 unixctl_command_register("unlock", "LOCK", 1, 1,
1784 ovsdb_client_unlock
, &lock_req
);
1785 unixctl_command_register("steal", "LOCK", 1, 1,
1786 ovsdb_client_steal
, &lock_req
);
1787 unixctl_command_register("lock", "LOCK", 1, 1,
1788 ovsdb_client_lock
, &lock_req
);
1789 unixctl_command_register("exit", "", 0, 0,
1790 ovsdb_client_exit
, &exiting
);
1796 struct jsonrpc_msg
*msg
;
1799 unixctl_server_run(unixctl
);
1800 if (enable_lock_request
&& lock_req_is_set(&lock_req
)) {
1801 request
= create_lock_request(&lock_req
);
1802 request_id
= json_clone(request
->id
);
1803 jsonrpc_send(rpc
, request
);
1804 lock_req_destroy(&lock_req
);
1807 error
= jsonrpc_recv(rpc
, &msg
);
1808 if (error
== EAGAIN
) {
1811 ovs_fatal(error
, "%s: receive failed", jsonrpc_get_name(rpc
));
1814 if (msg
->type
== JSONRPC_REQUEST
&& !strcmp(msg
->method
, "echo")) {
1815 jsonrpc_send(rpc
, jsonrpc_create_reply(json_clone(msg
->params
),
1817 } else if (msg
->type
== JSONRPC_REPLY
1818 && json_equal(msg
->id
, request_id
)) {
1819 print_json(msg
->result
);
1821 enable_lock_request
= true;
1822 json_destroy(request_id
);
1824 daemonize_complete();
1825 } else if (msg
->type
== JSONRPC_NOTIFY
) {
1827 print_json(msg
->params
);
1831 jsonrpc_msg_destroy(msg
);
1840 jsonrpc_recv_wait(rpc
);
1842 unixctl_server_wait(unixctl
);
1846 json_destroy(request_id
);
1847 unixctl_server_destroy(unixctl
);
1851 do_lock_create(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
1852 int argc OVS_UNUSED
, char *argv
[])
1854 do_lock(rpc
, "lock", argv
[0]);
1858 do_lock_steal(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
1859 int argc OVS_UNUSED
, char *argv
[])
1861 do_lock(rpc
, "steal", argv
[0]);
1865 do_lock_unlock(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
1866 int argc OVS_UNUSED
, char *argv
[])
1868 do_lock(rpc
, "unlock", argv
[0]);
1871 /* All command handlers (except for "help") are expected to take an optional
1872 * server socket name (e.g. "unix:...") as their first argument. The socket
1873 * name argument must be included in max_args (but left out of min_args). The
1874 * command name and socket name are not included in the arguments passed to the
1875 * handler: the argv[0] passed to the handler is the first argument after the
1876 * optional server socket name. The connection to the server is available as
1877 * global variable 'rpc'. */
1878 static const struct ovsdb_client_command all_commands
[] = {
1879 { "list-dbs", NEED_RPC
, 0, 0, do_list_dbs
},
1880 { "get-schema", NEED_DATABASE
, 0, 0, do_get_schema
},
1881 { "get-schema-version", NEED_DATABASE
, 0, 0, do_get_schema_version
},
1882 { "get-schema-cksum", NEED_DATABASE
, 0, 0, do_get_schema_cksum
},
1883 { "list-tables", NEED_DATABASE
, 0, 0, do_list_tables
},
1884 { "list-columns", NEED_DATABASE
, 0, 1, do_list_columns
},
1885 { "transact", NEED_RPC
, 1, 1, do_transact
},
1886 { "query", NEED_RPC
, 1, 1, do_query
},
1887 { "monitor", NEED_DATABASE
, 1, INT_MAX
, do_monitor
},
1888 { "monitor-cond", NEED_DATABASE
, 2, 3, do_monitor_cond
},
1889 { "dump", NEED_DATABASE
, 0, INT_MAX
, do_dump
},
1890 { "backup", NEED_DATABASE
, 0, 0, do_backup
},
1891 { "restore", NEED_DATABASE
, 0, 0, do_restore
},
1892 { "lock", NEED_RPC
, 1, 1, do_lock_create
},
1893 { "steal", NEED_RPC
, 1, 1, do_lock_steal
},
1894 { "unlock", NEED_RPC
, 1, 1, do_lock_unlock
},
1895 { "help", NEED_NONE
, 0, INT_MAX
, do_help
},
1897 { NULL
, 0, 0, 0, NULL
},
1900 static const struct ovsdb_client_command
*get_all_commands(void)
1902 return all_commands
;