2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2016, 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.
26 #include "command-line.h"
29 #include "openvswitch/dynamic-string.h"
30 #include "fatal-signal.h"
35 #include "openvswitch/hmap.h"
36 #include "openvswitch/json.h"
38 #include "ovsdb-data.h"
39 #include "ovsdb-error.h"
40 #include "ovsdb-parser.h"
42 #include "raft-private.h"
44 #include "socket-util.h"
48 #include "transaction.h"
50 #include "openvswitch/vlog.h"
52 /* -m, --more: Verbosity level for "show-log" command output. */
53 static int show_log_verbosity
;
55 /* --role: RBAC role to use for "transact" and "query" commands. */
56 static const char *rbac_role
;
58 /* --cid: Cluster ID for "join-cluster" command. */
59 static struct uuid cid
;
61 static const struct ovs_cmdl_command
*get_all_commands(void);
63 OVS_NO_RETURN
static void usage(void);
64 static void parse_options(int argc
, char *argv
[]);
66 static const char *default_db(void);
67 static const char *default_schema(void);
70 main(int argc
, char *argv
[])
72 struct ovs_cmdl_context ctx
= { .argc
= 0, };
73 set_program_name(argv
[0]);
74 parse_options(argc
, argv
);
75 fatal_ignore_sigpipe();
77 ctx
.argc
= argc
- optind
;
78 ctx
.argv
= argv
+ optind
;
79 ovs_cmdl_run_command(&ctx
, get_all_commands());
84 parse_options(int argc
, char *argv
[])
87 OPT_RBAC_ROLE
= UCHAR_MAX
+ 1,
90 static const struct option long_options
[] = {
91 {"more", no_argument
, NULL
, 'm'},
92 {"rbac-role", required_argument
, NULL
, OPT_RBAC_ROLE
},
93 {"cid", required_argument
, NULL
, OPT_CID
},
94 {"verbose", optional_argument
, NULL
, 'v'},
95 {"help", no_argument
, NULL
, 'h'},
96 {"option", no_argument
, NULL
, 'o'},
97 {"version", no_argument
, NULL
, 'V'},
100 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
105 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
112 show_log_verbosity
++;
120 if (!uuid_from_string(&cid
, optarg
) || uuid_is_zero(&cid
)) {
121 ovs_fatal(0, "%s: not a valid UUID", optarg
);
129 ovs_cmdl_print_options(long_options
);
133 ovs_print_version(0, 0);
137 vlog_set_verbosity(optarg
);
153 printf("%s: Open vSwitch database management utility\n"
154 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
155 " create [DB [SCHEMA]] create DB with the given SCHEMA\n"
156 " create-cluster DB CONTENTS LOCAL\n"
157 " create clustered DB with given CONTENTS and LOCAL address\n"
158 " [--cid=UUID] join-cluster DB NAME LOCAL REMOTE...\n"
159 " join clustered DB with given NAME and LOCAL and REMOTE addrs\n"
160 " compact [DB [DST]] compact DB in-place (or to DST)\n"
161 " convert [DB [SCHEMA [DST]]] convert DB to SCHEMA (to DST)\n"
162 " db-name [DB] report name of schema used by DB\n"
163 " db-version [DB] report version of schema used by DB\n"
164 " db-cksum [DB] report checksum of schema used by DB\n"
165 " db-cid DB report cluster ID of clustered DB\n"
166 " db-sid DB report server ID of clustered DB\n"
167 " db-local-address DB report local address of clustered DB\n"
168 " db-is-clustered DB test whether DB is clustered\n"
169 " db-is-standalone DB test whether DB is standalone\n"
170 " schema-name [SCHEMA] report SCHEMA's name\n"
171 " schema-version [SCHEMA] report SCHEMA's schema version\n"
172 " schema-cksum [SCHEMA] report SCHEMA's checksum\n"
173 " compare-versions A OP B compare OVSDB schema version numbers\n"
174 " query [DB] TRNS execute read-only transaction on DB\n"
175 " transact [DB] TRNS execute read/write transaction on DB\n"
176 " cluster-to-standalone DB DB Convert clustered DB to\n"
177 " standalone DB when cluster is down and cannot be\n"
179 " [-m]... show-log [DB] print DB's log entries\n"
180 "The default DB is %s.\n"
181 "The default SCHEMA is %s.\n",
182 program_name
, program_name
, default_db(), default_schema());
186 -m, --more increase show-log verbosity\n\
187 --rbac-role=ROLE RBAC role for transact and query commands\n\
188 -h, --help display this help message\n\
189 -V, --version display version information\n");
198 db
= xasprintf("%s/conf.db", ovs_dbdir());
208 schema
= xasprintf("%s/vswitch.ovsschema", ovs_pkgdatadir());
214 parse_json(const char *s
)
216 struct json
*json
= json_from_string(s
);
217 if (json
->type
== JSON_STRING
) {
218 ovs_fatal(0, "\"%s\": %s", s
, json
->string
);
224 print_and_free_json(struct json
*json
)
226 char *string
= json_to_string(json
, JSSF_SORT
);
233 check_ovsdb_error(struct ovsdb_error
*error
)
236 ovs_fatal(0, "%s", ovsdb_error_to_string(error
));
240 /* Opens the standalone database 'filename' and returns its schema. */
241 static struct ovsdb_schema
*
242 read_standalone_schema(const char *filename
)
244 struct ovsdb_storage
*storage
= ovsdb_storage_open_standalone(filename
,
246 struct ovsdb_schema
*schema
= ovsdb_storage_read_schema(storage
);
247 ovsdb_storage_close(storage
);
252 do_create(struct ovs_cmdl_context
*ctx
)
254 const char *db_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
255 const char *schema_file_name
= ctx
->argc
>= 3 ? ctx
->argv
[2] : default_schema();
256 struct ovsdb_schema
*schema
;
257 struct ovsdb_log
*log
;
260 /* Read schema from file and convert to JSON. */
261 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name
, &schema
));
262 json
= ovsdb_schema_to_json(schema
);
263 ovsdb_schema_destroy(schema
);
265 /* Create database file. */
266 check_ovsdb_error(ovsdb_log_open(db_file_name
, OVSDB_MAGIC
,
267 OVSDB_LOG_CREATE_EXCL
, -1, &log
));
268 check_ovsdb_error(ovsdb_log_write_and_free(log
, json
));
269 check_ovsdb_error(ovsdb_log_commit_block(log
));
270 ovsdb_log_close(log
);
274 do_create_cluster(struct ovs_cmdl_context
*ctx
)
276 const char *db_file_name
= ctx
->argv
[1];
277 const char *src_file_name
= ctx
->argv
[2];
278 const char *local
= ctx
->argv
[3];
280 struct ovsdb_schema
*schema
;
283 struct ovsdb_error
*error
= ovsdb_schema_from_file(src_file_name
, &schema
);
285 /* It's just a schema file. */
286 data
= json_object_create();
288 /* Not a schema file. Try reading it as a standalone database. */
289 ovsdb_error_destroy(error
);
291 struct ovsdb
*ovsdb
= ovsdb_file_read(src_file_name
, false);
292 char *comment
= xasprintf("created from %s", src_file_name
);
293 data
= ovsdb_to_txn_json(ovsdb
, comment
);
295 schema
= ovsdb_schema_clone(ovsdb
->schema
);
296 ovsdb_destroy(ovsdb
);
299 ovsdb_schema_persist_ephemeral_columns(schema
, src_file_name
);
301 struct json
*schema_json
= ovsdb_schema_to_json(schema
);
303 /* Create database file. */
304 struct json
*snapshot
= json_array_create_2(schema_json
, data
);
305 check_ovsdb_error(raft_create_cluster(db_file_name
, schema
->name
,
307 ovsdb_schema_destroy(schema
);
308 json_destroy(snapshot
);
312 do_join_cluster(struct ovs_cmdl_context
*ctx
)
314 const char *db_file_name
= ctx
->argv
[1];
315 const char *name
= ctx
->argv
[2];
316 const char *local
= ctx
->argv
[3];
318 /* Check for a plausible 'name'. */
319 if (!ovsdb_parser_is_id(name
)) {
320 ovs_fatal(0, "%s: not a valid schema name (use \"schema-name\" "
321 "command to find the correct name)", name
);
324 /* Create database file. */
325 struct sset remote_addrs
= SSET_INITIALIZER(&remote_addrs
);
326 for (size_t i
= 4; i
< ctx
->argc
; i
++) {
327 sset_add(&remote_addrs
, ctx
->argv
[i
]);
329 check_ovsdb_error(raft_join_cluster(db_file_name
, name
, local
,
331 uuid_is_zero(&cid
) ? NULL
: &cid
));
332 sset_destroy(&remote_addrs
);
335 static struct ovsdb_error
*
336 write_standalone_db(const char *file_name
, const char *comment
,
337 const struct ovsdb
*db
)
339 struct ovsdb_log
*log
;
340 struct ovsdb_error
*error
= ovsdb_log_open(file_name
, OVSDB_MAGIC
,
341 OVSDB_LOG_CREATE
, false, &log
);
346 error
= ovsdb_log_write_and_free(log
, ovsdb_schema_to_json(db
->schema
));
348 error
= ovsdb_log_write_and_free(log
, ovsdb_to_txn_json(db
, comment
));
350 ovsdb_log_close(log
);
358 /* Reads 'src_name' and writes it back, compacted, to 'dst_name', adding the
359 * specified 'comment'. If 'new_schema' is nonull, converts the databse to
362 * Standalone databases only. */
364 compact_or_convert(const char *src_name_
, const char *dst_name_
,
365 struct ovsdb_schema
*new_schema
, const char *comment
)
367 bool in_place
= dst_name_
== NULL
;
369 /* Dereference symlinks for source and destination names. In the in-place
370 * case this ensures that, if the source name is a symlink, we replace its
371 * target instead of replacing the symlink by a regular file. In the
372 * non-in-place, this has the same effect for the destination name. */
373 char *src_name
= follow_symlinks(src_name_
);
374 char *dst_name
= (in_place
375 ? xasprintf("%s.tmp", src_name
)
376 : follow_symlinks(dst_name_
));
378 /* Lock the source, if we will be replacing it. */
379 struct lockfile
*src_lock
= NULL
;
381 int retval
= lockfile_lock(src_name
, &src_lock
);
383 ovs_fatal(retval
, "%s: failed to lock lockfile", src_name
);
387 /* Get (temporary) destination and lock it. */
388 struct lockfile
*dst_lock
= NULL
;
389 int retval
= lockfile_lock(dst_name
, &dst_lock
);
391 ovs_fatal(retval
, "%s: failed to lock lockfile", dst_name
);
395 struct ovsdb
*ovsdb
= (new_schema
396 ? ovsdb_file_read_as_schema(src_name
, new_schema
)
397 : ovsdb_file_read(src_name
, false));
398 ovsdb_storage_close(ovsdb
->storage
);
399 ovsdb
->storage
= NULL
;
400 check_ovsdb_error(write_standalone_db(dst_name
, comment
, ovsdb
));
401 ovsdb_destroy(ovsdb
);
403 /* Replace source. */
408 if (rename(dst_name
, src_name
)) {
409 ovs_fatal(errno
, "failed to rename \"%s\" to \"%s\"",
412 fsync_parent_dir(dst_name
);
413 lockfile_unlock(src_lock
);
416 lockfile_unlock(dst_lock
);
423 do_compact(struct ovs_cmdl_context
*ctx
)
425 const char *db
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
426 const char *target
= ctx
->argc
>= 3 ? ctx
->argv
[2] : NULL
;
428 compact_or_convert(db
, target
, NULL
, "compacted by ovsdb-tool "VERSION
);
432 do_convert(struct ovs_cmdl_context
*ctx
)
434 const char *db
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
435 const char *schema
= ctx
->argc
>= 3 ? ctx
->argv
[2] : default_schema();
436 const char *target
= ctx
->argc
>= 4 ? ctx
->argv
[3] : NULL
;
437 struct ovsdb_schema
*new_schema
;
439 check_ovsdb_error(ovsdb_schema_from_file(schema
, &new_schema
));
440 compact_or_convert(db
, target
, new_schema
,
441 "converted by ovsdb-tool "VERSION
);
445 do_needs_conversion(struct ovs_cmdl_context
*ctx
)
447 const char *db_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
448 const char *schema_file_name
= ctx
->argc
>= 3 ? ctx
->argv
[2] : default_schema();
449 struct ovsdb_schema
*schema1
= read_standalone_schema(db_file_name
);
450 struct ovsdb_schema
*schema2
;
452 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name
, &schema2
));
453 puts(ovsdb_schema_equal(schema1
, schema2
) ? "no" : "yes");
454 ovsdb_schema_destroy(schema1
);
455 ovsdb_schema_destroy(schema2
);
459 do_db_name(struct ovs_cmdl_context
*ctx
)
461 const char *db_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
463 struct ovsdb_log
*log
;
464 check_ovsdb_error(ovsdb_log_open(db_file_name
, OVSDB_MAGIC
"|"RAFT_MAGIC
,
465 OVSDB_LOG_READ_ONLY
, -1, &log
));
466 if (!strcmp(ovsdb_log_get_magic(log
), OVSDB_MAGIC
)) {
467 struct json
*schema_json
;
468 check_ovsdb_error(ovsdb_log_read(log
, &schema_json
));
470 struct ovsdb_schema
*schema
;
471 check_ovsdb_error(ovsdb_schema_from_json(schema_json
, &schema
));
475 ovsdb_schema_destroy(schema
);
476 json_destroy(schema_json
);
477 } else if (!strcmp(ovsdb_log_get_magic(log
), RAFT_MAGIC
)) {
478 struct raft_metadata md
;
479 check_ovsdb_error(raft_read_metadata(log
, &md
));
481 raft_metadata_destroy(&md
);
486 ovsdb_log_close(log
);
490 do_db_version(struct ovs_cmdl_context
*ctx
)
492 const char *db_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
493 struct ovsdb_schema
*schema
= read_standalone_schema(db_file_name
);
495 puts(schema
->version
);
496 ovsdb_schema_destroy(schema
);
500 do_db_cksum(struct ovs_cmdl_context
*ctx
)
502 const char *db_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
503 struct ovsdb_schema
*schema
= read_standalone_schema(db_file_name
);
505 ovsdb_schema_destroy(schema
);
508 static struct raft_metadata
509 read_cluster_metadata(const char *filename
)
511 struct ovsdb_log
*log
;
512 check_ovsdb_error(ovsdb_log_open(filename
, OVSDB_MAGIC
"|"RAFT_MAGIC
,
513 OVSDB_LOG_READ_ONLY
, -1, &log
));
514 if (strcmp(ovsdb_log_get_magic(log
), RAFT_MAGIC
)) {
515 ovs_fatal(0, "%s: not a clustered database", filename
);
518 struct raft_metadata md
;
519 check_ovsdb_error(raft_read_metadata(log
, &md
));
521 ovsdb_log_close(log
);
527 do_db_cid(struct ovs_cmdl_context
*ctx
)
529 const char *db_file_name
= ctx
->argv
[1];
530 struct raft_metadata md
= read_cluster_metadata(db_file_name
);
531 if (uuid_is_zero(&md
.cid
)) {
532 fprintf(stderr
, "%s: cluster ID not yet known\n", db_file_name
);
535 printf(UUID_FMT
"\n", UUID_ARGS(&md
.cid
));
536 raft_metadata_destroy(&md
);
540 do_db_sid(struct ovs_cmdl_context
*ctx
)
542 const char *db_file_name
= ctx
->argv
[1];
543 struct raft_metadata md
= read_cluster_metadata(db_file_name
);
544 printf(UUID_FMT
"\n", UUID_ARGS(&md
.sid
));
545 raft_metadata_destroy(&md
);
549 do_db_local_address(struct ovs_cmdl_context
*ctx
)
551 const char *db_file_name
= ctx
->argv
[1];
552 struct raft_metadata md
= read_cluster_metadata(db_file_name
);
554 raft_metadata_destroy(&md
);
558 do_db_has_magic(struct ovs_cmdl_context
*ctx
, const char *magic
)
560 const char *filename
= ctx
->argv
[1];
561 struct ovsdb_log
*log
;
563 check_ovsdb_error(ovsdb_log_open(filename
, OVSDB_MAGIC
"|"RAFT_MAGIC
,
564 OVSDB_LOG_READ_ONLY
, -1, &log
));
565 int cmp
= strcmp(ovsdb_log_get_magic(log
), magic
);
566 ovsdb_log_close(log
);
573 do_db_is_clustered(struct ovs_cmdl_context
*ctx
)
575 do_db_has_magic(ctx
, RAFT_MAGIC
);
579 do_db_is_standalone(struct ovs_cmdl_context
*ctx
)
581 do_db_has_magic(ctx
, OVSDB_MAGIC
);
585 do_schema_name(struct ovs_cmdl_context
*ctx
)
587 const char *schema_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_schema();
588 struct ovsdb_schema
*schema
;
590 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name
, &schema
));
592 ovsdb_schema_destroy(schema
);
596 do_schema_version(struct ovs_cmdl_context
*ctx
)
598 const char *schema_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_schema();
599 struct ovsdb_schema
*schema
;
601 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name
, &schema
));
602 puts(schema
->version
);
603 ovsdb_schema_destroy(schema
);
607 do_schema_cksum(struct ovs_cmdl_context
*ctx
)
609 const char *schema_file_name
610 = ctx
->argc
>= 2 ? ctx
->argv
[1] : default_schema();
611 struct ovsdb_schema
*schema
;
613 check_ovsdb_error(ovsdb_schema_from_file(schema_file_name
, &schema
));
615 ovsdb_schema_destroy(schema
);
618 /* Standalone databases only. */
620 transact(struct ovs_cmdl_context
*ctx
, bool rw
)
622 const char *db_file_name
= ctx
->argc
>= 3 ? ctx
->argv
[1] : default_db();
623 const char *transaction
= ctx
->argv
[ctx
->argc
- 1];
625 struct ovsdb
*ovsdb
= ovsdb_file_read(db_file_name
, rw
);
626 struct json
*request
= parse_json(transaction
);
627 struct json
*result
= ovsdb_execute(ovsdb
, NULL
, request
, false,
628 rbac_role
, NULL
, 0, NULL
);
629 json_destroy(request
);
631 print_and_free_json(result
);
632 ovsdb_destroy(ovsdb
);
636 do_query(struct ovs_cmdl_context
*ctx
)
638 transact(ctx
, false);
642 do_transact(struct ovs_cmdl_context
*ctx
)
648 print_db_changes(struct shash
*tables
, struct smap
*names
,
649 const struct ovsdb_schema
*schema
)
651 struct shash_node
*n1
;
654 SHASH_FOR_EACH (n1
, tables
) {
655 const char *table
= n1
->name
;
656 struct ovsdb_table_schema
*table_schema
;
657 struct json
*rows
= n1
->data
;
658 struct shash_node
*n2
;
660 if (n1
->name
[0] == '_' || rows
->type
!= JSON_OBJECT
) {
668 table_schema
= schema
? shash_find_data(&schema
->tables
, table
) : NULL
;
669 SHASH_FOR_EACH (n2
, json_object(rows
)) {
670 const char *row_uuid
= n2
->name
;
671 struct json
*columns
= n2
->data
;
672 struct shash_node
*n3
;
674 const char *old_name
= smap_get(names
, row_uuid
);
675 char *new_name
= NULL
;
676 if (columns
->type
== JSON_OBJECT
) {
677 struct json
*new_name_json
;
679 new_name_json
= shash_find_data(json_object(columns
), "name");
681 new_name
= json_to_string(new_name_json
, JSSF_SORT
);
685 printf(" table %s", table
);
689 printf(" insert row %s (%.8s):\n", new_name
, row_uuid
);
691 printf(" insert row %.8s:\n", row_uuid
);
694 printf(" row %s (%.8s):\n", old_name
, row_uuid
);
697 if (columns
->type
== JSON_OBJECT
) {
698 if (show_log_verbosity
> 1) {
699 SHASH_FOR_EACH (n3
, json_object(columns
)) {
700 const char *column
= n3
->name
;
701 const struct ovsdb_column
*column_schema
;
702 struct json
*value
= n3
->data
;
703 char *value_string
= NULL
;
707 ? shash_find_data(&table_schema
->columns
, column
)
710 const struct ovsdb_type
*type
;
711 struct ovsdb_error
*error
;
712 struct ovsdb_datum datum
;
714 type
= &column_schema
->type
;
715 error
= ovsdb_datum_from_json(&datum
, type
,
721 ovsdb_datum_to_string(&datum
, type
, &s
);
722 value_string
= ds_steal_cstr(&s
);
724 ovsdb_error_destroy(error
);
728 value_string
= json_to_string(value
, JSSF_SORT
);
730 printf(" %s=%s\n", column
, value_string
);
735 if (new_name
&& (!old_name
|| strcmp(old_name
, new_name
))) {
736 smap_replace_nocopy(names
, row_uuid
, new_name
);
738 } else if (!old_name
) {
739 smap_add_nocopy(names
, xstrdup(row_uuid
),
740 xmemdup0(row_uuid
, 8));
742 } else if (columns
->type
== JSON_NULL
) {
743 printf(" delete row\n");
744 smap_remove(names
, row_uuid
);
753 print_change_record(const struct json
*json
, const struct ovsdb_schema
*schema
,
756 if (!json
|| json
->type
!= JSON_OBJECT
) {
760 struct json
*date
, *comment
;
762 date
= shash_find_data(json_object(json
), "_date");
763 if (date
&& date
->type
== JSON_INTEGER
) {
764 long long int t
= json_integer(date
);
768 /* Older versions of ovsdb wrote timestamps in seconds. */
772 s
= xastrftime_msec(" %Y-%m-%d %H:%M:%S.###", t
, true);
777 comment
= shash_find_data(json_object(json
), "_comment");
778 if (comment
&& comment
->type
== JSON_STRING
) {
779 printf(" \"%s\"", json_string(comment
));
782 if (show_log_verbosity
> 0) {
783 print_db_changes(json_object(json
), names
, schema
);
788 do_show_log_standalone(struct ovsdb_log
*log
)
790 struct smap names
= SMAP_INITIALIZER(&names
);
791 struct ovsdb_schema
*schema
= NULL
;
793 for (unsigned int i
= 0; ; i
++) {
796 check_ovsdb_error(ovsdb_log_read(log
, &json
));
801 printf("record %u:", i
);
803 check_ovsdb_error(ovsdb_schema_from_json(json
, &schema
));
804 printf(" \"%s\" schema, version=\"%s\", cksum=\"%s\"\n",
805 schema
->name
, schema
->version
, schema
->cksum
);
807 print_change_record(json
, schema
, &names
);
813 ovsdb_schema_destroy(schema
);
814 smap_destroy(&names
);
818 print_servers(const char *name
, const struct json
*servers
)
824 printf(" %s: ", name
);
826 const struct shash_node
**nodes
= shash_sort(json_object(servers
));
827 size_t n
= shash_count(json_object(servers
));
828 for (size_t i
= 0; i
< n
; i
++) {
833 const struct shash_node
*node
= nodes
[i
];
834 printf("%.4s(", node
->name
);
836 const struct json
*address
= node
->data
;
837 char *s
= json_to_string(address
, JSSF_SORT
);
848 print_data(const char *prefix
, const struct json
*data
,
849 struct ovsdb_schema
**schemap
, struct smap
*names
)
855 if (json_array(data
)->n
!= 2) {
856 printf(" ***invalid data***\n");
860 const struct json
*schema_json
= json_array(data
)->elems
[0];
861 if (schema_json
->type
!= JSON_NULL
) {
862 struct ovsdb_schema
*schema
;
864 check_ovsdb_error(ovsdb_schema_from_json(schema_json
, &schema
));
865 printf(" %sschema: \"%s\", version=\"%s\", cksum=\"%s\"\n",
866 prefix
, schema
->name
, schema
->version
, schema
->cksum
);
868 ovsdb_schema_destroy(*schemap
);
872 print_change_record(json_array(data
)->elems
[1], *schemap
, names
);
876 print_raft_header(const struct raft_header
*h
,
877 struct ovsdb_schema
**schemap
, struct smap
*names
)
879 printf(" name: \"%s\'\n", h
->name
);
880 printf(" local address: \"%s\"\n", h
->local_address
);
881 printf(" server_id: "SID_FMT
"\n", SID_ARGS(&h
->sid
));
882 if (!uuid_is_zero(&h
->cid
)) {
883 printf(" cluster_id: "CID_FMT
"\n", CID_ARGS(&h
->cid
));
885 if (!sset_is_empty(&h
->remote_addresses
)) {
886 printf(" remote_addresses:");
889 SSET_FOR_EACH (s
, &h
->remote_addresses
) {
895 printf(" prev_index: %"PRIu64
"\n", h
->snap_index
);
896 printf(" prev_term: %"PRIu64
"\n", h
->snap
.term
);
897 print_servers("prev_servers", h
->snap
.servers
);
898 if (!uuid_is_zero(&h
->snap
.eid
)) {
899 printf(" prev_eid: %04x\n", uuid_prefix(&h
->snap
.eid
, 4));
901 print_data("prev_", h
->snap
.data
, schemap
, names
);
906 print_raft_record(const struct raft_record
*r
,
907 struct ovsdb_schema
**schemap
, struct smap
*names
)
910 printf(" comment: \"%s\"\n", r
->comment
);
913 printf(" term: %"PRIu64
"\n", r
->term
);
918 printf(" index: %"PRIu64
"\n", r
->entry
.index
);
919 print_servers("servers", r
->entry
.servers
);
920 if (!uuid_is_zero(&r
->entry
.eid
)) {
921 printf(" eid: %04x\n", uuid_prefix(&r
->entry
.eid
, 4));
923 print_data("", r
->entry
.data
, schemap
, names
);
930 printf(" vote: "SID_FMT
"\n", SID_ARGS(&r
->sid
));
934 printf(" note: \"%s\"\n", r
->note
);
937 case RAFT_REC_COMMIT_INDEX
:
938 printf(" commit_index: %"PRIu64
"\n", r
->commit_index
);
941 case RAFT_REC_LEADER
:
942 printf(" leader: "SID_FMT
"\n", SID_ARGS(&r
->sid
));
951 raft_header_to_standalone_log(const struct raft_header
*h
,
952 struct ovsdb_log
*db_log_data
)
955 if (!h
->snap
.data
|| json_array(h
->snap
.data
)->n
!= 2) {
956 ovs_fatal(0, "Incorrect raft header data array length");
959 struct json
*schema_json
= json_array(h
->snap
.data
)->elems
[0];
960 if (schema_json
->type
!= JSON_NULL
) {
961 struct ovsdb_schema
*schema
;
962 check_ovsdb_error(ovsdb_schema_from_json(schema_json
, &schema
));
963 ovsdb_schema_destroy(schema
);
964 check_ovsdb_error(ovsdb_log_write_and_free(db_log_data
,
968 struct json
*data_json
= json_array(h
->snap
.data
)->elems
[1];
969 if (!data_json
|| data_json
->type
!= JSON_OBJECT
) {
970 ovs_fatal(0, "Invalid raft header data");
972 if (data_json
->type
!= JSON_NULL
) {
973 check_ovsdb_error(ovsdb_log_write_and_free(db_log_data
,
980 raft_record_to_standalone_log(const struct raft_record
*r
,
981 struct ovsdb_log
*db_log_data
)
983 if (r
->type
== RAFT_REC_ENTRY
) {
984 if (!r
->entry
.data
) {
987 if (json_array(r
->entry
.data
)->n
!= 2) {
988 ovs_fatal(0, "Incorrect raft record array length");
991 struct json
*data_json
= json_array(r
->entry
.data
)->elems
[1];
992 if (data_json
->type
!= JSON_NULL
) {
993 check_ovsdb_error(ovsdb_log_write_and_free(db_log_data
,
1000 do_show_log_cluster(struct ovsdb_log
*log
)
1002 struct smap names
= SMAP_INITIALIZER(&names
);
1003 struct ovsdb_schema
*schema
= NULL
;
1004 for (unsigned int i
= 0; ; i
++) {
1006 check_ovsdb_error(ovsdb_log_read(log
, &json
));
1011 printf("record %u:\n", i
);
1012 struct ovsdb_error
*error
;
1014 struct raft_header h
;
1015 error
= raft_header_from_json(&h
, json
);
1017 print_raft_header(&h
, &schema
, &names
);
1018 raft_header_uninit(&h
);
1021 struct raft_record r
;
1022 error
= raft_record_from_json(&r
, json
);
1024 print_raft_record(&r
, &schema
, &names
);
1025 raft_record_uninit(&r
);
1029 char *s
= ovsdb_error_to_string_free(error
);
1037 ovsdb_schema_destroy(schema
);
1038 smap_destroy(&names
);
1042 do_show_log(struct ovs_cmdl_context
*ctx
)
1044 const char *db_file_name
= ctx
->argc
>= 2 ? ctx
->argv
[1] : default_db();
1045 struct ovsdb_log
*log
;
1047 check_ovsdb_error(ovsdb_log_open(db_file_name
, OVSDB_MAGIC
"|"RAFT_MAGIC
,
1048 OVSDB_LOG_READ_ONLY
, -1, &log
));
1049 if (!strcmp(ovsdb_log_get_magic(log
), OVSDB_MAGIC
)) {
1050 do_show_log_standalone(log
);
1052 do_show_log_cluster(log
);
1054 ovsdb_log_close(log
);
1058 struct ovsdb_log
*log
;
1059 const char *filename
;
1060 const char *nickname
;
1062 struct raft_header header
;
1064 struct raft_record
*records
;
1067 struct raft_entry
*snap
;
1068 struct raft_entry
*entries
;
1069 uint64_t log_start
, log_end
;
1073 /* In struct cluster's 'leaders', indexed by 'term'. */
1074 struct hmap_node hmap_node
;
1076 /* This structure indicates that in 'term', 'server' reported that 'leader'
1077 * was elected leader. When 'log_end' is nonzero, it additionally
1078 * indicates 'leader''s log_end at the time it was elected. */
1080 struct server
*server
;
1086 /* In struct cluster's 'commits', indexed by 'term'. */
1087 struct hmap_node hmap_node
;
1089 /* This structure indicates that in 'term', 'server' reported the commit
1090 * index as 'index'. */
1092 struct server
*server
;
1093 uint64_t index
; /* Commit index. */
1097 struct server
*servers
;
1100 struct hmap leaders
; /* Contains 'struct leader's. */
1102 struct hmap commits
; /* Contains 'struct commit's. */
1106 get_server_name(const struct cluster
*c
, const struct uuid
*sid
,
1107 char buf
[SID_LEN
+ 1], size_t bufsize
)
1109 for (size_t i
= 0; i
< c
->n_servers
; i
++) {
1110 struct server
*s
= &c
->servers
[i
];
1111 if (uuid_equals(&s
->header
.sid
, sid
)) {
1116 snprintf(buf
, bufsize
, SID_FMT
, SID_ARGS(sid
));
1120 static struct leader
*
1121 find_leader(struct cluster
*c
, uint64_t term
)
1123 struct leader
*leader
;
1124 HMAP_FOR_EACH_WITH_HASH (leader
, hmap_node
, hash_uint64(term
),
1126 if (term
== leader
->term
) {
1133 /* Records that 'server' reported that 'leader' was elected leader in 'term'.
1135 * Checks the Election Safety Property: at most one leader may be elected in a
1136 * single term (see Figure 3.2). */
1138 record_leader(struct cluster
*c
, uint64_t term
, struct server
*server
,
1139 const struct uuid
*leader
)
1141 bool server_is_leader
= uuid_equals(&server
->header
.sid
, leader
);
1142 struct leader
*p
= find_leader(c
, term
);
1144 if (!uuid_equals(&p
->leader
, leader
)) {
1145 char buf1
[SID_LEN
+ 1];
1146 char buf2
[SID_LEN
+ 1];
1147 ovs_fatal(0, "term %"PRIu64
" has two different leaders: "
1148 "%s says that the leader is %s and "
1149 "%s says that the leader is %s",
1151 p
->server
->filename
,
1152 get_server_name(c
, &p
->leader
, buf1
, sizeof buf1
),
1154 get_server_name(c
, leader
, buf2
, sizeof buf2
));
1156 if (server_is_leader
&& server
->log_end
> p
->log_end
) {
1157 p
->log_end
= server
->log_end
;
1160 p
= xmalloc(sizeof *p
);
1161 hmap_insert(&c
->leaders
, &p
->hmap_node
, hash_uint64(term
));
1164 p
->leader
= *leader
;
1165 if (server_is_leader
) {
1166 p
->log_end
= server
->log_end
;
1173 static struct commit
*
1174 find_commit(struct cluster
*c
, uint64_t term
)
1176 struct commit
*commit
;
1177 HMAP_FOR_EACH_WITH_HASH (commit
, hmap_node
, hash_uint64(term
),
1179 if (term
== commit
->term
) {
1187 record_commit(struct cluster
*c
, uint64_t term
, struct server
*server
,
1188 uint64_t commit_index
)
1190 struct commit
*commit
= find_commit(c
, term
);
1192 if (commit_index
> commit
->index
) {
1193 commit
->server
= server
;
1194 commit
->index
= commit_index
;
1197 commit
= xmalloc(sizeof *commit
);
1198 hmap_insert(&c
->commits
, &commit
->hmap_node
, hash_uint64(term
));
1199 commit
->term
= term
;
1200 commit
->server
= server
;
1201 commit
->index
= commit_index
;
1206 do_check_cluster(struct ovs_cmdl_context
*ctx
)
1208 struct cluster c
= {
1209 .servers
= xzalloc((ctx
->argc
- 1) * sizeof *c
.servers
),
1211 .leaders
= HMAP_INITIALIZER(&c
.leaders
),
1212 .commits
= HMAP_INITIALIZER(&c
.commits
),
1215 uint64_t min_term
= UINT64_MAX
;
1216 uint64_t max_term
= 0;
1218 for (int i
= 1; i
< ctx
->argc
; i
++) {
1219 struct server
*s
= &c
.servers
[c
.n_servers
];
1220 s
->filename
= ctx
->argv
[i
];
1222 check_ovsdb_error(ovsdb_log_open(s
->filename
, RAFT_MAGIC
,
1223 OVSDB_LOG_READ_ONLY
, -1, &s
->log
));
1226 check_ovsdb_error(ovsdb_log_read(s
->log
, &json
));
1227 check_ovsdb_error(raft_header_from_json(&s
->header
, json
));
1230 if (s
->header
.joining
) {
1231 printf("%s has not joined the cluster, omitting\n", s
->filename
);
1232 ovsdb_log_close(s
->log
);
1235 for (size_t j
= 0; j
< c
.n_servers
; j
++) {
1236 if (uuid_equals(&s
->header
.sid
, &c
.servers
[j
].header
.sid
)) {
1237 ovs_fatal(0, "Duplicate server ID "SID_FMT
" in %s and %s.",
1238 SID_ARGS(&s
->header
.sid
),
1239 s
->filename
, c
.servers
[j
].filename
);
1242 if (c
.n_servers
> 0) {
1243 struct server
*s0
= &c
.servers
[0];
1244 if (!uuid_equals(&s0
->header
.cid
, &s
->header
.cid
)) {
1245 ovs_fatal(0, "%s has cluster ID "CID_FMT
" but %s "
1246 "has cluster ID "CID_FMT
,
1247 s0
->filename
, CID_ARGS(&s0
->header
.cid
),
1248 s
->filename
, CID_ARGS(&s
->header
.cid
));
1250 if (strcmp(s0
->header
.name
, s
->header
.name
)) {
1251 ovs_fatal(0, "%s is named \"%s\" but %s is named \"%s\"",
1252 s0
->filename
, s0
->header
.name
,
1253 s
->filename
, s
->header
.name
);
1259 for (struct server
*s
= c
.servers
; s
< &c
.servers
[c
.n_servers
]; s
++) {
1260 s
->snap
= &s
->header
.snap
;
1261 s
->log_start
= s
->log_end
= s
->header
.snap_index
+ 1;
1263 size_t allocated_records
= 0;
1264 size_t allocated_entries
= 0;
1266 uint64_t term
= 0; /* Current term. */
1267 struct uuid vote
= UUID_ZERO
; /* Server 's''s vote in 'term'. */
1268 struct uuid leader
= UUID_ZERO
; /* Cluster leader in 'term'. */
1269 uint64_t leader_rec_idx
= 0; /* Index of last "leader" record. */
1271 uint64_t commit_index
= s
->header
.snap_index
;
1273 for (unsigned long long int rec_idx
= 1; ; rec_idx
++) {
1274 if (s
->n_records
>= allocated_records
) {
1275 s
->records
= x2nrealloc(s
->records
, &allocated_records
,
1276 sizeof *s
->records
);
1280 check_ovsdb_error(ovsdb_log_read(s
->log
, &json
));
1284 struct raft_record
*r
= &s
->records
[s
->n_records
++];
1285 check_ovsdb_error(raft_record_from_json(r
, json
));
1288 if (r
->term
> term
) {
1294 if (term
< min_term
) {
1297 if (term
> max_term
) {
1302 case RAFT_REC_ENTRY
:
1303 if (r
->entry
.index
< commit_index
) {
1304 ovs_fatal(0, "%s: record %llu attempts to truncate log "
1305 "from %"PRIu64
" to %"PRIu64
" entries, but "
1306 "commit index is already %"PRIu64
,
1307 s
->filename
, rec_idx
,
1308 s
->log_end
, r
->entry
.index
,
1310 } else if (r
->entry
.index
> s
->log_end
) {
1311 ovs_fatal(0, "%s: record %llu with index %"PRIu64
" skips "
1312 "past expected index %"PRIu64
, s
->filename
,
1313 rec_idx
, r
->entry
.index
, s
->log_end
);
1316 if (r
->entry
.index
< s
->log_end
) {
1317 bool is_leader
= uuid_equals(&s
->header
.sid
, &leader
);
1319 /* Leader Append-Only property (see Figure 3.2). */
1320 ovs_fatal(0, "%s: record %llu truncates log from "
1321 "%"PRIu64
" to %"PRIu64
" entries while "
1322 "server is leader", s
->filename
, rec_idx
,
1323 s
->log_end
, r
->entry
.index
);
1325 /* This can happen, but it is unusual. */
1326 printf("%s: record %llu truncates log from %"PRIu64
1327 " to %"PRIu64
" entries\n", s
->filename
, rec_idx
,
1328 s
->log_end
, r
->entry
.index
);
1330 s
->log_end
= r
->entry
.index
;
1333 uint64_t prev_term
= (s
->log_end
> s
->log_start
1334 ? s
->entries
[s
->log_end
1335 - s
->log_start
- 1].term
1337 if (r
->term
< prev_term
) {
1338 ovs_fatal(0, "%s: record %llu with index %"PRIu64
" term "
1339 "%"PRIu64
" precedes previous entry's term "
1340 "%"PRIu64
, s
->filename
, rec_idx
,
1341 r
->entry
.index
, r
->term
, prev_term
);
1344 uint64_t log_idx
= s
->log_end
++ - s
->log_start
;
1345 if (log_idx
>= allocated_entries
) {
1346 s
->entries
= x2nrealloc(s
->entries
, &allocated_entries
,
1347 sizeof *s
->entries
);
1349 struct raft_entry
*e
= &s
->entries
[log_idx
];
1351 e
->data
= r
->entry
.data
;
1352 e
->eid
= r
->entry
.eid
;
1353 e
->servers
= r
->entry
.servers
;
1360 if (r
->term
< term
) {
1361 ovs_fatal(0, "%s: record %llu votes for term %"PRIu64
" "
1362 "but current term is %"PRIu64
, s
->filename
,
1363 rec_idx
, r
->term
, term
);
1364 } else if (!uuid_is_zero(&vote
)
1365 && !uuid_equals(&vote
, &r
->sid
)) {
1366 char buf1
[SID_LEN
+ 1];
1367 char buf2
[SID_LEN
+ 1];
1368 ovs_fatal(0, "%s: record %llu votes for %s in term "
1369 "%"PRIu64
" but a previous record for the "
1370 "same term voted for %s", s
->filename
,
1372 get_server_name(&c
, &vote
, buf1
, sizeof buf1
),
1374 get_server_name(&c
, &r
->sid
, buf2
, sizeof buf2
));
1381 if (!strcmp(r
->note
, "left")) {
1382 printf("%s: record %llu shows that the server left the "
1383 "cluster\n", s
->filename
, rec_idx
);
1387 case RAFT_REC_COMMIT_INDEX
:
1388 if (r
->commit_index
< commit_index
) {
1389 ovs_fatal(0, "%s: record %llu regresses commit index "
1390 "from %"PRIu64
" to %"PRIu64
, s
->filename
,
1391 rec_idx
, commit_index
, r
->commit_index
);
1392 } else if (r
->commit_index
>= s
->log_end
) {
1393 ovs_fatal(0, "%s: record %llu advances commit index to "
1394 "%"PRIu64
" but last log index is %"PRIu64
,
1395 s
->filename
, rec_idx
, r
->commit_index
,
1398 commit_index
= r
->commit_index
;
1401 record_commit(&c
, term
, s
, r
->commit_index
);
1404 case RAFT_REC_LEADER
:
1405 if (!uuid_equals(&r
->sid
, &leader
)) {
1406 if (uuid_is_zero(&leader
)) {
1408 leader_rec_idx
= rec_idx
;
1410 char buf1
[SID_LEN
+ 1];
1411 char buf2
[SID_LEN
+ 1];
1412 ovs_fatal(0, "%s: record %llu reports leader %s "
1413 "for term %"PRIu64
" but record %"PRIu64
" "
1414 "previously reported the leader as %s "
1416 s
->filename
, rec_idx
,
1417 get_server_name(&c
, &r
->sid
,
1419 term
, leader_rec_idx
,
1420 get_server_name(&c
, &leader
,
1421 buf2
, sizeof buf2
));
1424 record_leader(&c
, term
, s
, &r
->sid
);
1429 ovsdb_log_close(s
->log
);
1433 /* Check the Leader Completeness property from Figure 3.2: If a log entry
1434 * is committed in a given term, then that entry will be present in the
1435 * logs of the leaders for all higher-numbered terms. */
1436 if (min_term
== UINT64_MAX
|| max_term
== 0) {
1437 ovs_fatal(0, "all logs are empty");
1439 struct commit
*commit
= NULL
;
1440 for (uint64_t term
= min_term
; term
<= max_term
; term
++) {
1441 struct leader
*leader
= find_leader(&c
, term
);
1442 if (leader
&& leader
->log_end
1443 && commit
&& commit
->index
>= leader
->log_end
) {
1444 ovs_fatal(0, "leader %s for term %"PRIu64
" has log entries only "
1445 "up to index %"PRIu64
", but index %"PRIu64
" was "
1446 "committed in a previous term (e.g. by %s)",
1447 leader
->server
->filename
, term
, leader
->log_end
- 1,
1448 commit
->index
, commit
->server
->filename
);
1451 struct commit
*next
= find_commit(&c
, term
);
1452 if (next
&& (!commit
|| next
->index
> commit
->index
)) {
1457 /* Section 3.5: Check the Log Matching Property in Figure 3.2:
1459 * - If two entries in different logs have the same index and term, then
1460 * they store the same command.
1462 * - If two entries in different logs have the same index and term, then
1463 * the logs are identical in all preceding entries.
1465 for (size_t i
= 0; i
< c
.n_servers
; i
++) {
1466 for (size_t j
= 0; j
< c
.n_servers
; j
++) {
1467 struct server
*a
= &c
.servers
[i
];
1468 struct server
*b
= &c
.servers
[j
];
1474 bool must_equal
= false;
1475 for (uint64_t idx
= MIN(a
->log_end
, b
->log_end
) - 1;
1476 idx
>= MAX(a
->log_start
, b
->log_start
);
1478 const struct raft_entry
*ae
= &a
->entries
[idx
- a
->log_start
];
1479 const struct raft_entry
*be
= &b
->entries
[idx
- b
->log_start
];
1480 if (ae
->term
== be
->term
) {
1483 if (!must_equal
|| raft_entry_equals(ae
, be
)) {
1486 char *as
= json_to_string(raft_entry_to_json(ae
), JSSF_SORT
);
1487 char *bs
= json_to_string(raft_entry_to_json(be
), JSSF_SORT
);
1488 ovs_fatal(0, "log entries with index %"PRIu64
" differ:\n"
1491 idx
, a
->filename
, as
, b
->filename
, bs
);
1498 for (size_t i
= 0; i
< c
.n_servers
; i
++) {
1499 struct server
*s
= &c
.servers
[i
];
1501 raft_header_uninit(&s
->header
);
1502 for (size_t j
= 0; j
< s
->n_records
; j
++) {
1503 struct raft_record
*r
= &s
->records
[j
];
1505 raft_record_uninit(r
);
1512 struct commit
*next_commit
;
1513 HMAP_FOR_EACH_SAFE (commit
, next_commit
, hmap_node
, &c
.commits
) {
1514 hmap_remove(&c
.commits
, &commit
->hmap_node
);
1517 hmap_destroy(&c
.commits
);
1519 struct leader
*leader
, *next_leader
;
1520 HMAP_FOR_EACH_SAFE (leader
, next_leader
, hmap_node
, &c
.leaders
) {
1521 hmap_remove(&c
.leaders
, &leader
->hmap_node
);
1524 hmap_destroy(&c
.leaders
);
1527 static struct ovsdb_version
1528 parse_version(const char *s
)
1530 struct ovsdb_version version
;
1531 if (!ovsdb_parse_version(s
, &version
)) {
1532 ovs_fatal(0, "%s: not an OVSDB version number in format x.y.z", s
);
1538 do_compare_versions(struct ovs_cmdl_context
*ctx
)
1540 struct ovsdb_version a
= parse_version(ctx
->argv
[1]);
1541 struct ovsdb_version b
= parse_version(ctx
->argv
[3]);
1542 int cmp
= (a
.x
!= b
.x
? (a
.x
> b
.x
? 1 : -1)
1543 : a
.y
!= b
.y
? (a
.y
> b
.y
? 1 : -1)
1544 : a
.z
!= b
.z
? (a
.z
> b
.z
? 1 : -1)
1547 const char *op
= ctx
->argv
[2];
1549 if (!strcmp(op
, "<")) {
1551 } else if (!strcmp(op
, "<=")) {
1553 } else if (!strcmp(op
, "==")) {
1555 } else if (!strcmp(op
, ">=")) {
1557 } else if (!strcmp(op
, ">")) {
1559 } else if (!strcmp(op
, "!=")) {
1562 ovs_fatal(0, "%s: not a relational operator", op
);
1565 exit(result
? 0 : 2);
1569 do_convert_to_standalone(struct ovsdb_log
*log
, struct ovsdb_log
*db_log_data
)
1571 for (unsigned int i
= 0; ; i
++) {
1573 check_ovsdb_error(ovsdb_log_read(log
, &json
));
1579 struct raft_header h
;
1580 check_ovsdb_error(raft_header_from_json(&h
, json
));
1581 raft_header_to_standalone_log(&h
, db_log_data
);
1582 raft_header_uninit(&h
);
1584 struct raft_record r
;
1585 check_ovsdb_error(raft_record_from_json(&r
, json
));
1586 raft_record_to_standalone_log(&r
, db_log_data
);
1587 raft_record_uninit(&r
);
1593 do_cluster_standalone(struct ovs_cmdl_context
*ctx
)
1595 const char *db_file_name
= ctx
->argv
[1];
1596 const char *cluster_db_file_name
= ctx
->argv
[2];
1597 struct ovsdb_log
*log
;
1598 struct ovsdb_log
*db_log_data
;
1600 check_ovsdb_error(ovsdb_log_open(cluster_db_file_name
,
1601 OVSDB_MAGIC
"|"RAFT_MAGIC
,
1602 OVSDB_LOG_READ_ONLY
, -1, &log
));
1603 check_ovsdb_error(ovsdb_log_open(db_file_name
, OVSDB_MAGIC
,
1604 OVSDB_LOG_CREATE_EXCL
, -1, &db_log_data
));
1605 if (strcmp(ovsdb_log_get_magic(log
), RAFT_MAGIC
) != 0) {
1606 ovs_fatal(0, "Database is not clustered db.\n");
1608 do_convert_to_standalone(log
, db_log_data
);
1609 check_ovsdb_error(ovsdb_log_commit_block(db_log_data
));
1610 ovsdb_log_close(db_log_data
);
1611 ovsdb_log_close(log
);
1615 do_help(struct ovs_cmdl_context
*ctx OVS_UNUSED
)
1621 do_list_commands(struct ovs_cmdl_context
*ctx OVS_UNUSED
)
1623 ovs_cmdl_print_commands(get_all_commands());
1626 static const struct ovs_cmdl_command all_commands
[] = {
1627 { "create", "[db [schema]]", 0, 2, do_create
, OVS_RW
},
1628 { "create-cluster", "db contents local", 3, 3, do_create_cluster
, OVS_RW
},
1629 { "join-cluster", "db name local remote...", 4, INT_MAX
, do_join_cluster
,
1631 { "compact", "[db [dst]]", 0, 2, do_compact
, OVS_RW
},
1632 { "convert", "[db [schema [dst]]]", 0, 3, do_convert
, OVS_RW
},
1633 { "needs-conversion", NULL
, 0, 2, do_needs_conversion
, OVS_RO
},
1634 { "db-name", "[db]", 0, 1, do_db_name
, OVS_RO
},
1635 { "db-version", "[db]", 0, 1, do_db_version
, OVS_RO
},
1636 { "db-cksum", "[db]", 0, 1, do_db_cksum
, OVS_RO
},
1637 { "db-cid", "db", 1, 1, do_db_cid
, OVS_RO
},
1638 { "db-sid", "db", 1, 1, do_db_sid
, OVS_RO
},
1639 { "db-local-address", "db", 1, 1, do_db_local_address
, OVS_RO
},
1640 { "db-is-clustered", "db", 1, 1, do_db_is_clustered
, OVS_RO
},
1641 { "db-is-standalone", "db", 1, 1, do_db_is_standalone
, OVS_RO
},
1642 { "schema-name", "[schema]", 0, 1, do_schema_name
, OVS_RO
},
1643 { "schema-version", "[schema]", 0, 1, do_schema_version
, OVS_RO
},
1644 { "schema-cksum", "[schema]", 0, 1, do_schema_cksum
, OVS_RO
},
1645 { "query", "[db] trns", 1, 2, do_query
, OVS_RO
},
1646 { "transact", "[db] trns", 1, 2, do_transact
, OVS_RO
},
1647 { "show-log", "[db]", 0, 1, do_show_log
, OVS_RO
},
1648 { "check-cluster", "db...", 1, INT_MAX
, do_check_cluster
, OVS_RO
},
1649 { "compare-versions", "a op b", 3, 3, do_compare_versions
, OVS_RO
},
1650 { "help", NULL
, 0, INT_MAX
, do_help
, OVS_RO
},
1651 { "list-commands", NULL
, 0, INT_MAX
, do_list_commands
, OVS_RO
},
1652 { "cluster-to-standalone", "db clusterdb", 2, 2,
1653 do_cluster_standalone
, OVS_RW
},
1654 { NULL
, NULL
, 2, 2, NULL
, OVS_RO
},
1657 static const struct ovs_cmdl_command
*get_all_commands(void)
1659 return all_commands
;