[ovs-dev] [PATCH v2] ovsdb-tool: add db-set-election-timer command for clustered databases
Dan Williams
dcbw at redhat.com
Fri May 21 19:25:52 UTC 2021
After creating the new cluster database write a raft entry that
sets the desired election timer. This allows CMSes to set the
election timer at cluster start and avoid an error-prone
election timer modification process after the cluster is up.
Reported-at: https://bugzilla.redhat.com/1831778
Signed-off-by: Dan Williams <dcbw at redhat.com>
---
v2:
- Address Ben's comments; add --help and manpage docs
- Write raft record directly instead of using private raft.c functions
NEWS | 3 ++
ovsdb/ovsdb-tool.1.in | 12 ++++++++
ovsdb/ovsdb-tool.c | 64 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 79 insertions(+)
diff --git a/NEWS b/NEWS
index 402ce59690478..8cf88acf861f2 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,9 @@ Post-v2.15.0
* New option '--no-record-hostname' to disable hostname configuration
in ovsdb on startup.
* New command 'record-hostname-if-not-set' to update hostname in ovsdb.
+ - ovsdb-tool:
+ * New command 'db-set-election-timer' to change a newly created clustered
+ database election timer before a cluster has started.
- DPDK:
* OVS validated with DPDK 20.11.1. It is recommended to use this version
until further releases.
diff --git a/ovsdb/ovsdb-tool.1.in b/ovsdb/ovsdb-tool.1.in
index 3bdda85062b23..1d6d45666a984 100644
--- a/ovsdb/ovsdb-tool.1.in
+++ b/ovsdb/ovsdb-tool.1.in
@@ -25,6 +25,8 @@ ovsdb\-tool \- Open vSwitch database management utility
.br
\fBovsdb\-tool \fR[\fIoptions\fR] \fBdb\-cksum \fR[\fIdb\fR]
.br
+\fBovsdb\-tool \fR[\fIoptions\fR] \fBdb\-set\-election\-timer \fR[\fIdb\fR] \fR[\fIms\fR]
+.br
\fBovsdb\-tool \fR[\fIoptions\fR] \fBschema\-cksum \fR[\fIschema\fR]
.br
\fBovsdb\-tool \fR[\fIoptions\fR] \fBcompare-versions\fI a op b\fR
@@ -221,6 +223,16 @@ The \fBdb\-cksum\fR command is for standalone and active-backup
databases only. For clustered databases, use \fBovsdb\-client\fR's
\fBschema\-cksum\fR command instead.
.
+.IP "\fBdb\-set\-election\-timer \fR[\fIdb\fR] \fR[\fIms\fR]"
+Sets the leader election timeout base value for a newly created clustered
+database \fIdb\fR.
+.IP
+Leader election will be initiated by a follower if there is no heartbeat
+received from the leader within this time plus a random time within 1 second.
+.IP
+The default value is 1000, if not changed with this command. The value must be
+between 100ms and 600000ms (10 minutes) inclusive.
+.
.IP "\fBcompare-versions\fI a op b\fR"
Compares \fIa\fR and \fIb\fR according to \fIop\fR. Both \fIa\fR and
\fIb\fR must be OVSDB schema version numbers in the form
diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c
index b8560f850cd08..e0aaffb0608b0 100644
--- a/ovsdb/ovsdb-tool.c
+++ b/ovsdb/ovsdb-tool.c
@@ -167,6 +167,8 @@ usage(void)
" db-local-address DB report local address of clustered DB\n"
" db-is-clustered DB test whether DB is clustered\n"
" db-is-standalone DB test whether DB is standalone\n"
+ " db-set-election_timer DB ms sets the leader election timer for\n"
+ " newly created clustered database DB to ms milliseconds\n"
" schema-name [SCHEMA] report SCHEMA's name\n"
" schema-version [SCHEMA] report SCHEMA's schema version\n"
" schema-cksum [SCHEMA] report SCHEMA's checksum\n"
@@ -584,6 +586,68 @@ do_db_is_standalone(struct ovs_cmdl_context *ctx)
do_db_has_magic(ctx, OVSDB_MAGIC);
}
+static void
+do_db_set_election_timer(struct ovs_cmdl_context *ctx)
+{
+ const char *db_file_name = ctx->argv[1];
+ const char *timer_ms = ctx->argv[2];
+ uint64_t election_timer = 0;
+
+ election_timer = atoll(timer_ms);
+ /* Election timer smaller than 100ms or bigger than 10min doesn't make
+ * sense. */
+ if (election_timer < 100 || election_timer > 600000) {
+ ovs_fatal(0, "election timer must be between 100 and 600000, "
+ "in msec.");
+ return;
+ }
+
+ struct ovsdb_log *log = NULL;
+ check_ovsdb_error(ovsdb_log_open(db_file_name, RAFT_MAGIC,
+ OVSDB_LOG_READ_WRITE, -1, &log));
+ struct json *json = NULL;
+ check_ovsdb_error(ovsdb_log_read(log, &json));
+ if (!json) {
+ ovs_fatal(0, "failed to find first RAFT record in database.");
+ return;
+ }
+
+ /* Minimally verify the header */
+ struct ovsdb_error *error;
+ struct raft_header h;
+ error = raft_header_from_json(&h, json);
+ raft_header_uninit(&h);
+ json_destroy(json);
+ if (error) {
+ ovs_fatal(0, "failed to read RAFT header: %s",
+ ovsdb_error_to_string(error));
+ return;
+ }
+
+ /* Ensure there is no second record yet */
+ json = NULL;
+ check_ovsdb_error(ovsdb_log_read(log, &json));
+ if (json) {
+ json_destroy(json);
+ ovs_fatal(0, "election timer can only be changed for new databases.");
+ return;
+ }
+
+ struct raft_record r = {
+ .type = RAFT_REC_ENTRY,
+ .term = 1, /* New databases always start at term 1 */
+ .entry = {
+ .index = 2, /* First log entry after header is index 2 */
+ .data = NULL,
+ .servers = NULL,
+ .election_timer = election_timer,
+ .eid = UUID_ZERO,
+ },
+ };
+ check_ovsdb_error(ovsdb_log_write_and_free(log, raft_record_to_json(&r)));
+ ovsdb_log_close(log);
+}
+
static void
do_schema_name(struct ovs_cmdl_context *ctx)
{
@@ -1689,6 +1753,8 @@ static const struct ovs_cmdl_command all_commands[] = {
{ "db-local-address", "db", 1, 1, do_db_local_address, OVS_RO },
{ "db-is-clustered", "db", 1, 1, do_db_is_clustered, OVS_RO },
{ "db-is-standalone", "db", 1, 1, do_db_is_standalone, OVS_RO },
+ { "db-set-election-timer", "db ms", 2, 2,
+ do_db_set_election_timer, OVS_RW },
{ "schema-name", "[schema]", 0, 1, do_schema_name, OVS_RO },
{ "schema-version", "[schema]", 0, 1, do_schema_version, OVS_RO },
{ "schema-cksum", "[schema]", 0, 1, do_schema_cksum, OVS_RO },
--
2.31.1
More information about the dev
mailing list