[ovs-dev] [PATCH RFC 49/52] ovsdb-client: Add new "restore" command.
Ben Pfaff
blp at ovn.org
Tue Sep 19 22:01:22 UTC 2017
Signed-off-by: Ben Pfaff <blp at ovn.org>
---
NEWS | 2 +-
lib/ovsdb-data.c | 76 +++++++++---
lib/ovsdb-data.h | 5 +
lib/ovsdb-idl.c | 20 +---
manpages.mk | 299 ++++++++++++++++++++++++++++++++++++++++++++++++
ovsdb/log.c | 8 +-
ovsdb/ovsdb-client.1.in | 28 ++++-
ovsdb/ovsdb-client.c | 108 +++++++++++++++++
ovsdb/ovsdb.7.xml | 13 ++-
9 files changed, 522 insertions(+), 37 deletions(-)
diff --git a/NEWS b/NEWS
index 686c387d782a..9782818a1b0d 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,7 @@ Post-v2.8.0
* ovsdb-server now always hosts a built-in database named _Server. See
ovsdb-server(5) for more details.
* ovsdb-client: New "get-schema-cksum" command.
- * ovsdb-client: New "backup" command.
+ * ovsdb-client: New "backup" and "restore" commands.
- ovs-vsctl and other commands that display data in tables now support a
--max-column-width option to limit column width.
- OVN:
diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c
index b4ea3dcac227..69122dc10432 100644
--- a/lib/ovsdb-data.c
+++ b/lib/ovsdb-data.c
@@ -1358,15 +1358,26 @@ ovsdb_unconstrained_datum_from_json(struct ovsdb_datum *datum,
return ovsdb_datum_from_json(datum, &relaxed_type, json, NULL);
}
-/* Converts 'datum', of the specified 'type', to JSON format, and returns the
- * JSON. The caller is responsible for freeing the returned JSON.
- *
- * 'type' constraints on datum->n are ignored.
- *
- * Refer to RFC 7047 for the format of the JSON that this function produces. */
-struct json *
-ovsdb_datum_to_json(const struct ovsdb_datum *datum,
- const struct ovsdb_type *type)
+static struct json *
+ovsdb_base_to_json(const union ovsdb_atom *atom,
+ const struct ovsdb_base_type *base,
+ bool use_row_names)
+{
+ if (!use_row_names
+ || base->type != OVSDB_TYPE_UUID
+ || !base->u.uuid.refTableName) {
+ return ovsdb_atom_to_json(atom, base->type);
+ } else {
+ return json_array_create_2(
+ json_string_create("named-uuid"),
+ json_string_create_nocopy(ovsdb_data_row_name(&atom->uuid)));
+ }
+}
+
+static struct json *
+ovsdb_datum_to_json__(const struct ovsdb_datum *datum,
+ const struct ovsdb_type *type,
+ bool use_row_names)
{
if (ovsdb_type_is_map(type)) {
struct json **elems;
@@ -1375,26 +1386,49 @@ ovsdb_datum_to_json(const struct ovsdb_datum *datum,
elems = xmalloc(datum->n * sizeof *elems);
for (i = 0; i < datum->n; i++) {
elems[i] = json_array_create_2(
- ovsdb_atom_to_json(&datum->keys[i], type->key.type),
- ovsdb_atom_to_json(&datum->values[i], type->value.type));
+ ovsdb_base_to_json(&datum->keys[i], &type->key,
+ use_row_names),
+ ovsdb_base_to_json(&datum->values[i], &type->value,
+ use_row_names));
}
return wrap_json("map", json_array_create(elems, datum->n));
} else if (datum->n == 1) {
- return ovsdb_atom_to_json(&datum->keys[0], type->key.type);
+ return ovsdb_base_to_json(&datum->keys[0], &type->key, use_row_names);
} else {
struct json **elems;
size_t i;
elems = xmalloc(datum->n * sizeof *elems);
for (i = 0; i < datum->n; i++) {
- elems[i] = ovsdb_atom_to_json(&datum->keys[i], type->key.type);
+ elems[i] = ovsdb_base_to_json(&datum->keys[i], &type->key,
+ use_row_names);
}
return wrap_json("set", json_array_create(elems, datum->n));
}
}
+/* Converts 'datum', of the specified 'type', to JSON format, and returns the
+ * JSON. The caller is responsible for freeing the returned JSON.
+ *
+ * 'type' constraints on datum->n are ignored.
+ *
+ * Refer to RFC 7047 for the format of the JSON that this function produces. */
+struct json *
+ovsdb_datum_to_json(const struct ovsdb_datum *datum,
+ const struct ovsdb_type *type)
+{
+ return ovsdb_datum_to_json__(datum, type, false);
+}
+
+struct json *
+ovsdb_datum_to_json_with_row_names(const struct ovsdb_datum *datum,
+ const struct ovsdb_type *type)
+{
+ return ovsdb_datum_to_json__(datum, type, true);
+}
+
static const char *
skip_spaces(const char *p)
{
@@ -2180,3 +2214,19 @@ ovsdb_atom_range_check_size(int64_t range_start, int64_t range_end)
}
return NULL;
}
+
+char *
+ovsdb_data_row_name(const struct uuid *uuid)
+{
+ char *name;
+ char *p;
+
+ name = xasprintf("row"UUID_FMT, UUID_ARGS(uuid));
+ for (p = name; *p != '\0'; p++) {
+ if (*p == '-') {
+ *p = '_';
+ }
+ }
+
+ return name;
+}
diff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h
index 835d0a8a14e7..14716912ea49 100644
--- a/lib/ovsdb-data.h
+++ b/lib/ovsdb-data.h
@@ -251,6 +251,11 @@ void ovsdb_datum_add_unsafe(struct ovsdb_datum *,
const struct ovsdb_type *,
const union ovsdb_atom *range_end_atom);
+/* Transactions with named-uuid row names. */
+struct json *ovsdb_datum_to_json_with_row_names(const struct ovsdb_datum *,
+ const struct ovsdb_type *);
+char *ovsdb_data_row_name(const struct uuid *);
+
/* Type checking. */
static inline bool
ovsdb_datum_conforms_to_type(const struct ovsdb_datum *datum,
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index 6cb1404735d1..949c15e11940 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -3178,22 +3178,6 @@ where_uuid_equals(const struct uuid *uuid)
xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
}
-static char *
-uuid_name_from_uuid(const struct uuid *uuid)
-{
- char *name;
- char *p;
-
- name = xasprintf("row"UUID_FMT, UUID_ARGS(uuid));
- for (p = name; *p != '\0'; p++) {
- if (*p == '-') {
- *p = '_';
- }
- }
-
- return name;
-}
-
static const struct ovsdb_idl_row *
ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn *txn, const struct uuid *uuid)
{
@@ -3228,7 +3212,7 @@ substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)
return json_array_create_2(
json_string_create("named-uuid"),
- json_string_create_nocopy(uuid_name_from_uuid(&uuid)));
+ json_string_create_nocopy(ovsdb_data_row_name(&uuid)));
}
}
@@ -3643,7 +3627,7 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
json_object_put(op, "uuid-name",
json_string_create_nocopy(
- uuid_name_from_uuid(&row->uuid)));
+ ovsdb_data_row_name(&row->uuid)));
insert = xmalloc(sizeof *insert);
insert->dummy = row->uuid;
diff --git a/manpages.mk b/manpages.mk
index e69de29bb2d1..7d6a507e0039 100644
--- a/manpages.mk
+++ b/manpages.mk
@@ -0,0 +1,299 @@
+# Generated automatically -- do not modify! -*- buffer-read-only: t -*-
+
+ovn/utilities/ovn-detrace.1: \
+ ovn/utilities/ovn-detrace.1.in \
+ lib/common-syn.man \
+ lib/common.man
+ovn/utilities/ovn-detrace.1.in:
+lib/common-syn.man:
+lib/common.man:
+
+ovn/utilities/ovn-sbctl.8: \
+ ovn/utilities/ovn-sbctl.8.in \
+ lib/common.man \
+ lib/db-ctl-base.man \
+ lib/ssl-bootstrap.man \
+ lib/ssl-peer-ca-cert.man \
+ lib/ssl.man \
+ lib/table.man \
+ lib/vlog.man
+ovn/utilities/ovn-sbctl.8.in:
+lib/common.man:
+lib/db-ctl-base.man:
+lib/ssl-bootstrap.man:
+lib/ssl-peer-ca-cert.man:
+lib/ssl.man:
+lib/table.man:
+lib/vlog.man:
+
+ovsdb/ovsdb-client.1: \
+ ovsdb/ovsdb-client.1.in \
+ lib/common-syn.man \
+ lib/common.man \
+ lib/daemon-syn.man \
+ lib/daemon.man \
+ lib/ssl-bootstrap-syn.man \
+ lib/ssl-bootstrap.man \
+ lib/ssl-connect-syn.man \
+ lib/ssl-connect.man \
+ lib/ssl-syn.man \
+ lib/ssl.man \
+ lib/table.man \
+ lib/vlog-syn.man \
+ lib/vlog.man \
+ ovsdb/ovsdb-schemas.man
+ovsdb/ovsdb-client.1.in:
+lib/common-syn.man:
+lib/common.man:
+lib/daemon-syn.man:
+lib/daemon.man:
+lib/ssl-bootstrap-syn.man:
+lib/ssl-bootstrap.man:
+lib/ssl-connect-syn.man:
+lib/ssl-connect.man:
+lib/ssl-syn.man:
+lib/ssl.man:
+lib/table.man:
+lib/vlog-syn.man:
+lib/vlog.man:
+ovsdb/ovsdb-schemas.man:
+
+ovsdb/ovsdb-server.1: \
+ ovsdb/ovsdb-server.1.in \
+ lib/common-syn.man \
+ lib/common.man \
+ lib/coverage-unixctl.man \
+ lib/daemon-syn.man \
+ lib/daemon.man \
+ lib/memory-unixctl.man \
+ lib/service-syn.man \
+ lib/service.man \
+ lib/ssl-bootstrap-syn.man \
+ lib/ssl-bootstrap.man \
+ lib/ssl-connect-syn.man \
+ lib/ssl-connect.man \
+ lib/ssl-peer-ca-cert-syn.man \
+ lib/ssl-peer-ca-cert.man \
+ lib/ssl-syn.man \
+ lib/ssl.man \
+ lib/unixctl-syn.man \
+ lib/unixctl.man \
+ lib/vlog-syn.man \
+ lib/vlog-unixctl.man \
+ lib/vlog.man
+ovsdb/ovsdb-server.1.in:
+lib/common-syn.man:
+lib/common.man:
+lib/coverage-unixctl.man:
+lib/daemon-syn.man:
+lib/daemon.man:
+lib/memory-unixctl.man:
+lib/service-syn.man:
+lib/service.man:
+lib/ssl-bootstrap-syn.man:
+lib/ssl-bootstrap.man:
+lib/ssl-connect-syn.man:
+lib/ssl-connect.man:
+lib/ssl-peer-ca-cert-syn.man:
+lib/ssl-peer-ca-cert.man:
+lib/ssl-syn.man:
+lib/ssl.man:
+lib/unixctl-syn.man:
+lib/unixctl.man:
+lib/vlog-syn.man:
+lib/vlog-unixctl.man:
+lib/vlog.man:
+
+ovsdb/ovsdb-tool.1: \
+ ovsdb/ovsdb-tool.1.in \
+ lib/common-syn.man \
+ lib/common.man \
+ lib/vlog-syn.man \
+ lib/vlog.man \
+ ovsdb/ovsdb-schemas.man
+ovsdb/ovsdb-tool.1.in:
+lib/common-syn.man:
+lib/common.man:
+lib/vlog-syn.man:
+lib/vlog.man:
+ovsdb/ovsdb-schemas.man:
+
+utilities/bugtool/ovs-bugtool.8: \
+ utilities/bugtool/ovs-bugtool.8.in
+utilities/bugtool/ovs-bugtool.8.in:
+
+utilities/ovs-appctl.8: \
+ utilities/ovs-appctl.8.in \
+ lib/common.man
+utilities/ovs-appctl.8.in:
+lib/common.man:
+
+utilities/ovs-dpctl-top.8: \
+ utilities/ovs-dpctl-top.8.in
+utilities/ovs-dpctl-top.8.in:
+
+utilities/ovs-dpctl.8: \
+ utilities/ovs-dpctl.8.in \
+ lib/common.man \
+ lib/dpctl.man \
+ lib/vlog.man
+utilities/ovs-dpctl.8.in:
+lib/common.man:
+lib/dpctl.man:
+lib/vlog.man:
+
+utilities/ovs-l3ping.8: \
+ utilities/ovs-l3ping.8.in \
+ lib/common-syn.man \
+ lib/common.man
+utilities/ovs-l3ping.8.in:
+lib/common-syn.man:
+lib/common.man:
+
+utilities/ovs-ofctl.8: \
+ utilities/ovs-ofctl.8.in \
+ lib/colors.man \
+ lib/common.man \
+ lib/daemon.man \
+ lib/ofp-version.man \
+ lib/ssl.man \
+ lib/unixctl.man \
+ lib/vconn-active.man \
+ lib/vlog.man
+utilities/ovs-ofctl.8.in:
+lib/colors.man:
+lib/common.man:
+lib/daemon.man:
+lib/ofp-version.man:
+lib/ssl.man:
+lib/unixctl.man:
+lib/vconn-active.man:
+lib/vlog.man:
+
+utilities/ovs-pcap.1: \
+ utilities/ovs-pcap.1.in \
+ lib/common-syn.man \
+ lib/common.man
+utilities/ovs-pcap.1.in:
+lib/common-syn.man:
+lib/common.man:
+
+utilities/ovs-pki.8: \
+ utilities/ovs-pki.8.in
+utilities/ovs-pki.8.in:
+
+utilities/ovs-tcpdump.8: \
+ utilities/ovs-tcpdump.8.in \
+ lib/common.man
+utilities/ovs-tcpdump.8.in:
+lib/common.man:
+
+utilities/ovs-tcpundump.1: \
+ utilities/ovs-tcpundump.1.in \
+ lib/common-syn.man \
+ lib/common.man
+utilities/ovs-tcpundump.1.in:
+lib/common-syn.man:
+lib/common.man:
+
+utilities/ovs-testcontroller.8: \
+ utilities/ovs-testcontroller.8.in \
+ lib/common.man \
+ lib/daemon.man \
+ lib/ofp-version.man \
+ lib/ssl-peer-ca-cert.man \
+ lib/ssl.man \
+ lib/unixctl.man \
+ lib/vconn-active.man \
+ lib/vconn-passive.man \
+ lib/vlog.man
+utilities/ovs-testcontroller.8.in:
+lib/common.man:
+lib/daemon.man:
+lib/ofp-version.man:
+lib/ssl-peer-ca-cert.man:
+lib/ssl.man:
+lib/unixctl.man:
+lib/vconn-active.man:
+lib/vconn-passive.man:
+lib/vlog.man:
+
+utilities/ovs-vlan-bug-workaround.8: \
+ utilities/ovs-vlan-bug-workaround.8.in \
+ lib/common.man \
+ utilities/ovs-vlan-bugs.man
+utilities/ovs-vlan-bug-workaround.8.in:
+lib/common.man:
+utilities/ovs-vlan-bugs.man:
+
+utilities/ovs-vsctl.8: \
+ utilities/ovs-vsctl.8.in \
+ lib/common.man \
+ lib/db-ctl-base.man \
+ lib/ssl-bootstrap.man \
+ lib/ssl-peer-ca-cert.man \
+ lib/ssl.man \
+ lib/table.man \
+ lib/vconn-active.man \
+ lib/vconn-passive.man \
+ lib/vlog.man
+utilities/ovs-vsctl.8.in:
+lib/common.man:
+lib/db-ctl-base.man:
+lib/ssl-bootstrap.man:
+lib/ssl-peer-ca-cert.man:
+lib/ssl.man:
+lib/table.man:
+lib/vconn-active.man:
+lib/vconn-passive.man:
+lib/vlog.man:
+
+vswitchd/ovs-vswitchd.8: \
+ vswitchd/ovs-vswitchd.8.in \
+ lib/common.man \
+ lib/coverage-unixctl.man \
+ lib/daemon.man \
+ lib/dpctl.man \
+ lib/memory-unixctl.man \
+ lib/service.man \
+ lib/ssl-bootstrap.man \
+ lib/ssl.man \
+ lib/unixctl.man \
+ lib/vlog-unixctl.man \
+ lib/vlog.man \
+ ofproto/ofproto-dpif-unixctl.man \
+ ofproto/ofproto-tnl-unixctl.man \
+ ofproto/ofproto-unixctl.man
+vswitchd/ovs-vswitchd.8.in:
+lib/common.man:
+lib/coverage-unixctl.man:
+lib/daemon.man:
+lib/dpctl.man:
+lib/memory-unixctl.man:
+lib/service.man:
+lib/ssl-bootstrap.man:
+lib/ssl.man:
+lib/unixctl.man:
+lib/vlog-unixctl.man:
+lib/vlog.man:
+ofproto/ofproto-dpif-unixctl.man:
+ofproto/ofproto-tnl-unixctl.man:
+ofproto/ofproto-unixctl.man:
+
+vtep/vtep-ctl.8: \
+ vtep/vtep-ctl.8.in \
+ lib/common.man \
+ lib/db-ctl-base.man \
+ lib/ssl-bootstrap.man \
+ lib/ssl-peer-ca-cert.man \
+ lib/ssl.man \
+ lib/table.man \
+ lib/vlog.man
+vtep/vtep-ctl.8.in:
+lib/common.man:
+lib/db-ctl-base.man:
+lib/ssl-bootstrap.man:
+lib/ssl-peer-ca-cert.man:
+lib/ssl.man:
+lib/table.man:
+lib/vlog.man:
diff --git a/ovsdb/log.c b/ovsdb/log.c
index adc14761cd8a..7f05fb083246 100644
--- a/ovsdb/log.c
+++ b/ovsdb/log.c
@@ -116,7 +116,13 @@ ovsdb_log_open(const char *name, const char *magic,
#ifdef _WIN32
flags = flags | O_BINARY;
#endif
- fd = open(name, flags, 0666);
+ /* Special case for /dev/stdin to make it work even if the operating system
+ * doesn't support it under that name. */
+ if (!strcmp(name, "/dev/stdin") && open_mode == OVSDB_LOG_READ_ONLY) {
+ fd = dup(STDIN_FILENO);
+ } else {
+ fd = open(name, flags, 0666);
+ }
if (fd < 0) {
const char *op = (open_mode == OVSDB_LOG_CREATE_EXCL ? "create"
: open_mode == OVSDB_LOG_CREATE ? "create or open"
diff --git a/ovsdb/ovsdb-client.1.in b/ovsdb/ovsdb-client.1.in
index 26f007258c09..cd17467147da 100644
--- a/ovsdb/ovsdb-client.1.in
+++ b/ovsdb/ovsdb-client.1.in
@@ -36,6 +36,9 @@ ovsdb\-client \- command-line interface to \fBovsdb-server\fR(1)
\fBovsdb\-client \fR[\fIoptions\fR]
\fBbackup\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] > \fIsnapshot\fR
.br
+\fBovsdb\-client \fR[\fIoptions\fR] [\fB\-\-force\fR]
+\fBrestore\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] < \fIsnapshot\fR
+.br
\fBovsdb\-client \fR[\fIoptions\fR] \fBmonitor\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fItable\fR
[\fIcolumn\fR[\fB,\fIcolumn\fR]...]...
.br
@@ -44,7 +47,6 @@ ovsdb\-client \- command-line interface to \fBovsdb-server\fR(1)
\fBovsdb\-client \fR[\fIoptions\fR] \fBmonitor\-cond\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fIconditions
\fItable\fR [\fIcolumn\fR[\fB,\fIcolumn\fR]...]...
.IP "Testing Commands:"
-.br
\fBovsdb\-client \fR[\fIoptions\fR] \fBlock\fI \fR[\fIserver\fR] \fIlock\fR
.br
\fBovsdb\-client \fR[\fIoptions\fR] \fBsteal\fI \fR[\fIserver\fR] \fIlock\fR
@@ -203,6 +205,30 @@ database is in use.
The output does not include ephemeral columns, which by design do not
survive across restarts of \fBovsdb\-server\fR.
.
+.IP "[\fB\-\-force\fR] \fBrestore\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] < \fIsnapshot\fR"
+Reads \fIsnapshot\fR, which must be in the format used for OVSDB
+standalone and active-backup databases. Then, connects to
+\fIserver\fR, verifies that \fIdatabase\fR and \fIsnapshot\fR have the
+same schema, then deletes all of the data in \fIdatabase\fR and
+replaces it by \fIsnapshot\fR. The replacement happens atomically, in a
+single transaction.
+.IP
+UUIDs for rows in the restored database will differ from those in
+\fIsnapshot\fR, because the OVSDB protocol does not allow clients to
+specify row UUIDs. Another way to restore a database,
+which does also restore row UUIDs, is to stop
+the server or servers, replace the database file by the snapshot, then
+restart the database. Either way, ephemeral columns are not restored,
+since by design they do not survive across restarts of
+\fBovsdb\-server\fR.
+.IP
+Normally \fBrestore\fR exits with a failure if \fBsnapshot\fR and the
+server's database have different schemas. In such a case, it is a
+good idea to convert the database to the new schema before restoring,
+e.g. with \fBovsdb\-client convert\fR. Use \fB\-\-force\fR to proceed
+regardless of schema differences even though the restore might fail
+with an error or succeed with surprising results.
+.
.IP "\fBmonitor\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fItable\fR [\fIcolumn\fR[\fB,\fIcolumn\fR]...]..."
.IQ "\fBmonitor\-cond\fI \fR[\fIserver\fR] \fR[\fIdatabase\fR] \fIconditions\fR \fItable\fR [\fIcolumn\fR[\fB,\fIcolumn\fR]...]..."
Connects to \fIserver\fR and monitors the contents of rows that match conditions in
diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
index bfffc08effb0..056aa25c8983 100644
--- a/ovsdb/ovsdb-client.c
+++ b/ovsdb/ovsdb-client.c
@@ -41,6 +41,7 @@
#include "ovsdb-data.h"
#include "ovsdb-error.h"
#include "poll-loop.h"
+#include "row.h"
#include "sort.h"
#include "svec.h"
#include "stream.h"
@@ -85,6 +86,9 @@ static bool timestamp;
* actually works.) */
static int db_change_aware = -1;
+/* --force: Ignore schema differences for "restore" command? */
+static bool force;
+
/* Format for table output. */
static struct table_style table_style = TABLE_STYLE_DEFAULT;
@@ -196,6 +200,7 @@ parse_options(int argc, char *argv[])
enum {
OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
OPT_TIMESTAMP,
+ OPT_FORCE,
VLOG_OPTION_ENUMS,
DAEMON_OPTION_ENUMS,
TABLE_OPTION_ENUMS,
@@ -207,6 +212,7 @@ parse_options(int argc, char *argv[])
{"timestamp", no_argument, NULL, OPT_TIMESTAMP},
{"db-change-aware", no_argument, &db_change_aware, 1},
{"no-db-change-aware", no_argument, &db_change_aware, 0},
+ {"force", no_argument, NULL, OPT_FORCE},
VLOG_LONG_OPTIONS,
DAEMON_LONG_OPTIONS,
#ifdef HAVE_OPENSSL
@@ -249,6 +255,10 @@ parse_options(int argc, char *argv[])
timestamp = true;
break;
+ case OPT_FORCE:
+ force = true;
+ break;
+
case '?':
exit(EXIT_FAILURE);
@@ -304,6 +314,8 @@ usage(void)
" dump contents of DATABASE on SERVER to stdout\n"
"\n backup [SERVER] [DATABASE] > DB\n"
" dump database contents in the form of a database file\n"
+ "\n [--force] restore [SERVER] [DATABASE] < DB\n"
+ " restore database contents from a database file\n"
"\n lock [SERVER] LOCK\n"
" create or wait for LOCK in SERVER\n"
"\n steal [SERVER] LOCK\n"
@@ -1607,6 +1619,101 @@ do_backup(struct jsonrpc *rpc, const char *database,
}
static void
+do_restore(struct jsonrpc *rpc, const char *database,
+ int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ if (isatty(STDIN_FILENO)) {
+ ovs_fatal(0, "not reading backup from a terminal; "
+ "please redirect stdin from a file");
+ }
+
+ struct ovsdb *backup;
+ check_ovsdb_error(ovsdb_file_open("/dev/stdin", true, &backup, NULL));
+
+ const struct ovsdb_schema *schema = backup->schema;
+ struct ovsdb_schema *schema2 = fetch_schema(rpc, database);
+ if (!ovsdb_schema_equal(schema, schema2)) {
+ struct ds s = DS_EMPTY_INITIALIZER;
+ if (strcmp(schema->version, schema2->version)) {
+ ds_put_format(&s, "backup schema has version \"%s\" but "
+ "database schema has version \"%s\"",
+ schema->version, schema2->version);
+ } else {
+ ds_put_format(&s, "backup schema and database schema are "
+ "both version %s but still differ",
+ schema->version);
+ }
+ if (!force) {
+ ovs_fatal(0, "%s (use --force to override differences, or "
+ "\"ovsdb-client convert\" to change the schema)",
+ ds_cstr(&s));
+ }
+ VLOG_INFO("%s", ds_cstr(&s));
+ ds_destroy(&s);
+ }
+
+ struct json *txn = json_array_create_empty();
+ json_array_add(txn, json_string_create(schema->name));
+ struct shash_node *node;
+ SHASH_FOR_EACH (node, &backup->tables) {
+ const char *table_name = node->name;
+ struct ovsdb_table *table = node->data;
+
+ struct json *del_op = json_object_create();
+ json_object_put_string(del_op, "op", "delete");
+ json_object_put_string(del_op, "table", table_name);
+ json_object_put(del_op, "where", json_array_create_empty());
+ json_array_add(txn, del_op);
+
+ const struct ovsdb_row *row;
+ HMAP_FOR_EACH (row, hmap_node, &table->rows) {
+ struct json *ins_op = json_object_create();
+ json_object_put_string(ins_op, "op", "insert");
+ json_object_put_string(ins_op, "table", table_name);
+ json_object_put(ins_op, "uuid-name",
+ json_string_create_nocopy(
+ ovsdb_data_row_name(ovsdb_row_get_uuid(row))));
+ struct json *row_json = json_object_create();
+ json_object_put(ins_op, "row", row_json);
+
+ struct shash_node *node2;
+ SHASH_FOR_EACH (node2, &table->schema->columns) {
+ const struct ovsdb_column *column = node2->data;
+ const struct ovsdb_datum *datum = &row->fields[column->index];
+ const struct ovsdb_type *type = &column->type;
+ if (column->persistent
+ && column->index >= OVSDB_N_STD_COLUMNS
+ && !ovsdb_datum_is_default(datum, type)) {
+ struct json *value = ovsdb_datum_to_json_with_row_names(
+ datum, type);
+ json_object_put(row_json, column->name, value);
+ }
+ }
+ json_array_add(txn, ins_op);
+ }
+ }
+ struct jsonrpc_msg *rq = jsonrpc_create_request("transact", txn, NULL);
+ struct jsonrpc_msg *reply;
+ check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);
+ if (reply->result->type != JSON_ARRAY) {
+ ovs_fatal(0, "result is not array");
+ }
+ for (size_t i = 0; i < json_array(reply->result)->n; i++) {
+ struct json *json = json_array(reply->result)->elems[i];
+ if (json->type != JSON_OBJECT) {
+ ovs_fatal(0, "result array element is not object");
+ }
+ struct shash *object = json_object(json);
+ if (shash_find(object, "error")) {
+ ovs_fatal(0, "server returned error reply: %s",
+ json_to_string(json, JSSF_SORT));
+ }
+ }
+ jsonrpc_msg_destroy(reply);
+}
+
+
+static void
do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
@@ -1821,6 +1928,7 @@ static const struct ovsdb_client_command all_commands[] = {
{ "needs-conversion", NEED_RPC, 1, 1, do_needs_conversion },
{ "dump", NEED_DATABASE, 0, INT_MAX, do_dump },
{ "backup", NEED_DATABASE, 0, 0, do_backup },
+ { "restore", NEED_DATABASE, 0, 0, do_restore },
{ "lock", NEED_RPC, 1, 1, do_lock_create },
{ "steal", NEED_RPC, 1, 1, do_lock_steal },
{ "unlock", NEED_RPC, 1, 1, do_lock_unlock },
diff --git a/ovsdb/ovsdb.7.xml b/ovsdb/ovsdb.7.xml
index 5461f252a03a..8169120c88f2 100644
--- a/ovsdb/ovsdb.7.xml
+++ b/ovsdb/ovsdb.7.xml
@@ -410,9 +410,16 @@
</p>
<p>
- To restore from a backup, stop the database server or servers, overwrite
- the database file with the backup (e.g. with <code>cp</code>), and then
- restart the servers.
+ Multiple options are also available when the time comes to restore a
+ database from a backup. One option is to stop the database server or
+ servers, overwrite the database file with the backup (e.g. with
+ <code>cp</code>), and then restart the servers. Another way is to use
+ <code>ovsdb-client restore</code>, which connects to a running database
+ server and replaces the data in one of its databases by a provided
+ snapshot. Using <code>ovsdb-client restore</code> has the disadvantage
+ that UUIDs of rows in the restored database will differ from those in the
+ snapshot, because the OVSDB protocol does not allow clients to specify row
+ UUIDs.
</p>
<p>
--
2.10.2
More information about the dev
mailing list