Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/815902/?format=api
{ "id": 815902, "url": "http://patchwork.ozlabs.org/api/patches/815902/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170919220125.32535-50-blp@ovn.org/", "project": { "id": 47, "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api", "name": "Open vSwitch", "link_name": "openvswitch", "list_id": "ovs-dev.openvswitch.org", "list_email": "ovs-dev@openvswitch.org", "web_url": "http://openvswitch.org/", "scm_url": "git@github.com:openvswitch/ovs.git", "webscm_url": "https://github.com/openvswitch/ovs", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170919220125.32535-50-blp@ovn.org>", "list_archive_url": null, "date": "2017-09-19T22:01:22", "name": "[ovs-dev,RFC,49/52] ovsdb-client: Add new \"restore\" command.", "commit_ref": null, "pull_url": null, "state": "rfc", "archived": false, "hash": "4c0b90b226488963d7aa1dfa61fc4452d0693e88", "submitter": { "id": 67603, "url": "http://patchwork.ozlabs.org/api/people/67603/?format=api", "name": "Ben Pfaff", "email": "blp@ovn.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170919220125.32535-50-blp@ovn.org/mbox/", "series": [ { "id": 3975, "url": "http://patchwork.ozlabs.org/api/series/3975/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=3975", "date": "2017-09-19T22:00:34", "name": "clustering implementation", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/3975/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/815902/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/815902/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<ovs-dev-bounces@openvswitch.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "dev@openvswitch.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "ovs-dev@mail.linuxfoundation.org" ], "Authentication-Results": "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xxctX44khz9sNV\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 20 Sep 2017 08:27:00 +1000 (AEST)", "from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 82CDCD5E;\n\tTue, 19 Sep 2017 22:03:01 +0000 (UTC)", "from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id C2CE7CFB\n\tfor <dev@openvswitch.org>; Tue, 19 Sep 2017 22:02:58 +0000 (UTC)", "from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net\n\t[217.70.183.196])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 3FBDB3D4\n\tfor <dev@openvswitch.org>; Tue, 19 Sep 2017 22:02:57 +0000 (UTC)", "from sigabrt.benpfaff.org (unknown [208.91.2.3])\n\t(Authenticated sender: blp@ovn.org)\n\tby relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 13B2D17209B;\n\tWed, 20 Sep 2017 00:02:54 +0200 (CEST)" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "X-Originating-IP": "208.91.2.3", "From": "Ben Pfaff <blp@ovn.org>", "To": "dev@openvswitch.org", "Date": "Tue, 19 Sep 2017 15:01:22 -0700", "Message-Id": "<20170919220125.32535-50-blp@ovn.org>", "X-Mailer": "git-send-email 2.10.2", "In-Reply-To": "<20170919220125.32535-1-blp@ovn.org>", "References": "<20170919220125.32535-1-blp@ovn.org>", "X-Spam-Status": "No, score=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW\n\tautolearn=disabled version=3.3.1", "X-Spam-Checker-Version": "SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org", "Cc": "Ben Pfaff <blp@ovn.org>", "Subject": "[ovs-dev] [PATCH RFC 49/52] ovsdb-client: Add new \"restore\" command.", "X-BeenThere": "ovs-dev@openvswitch.org", "X-Mailman-Version": "2.1.12", "Precedence": "list", "List-Id": "<ovs-dev.openvswitch.org>", "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>", "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>", "List-Post": "<mailto:ovs-dev@openvswitch.org>", "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>", "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Sender": "ovs-dev-bounces@openvswitch.org", "Errors-To": "ovs-dev-bounces@openvswitch.org" }, "content": "Signed-off-by: Ben Pfaff <blp@ovn.org>\n---\n NEWS | 2 +-\n lib/ovsdb-data.c | 76 +++++++++---\n lib/ovsdb-data.h | 5 +\n lib/ovsdb-idl.c | 20 +---\n manpages.mk | 299 ++++++++++++++++++++++++++++++++++++++++++++++++\n ovsdb/log.c | 8 +-\n ovsdb/ovsdb-client.1.in | 28 ++++-\n ovsdb/ovsdb-client.c | 108 +++++++++++++++++\n ovsdb/ovsdb.7.xml | 13 ++-\n 9 files changed, 522 insertions(+), 37 deletions(-)", "diff": "diff --git a/NEWS b/NEWS\nindex 686c387d782a..9782818a1b0d 100644\n--- a/NEWS\n+++ b/NEWS\n@@ -8,7 +8,7 @@ Post-v2.8.0\n * ovsdb-server now always hosts a built-in database named _Server. See\n ovsdb-server(5) for more details.\n * ovsdb-client: New \"get-schema-cksum\" command.\n- * ovsdb-client: New \"backup\" command.\n+ * ovsdb-client: New \"backup\" and \"restore\" commands.\n - ovs-vsctl and other commands that display data in tables now support a\n --max-column-width option to limit column width.\n - OVN:\ndiff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c\nindex b4ea3dcac227..69122dc10432 100644\n--- a/lib/ovsdb-data.c\n+++ b/lib/ovsdb-data.c\n@@ -1358,15 +1358,26 @@ ovsdb_unconstrained_datum_from_json(struct ovsdb_datum *datum,\n return ovsdb_datum_from_json(datum, &relaxed_type, json, NULL);\n }\n \n-/* Converts 'datum', of the specified 'type', to JSON format, and returns the\n- * JSON. The caller is responsible for freeing the returned JSON.\n- *\n- * 'type' constraints on datum->n are ignored.\n- *\n- * Refer to RFC 7047 for the format of the JSON that this function produces. */\n-struct json *\n-ovsdb_datum_to_json(const struct ovsdb_datum *datum,\n- const struct ovsdb_type *type)\n+static struct json *\n+ovsdb_base_to_json(const union ovsdb_atom *atom,\n+ const struct ovsdb_base_type *base,\n+ bool use_row_names)\n+{\n+ if (!use_row_names\n+ || base->type != OVSDB_TYPE_UUID\n+ || !base->u.uuid.refTableName) {\n+ return ovsdb_atom_to_json(atom, base->type);\n+ } else {\n+ return json_array_create_2(\n+ json_string_create(\"named-uuid\"),\n+ json_string_create_nocopy(ovsdb_data_row_name(&atom->uuid)));\n+ }\n+}\n+\n+static struct json *\n+ovsdb_datum_to_json__(const struct ovsdb_datum *datum,\n+ const struct ovsdb_type *type,\n+ bool use_row_names)\n {\n if (ovsdb_type_is_map(type)) {\n struct json **elems;\n@@ -1375,26 +1386,49 @@ ovsdb_datum_to_json(const struct ovsdb_datum *datum,\n elems = xmalloc(datum->n * sizeof *elems);\n for (i = 0; i < datum->n; i++) {\n elems[i] = json_array_create_2(\n- ovsdb_atom_to_json(&datum->keys[i], type->key.type),\n- ovsdb_atom_to_json(&datum->values[i], type->value.type));\n+ ovsdb_base_to_json(&datum->keys[i], &type->key,\n+ use_row_names),\n+ ovsdb_base_to_json(&datum->values[i], &type->value,\n+ use_row_names));\n }\n \n return wrap_json(\"map\", json_array_create(elems, datum->n));\n } else if (datum->n == 1) {\n- return ovsdb_atom_to_json(&datum->keys[0], type->key.type);\n+ return ovsdb_base_to_json(&datum->keys[0], &type->key, use_row_names);\n } else {\n struct json **elems;\n size_t i;\n \n elems = xmalloc(datum->n * sizeof *elems);\n for (i = 0; i < datum->n; i++) {\n- elems[i] = ovsdb_atom_to_json(&datum->keys[i], type->key.type);\n+ elems[i] = ovsdb_base_to_json(&datum->keys[i], &type->key,\n+ use_row_names);\n }\n \n return wrap_json(\"set\", json_array_create(elems, datum->n));\n }\n }\n \n+/* Converts 'datum', of the specified 'type', to JSON format, and returns the\n+ * JSON. The caller is responsible for freeing the returned JSON.\n+ *\n+ * 'type' constraints on datum->n are ignored.\n+ *\n+ * Refer to RFC 7047 for the format of the JSON that this function produces. */\n+struct json *\n+ovsdb_datum_to_json(const struct ovsdb_datum *datum,\n+ const struct ovsdb_type *type)\n+{\n+ return ovsdb_datum_to_json__(datum, type, false);\n+}\n+\n+struct json *\n+ovsdb_datum_to_json_with_row_names(const struct ovsdb_datum *datum,\n+ const struct ovsdb_type *type)\n+{\n+ return ovsdb_datum_to_json__(datum, type, true);\n+}\n+\n static const char *\n skip_spaces(const char *p)\n {\n@@ -2180,3 +2214,19 @@ ovsdb_atom_range_check_size(int64_t range_start, int64_t range_end)\n }\n return NULL;\n }\n+\f\n+char *\n+ovsdb_data_row_name(const struct uuid *uuid)\n+{\n+ char *name;\n+ char *p;\n+\n+ name = xasprintf(\"row\"UUID_FMT, UUID_ARGS(uuid));\n+ for (p = name; *p != '\\0'; p++) {\n+ if (*p == '-') {\n+ *p = '_';\n+ }\n+ }\n+\n+ return name;\n+}\ndiff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h\nindex 835d0a8a14e7..14716912ea49 100644\n--- a/lib/ovsdb-data.h\n+++ b/lib/ovsdb-data.h\n@@ -251,6 +251,11 @@ void ovsdb_datum_add_unsafe(struct ovsdb_datum *,\n const struct ovsdb_type *,\n const union ovsdb_atom *range_end_atom);\n \n+/* Transactions with named-uuid row names. */\n+struct json *ovsdb_datum_to_json_with_row_names(const struct ovsdb_datum *,\n+ const struct ovsdb_type *);\n+char *ovsdb_data_row_name(const struct uuid *);\n+\n /* Type checking. */\n static inline bool\n ovsdb_datum_conforms_to_type(const struct ovsdb_datum *datum,\ndiff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c\nindex 6cb1404735d1..949c15e11940 100644\n--- a/lib/ovsdb-idl.c\n+++ b/lib/ovsdb-idl.c\n@@ -3178,22 +3178,6 @@ where_uuid_equals(const struct uuid *uuid)\n xasprintf(UUID_FMT, UUID_ARGS(uuid))))));\n }\n \n-static char *\n-uuid_name_from_uuid(const struct uuid *uuid)\n-{\n- char *name;\n- char *p;\n-\n- name = xasprintf(\"row\"UUID_FMT, UUID_ARGS(uuid));\n- for (p = name; *p != '\\0'; p++) {\n- if (*p == '-') {\n- *p = '_';\n- }\n- }\n-\n- return name;\n-}\n-\n static const struct ovsdb_idl_row *\n ovsdb_idl_txn_get_row(const struct ovsdb_idl_txn *txn, const struct uuid *uuid)\n {\n@@ -3228,7 +3212,7 @@ substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)\n \n return json_array_create_2(\n json_string_create(\"named-uuid\"),\n- json_string_create_nocopy(uuid_name_from_uuid(&uuid)));\n+ json_string_create_nocopy(ovsdb_data_row_name(&uuid)));\n }\n }\n \n@@ -3643,7 +3627,7 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)\n \n json_object_put(op, \"uuid-name\",\n json_string_create_nocopy(\n- uuid_name_from_uuid(&row->uuid)));\n+ ovsdb_data_row_name(&row->uuid)));\n \n insert = xmalloc(sizeof *insert);\n insert->dummy = row->uuid;\ndiff --git a/manpages.mk b/manpages.mk\nindex e69de29bb2d1..7d6a507e0039 100644\n--- a/manpages.mk\n+++ b/manpages.mk\n@@ -0,0 +1,299 @@\n+# Generated automatically -- do not modify! -*- buffer-read-only: t -*-\n+\n+ovn/utilities/ovn-detrace.1: \\\n+\tovn/utilities/ovn-detrace.1.in \\\n+\tlib/common-syn.man \\\n+\tlib/common.man\n+ovn/utilities/ovn-detrace.1.in:\n+lib/common-syn.man:\n+lib/common.man:\n+\n+ovn/utilities/ovn-sbctl.8: \\\n+\tovn/utilities/ovn-sbctl.8.in \\\n+\tlib/common.man \\\n+\tlib/db-ctl-base.man \\\n+\tlib/ssl-bootstrap.man \\\n+\tlib/ssl-peer-ca-cert.man \\\n+\tlib/ssl.man \\\n+\tlib/table.man \\\n+\tlib/vlog.man\n+ovn/utilities/ovn-sbctl.8.in:\n+lib/common.man:\n+lib/db-ctl-base.man:\n+lib/ssl-bootstrap.man:\n+lib/ssl-peer-ca-cert.man:\n+lib/ssl.man:\n+lib/table.man:\n+lib/vlog.man:\n+\n+ovsdb/ovsdb-client.1: \\\n+\tovsdb/ovsdb-client.1.in \\\n+\tlib/common-syn.man \\\n+\tlib/common.man \\\n+\tlib/daemon-syn.man \\\n+\tlib/daemon.man \\\n+\tlib/ssl-bootstrap-syn.man \\\n+\tlib/ssl-bootstrap.man \\\n+\tlib/ssl-connect-syn.man \\\n+\tlib/ssl-connect.man \\\n+\tlib/ssl-syn.man \\\n+\tlib/ssl.man \\\n+\tlib/table.man \\\n+\tlib/vlog-syn.man \\\n+\tlib/vlog.man \\\n+\tovsdb/ovsdb-schemas.man\n+ovsdb/ovsdb-client.1.in:\n+lib/common-syn.man:\n+lib/common.man:\n+lib/daemon-syn.man:\n+lib/daemon.man:\n+lib/ssl-bootstrap-syn.man:\n+lib/ssl-bootstrap.man:\n+lib/ssl-connect-syn.man:\n+lib/ssl-connect.man:\n+lib/ssl-syn.man:\n+lib/ssl.man:\n+lib/table.man:\n+lib/vlog-syn.man:\n+lib/vlog.man:\n+ovsdb/ovsdb-schemas.man:\n+\n+ovsdb/ovsdb-server.1: \\\n+\tovsdb/ovsdb-server.1.in \\\n+\tlib/common-syn.man \\\n+\tlib/common.man \\\n+\tlib/coverage-unixctl.man \\\n+\tlib/daemon-syn.man \\\n+\tlib/daemon.man \\\n+\tlib/memory-unixctl.man \\\n+\tlib/service-syn.man \\\n+\tlib/service.man \\\n+\tlib/ssl-bootstrap-syn.man \\\n+\tlib/ssl-bootstrap.man \\\n+\tlib/ssl-connect-syn.man \\\n+\tlib/ssl-connect.man \\\n+\tlib/ssl-peer-ca-cert-syn.man \\\n+\tlib/ssl-peer-ca-cert.man \\\n+\tlib/ssl-syn.man \\\n+\tlib/ssl.man \\\n+\tlib/unixctl-syn.man \\\n+\tlib/unixctl.man \\\n+\tlib/vlog-syn.man \\\n+\tlib/vlog-unixctl.man \\\n+\tlib/vlog.man\n+ovsdb/ovsdb-server.1.in:\n+lib/common-syn.man:\n+lib/common.man:\n+lib/coverage-unixctl.man:\n+lib/daemon-syn.man:\n+lib/daemon.man:\n+lib/memory-unixctl.man:\n+lib/service-syn.man:\n+lib/service.man:\n+lib/ssl-bootstrap-syn.man:\n+lib/ssl-bootstrap.man:\n+lib/ssl-connect-syn.man:\n+lib/ssl-connect.man:\n+lib/ssl-peer-ca-cert-syn.man:\n+lib/ssl-peer-ca-cert.man:\n+lib/ssl-syn.man:\n+lib/ssl.man:\n+lib/unixctl-syn.man:\n+lib/unixctl.man:\n+lib/vlog-syn.man:\n+lib/vlog-unixctl.man:\n+lib/vlog.man:\n+\n+ovsdb/ovsdb-tool.1: \\\n+\tovsdb/ovsdb-tool.1.in \\\n+\tlib/common-syn.man \\\n+\tlib/common.man \\\n+\tlib/vlog-syn.man \\\n+\tlib/vlog.man \\\n+\tovsdb/ovsdb-schemas.man\n+ovsdb/ovsdb-tool.1.in:\n+lib/common-syn.man:\n+lib/common.man:\n+lib/vlog-syn.man:\n+lib/vlog.man:\n+ovsdb/ovsdb-schemas.man:\n+\n+utilities/bugtool/ovs-bugtool.8: \\\n+\tutilities/bugtool/ovs-bugtool.8.in\n+utilities/bugtool/ovs-bugtool.8.in:\n+\n+utilities/ovs-appctl.8: \\\n+\tutilities/ovs-appctl.8.in \\\n+\tlib/common.man\n+utilities/ovs-appctl.8.in:\n+lib/common.man:\n+\n+utilities/ovs-dpctl-top.8: \\\n+\tutilities/ovs-dpctl-top.8.in\n+utilities/ovs-dpctl-top.8.in:\n+\n+utilities/ovs-dpctl.8: \\\n+\tutilities/ovs-dpctl.8.in \\\n+\tlib/common.man \\\n+\tlib/dpctl.man \\\n+\tlib/vlog.man\n+utilities/ovs-dpctl.8.in:\n+lib/common.man:\n+lib/dpctl.man:\n+lib/vlog.man:\n+\n+utilities/ovs-l3ping.8: \\\n+\tutilities/ovs-l3ping.8.in \\\n+\tlib/common-syn.man \\\n+\tlib/common.man\n+utilities/ovs-l3ping.8.in:\n+lib/common-syn.man:\n+lib/common.man:\n+\n+utilities/ovs-ofctl.8: \\\n+\tutilities/ovs-ofctl.8.in \\\n+\tlib/colors.man \\\n+\tlib/common.man \\\n+\tlib/daemon.man \\\n+\tlib/ofp-version.man \\\n+\tlib/ssl.man \\\n+\tlib/unixctl.man \\\n+\tlib/vconn-active.man \\\n+\tlib/vlog.man\n+utilities/ovs-ofctl.8.in:\n+lib/colors.man:\n+lib/common.man:\n+lib/daemon.man:\n+lib/ofp-version.man:\n+lib/ssl.man:\n+lib/unixctl.man:\n+lib/vconn-active.man:\n+lib/vlog.man:\n+\n+utilities/ovs-pcap.1: \\\n+\tutilities/ovs-pcap.1.in \\\n+\tlib/common-syn.man \\\n+\tlib/common.man\n+utilities/ovs-pcap.1.in:\n+lib/common-syn.man:\n+lib/common.man:\n+\n+utilities/ovs-pki.8: \\\n+\tutilities/ovs-pki.8.in\n+utilities/ovs-pki.8.in:\n+\n+utilities/ovs-tcpdump.8: \\\n+\tutilities/ovs-tcpdump.8.in \\\n+\tlib/common.man\n+utilities/ovs-tcpdump.8.in:\n+lib/common.man:\n+\n+utilities/ovs-tcpundump.1: \\\n+\tutilities/ovs-tcpundump.1.in \\\n+\tlib/common-syn.man \\\n+\tlib/common.man\n+utilities/ovs-tcpundump.1.in:\n+lib/common-syn.man:\n+lib/common.man:\n+\n+utilities/ovs-testcontroller.8: \\\n+\tutilities/ovs-testcontroller.8.in \\\n+\tlib/common.man \\\n+\tlib/daemon.man \\\n+\tlib/ofp-version.man \\\n+\tlib/ssl-peer-ca-cert.man \\\n+\tlib/ssl.man \\\n+\tlib/unixctl.man \\\n+\tlib/vconn-active.man \\\n+\tlib/vconn-passive.man \\\n+\tlib/vlog.man\n+utilities/ovs-testcontroller.8.in:\n+lib/common.man:\n+lib/daemon.man:\n+lib/ofp-version.man:\n+lib/ssl-peer-ca-cert.man:\n+lib/ssl.man:\n+lib/unixctl.man:\n+lib/vconn-active.man:\n+lib/vconn-passive.man:\n+lib/vlog.man:\n+\n+utilities/ovs-vlan-bug-workaround.8: \\\n+\tutilities/ovs-vlan-bug-workaround.8.in \\\n+\tlib/common.man \\\n+\tutilities/ovs-vlan-bugs.man\n+utilities/ovs-vlan-bug-workaround.8.in:\n+lib/common.man:\n+utilities/ovs-vlan-bugs.man:\n+\n+utilities/ovs-vsctl.8: \\\n+\tutilities/ovs-vsctl.8.in \\\n+\tlib/common.man \\\n+\tlib/db-ctl-base.man \\\n+\tlib/ssl-bootstrap.man \\\n+\tlib/ssl-peer-ca-cert.man \\\n+\tlib/ssl.man \\\n+\tlib/table.man \\\n+\tlib/vconn-active.man \\\n+\tlib/vconn-passive.man \\\n+\tlib/vlog.man\n+utilities/ovs-vsctl.8.in:\n+lib/common.man:\n+lib/db-ctl-base.man:\n+lib/ssl-bootstrap.man:\n+lib/ssl-peer-ca-cert.man:\n+lib/ssl.man:\n+lib/table.man:\n+lib/vconn-active.man:\n+lib/vconn-passive.man:\n+lib/vlog.man:\n+\n+vswitchd/ovs-vswitchd.8: \\\n+\tvswitchd/ovs-vswitchd.8.in \\\n+\tlib/common.man \\\n+\tlib/coverage-unixctl.man \\\n+\tlib/daemon.man \\\n+\tlib/dpctl.man \\\n+\tlib/memory-unixctl.man \\\n+\tlib/service.man \\\n+\tlib/ssl-bootstrap.man \\\n+\tlib/ssl.man \\\n+\tlib/unixctl.man \\\n+\tlib/vlog-unixctl.man \\\n+\tlib/vlog.man \\\n+\tofproto/ofproto-dpif-unixctl.man \\\n+\tofproto/ofproto-tnl-unixctl.man \\\n+\tofproto/ofproto-unixctl.man\n+vswitchd/ovs-vswitchd.8.in:\n+lib/common.man:\n+lib/coverage-unixctl.man:\n+lib/daemon.man:\n+lib/dpctl.man:\n+lib/memory-unixctl.man:\n+lib/service.man:\n+lib/ssl-bootstrap.man:\n+lib/ssl.man:\n+lib/unixctl.man:\n+lib/vlog-unixctl.man:\n+lib/vlog.man:\n+ofproto/ofproto-dpif-unixctl.man:\n+ofproto/ofproto-tnl-unixctl.man:\n+ofproto/ofproto-unixctl.man:\n+\n+vtep/vtep-ctl.8: \\\n+\tvtep/vtep-ctl.8.in \\\n+\tlib/common.man \\\n+\tlib/db-ctl-base.man \\\n+\tlib/ssl-bootstrap.man \\\n+\tlib/ssl-peer-ca-cert.man \\\n+\tlib/ssl.man \\\n+\tlib/table.man \\\n+\tlib/vlog.man\n+vtep/vtep-ctl.8.in:\n+lib/common.man:\n+lib/db-ctl-base.man:\n+lib/ssl-bootstrap.man:\n+lib/ssl-peer-ca-cert.man:\n+lib/ssl.man:\n+lib/table.man:\n+lib/vlog.man:\ndiff --git a/ovsdb/log.c b/ovsdb/log.c\nindex adc14761cd8a..7f05fb083246 100644\n--- a/ovsdb/log.c\n+++ b/ovsdb/log.c\n@@ -116,7 +116,13 @@ ovsdb_log_open(const char *name, const char *magic,\n #ifdef _WIN32\n flags = flags | O_BINARY;\n #endif\n- fd = open(name, flags, 0666);\n+ /* Special case for /dev/stdin to make it work even if the operating system\n+ * doesn't support it under that name. */\n+ if (!strcmp(name, \"/dev/stdin\") && open_mode == OVSDB_LOG_READ_ONLY) {\n+ fd = dup(STDIN_FILENO);\n+ } else {\n+ fd = open(name, flags, 0666);\n+ }\n if (fd < 0) {\n const char *op = (open_mode == OVSDB_LOG_CREATE_EXCL ? \"create\"\n : open_mode == OVSDB_LOG_CREATE ? \"create or open\"\ndiff --git a/ovsdb/ovsdb-client.1.in b/ovsdb/ovsdb-client.1.in\nindex 26f007258c09..cd17467147da 100644\n--- a/ovsdb/ovsdb-client.1.in\n+++ b/ovsdb/ovsdb-client.1.in\n@@ -36,6 +36,9 @@ ovsdb\\-client \\- command-line interface to \\fBovsdb-server\\fR(1)\n \\fBovsdb\\-client \\fR[\\fIoptions\\fR]\n \\fBbackup\\fI \\fR[\\fIserver\\fR] \\fR[\\fIdatabase\\fR] > \\fIsnapshot\\fR\n .br\n+\\fBovsdb\\-client \\fR[\\fIoptions\\fR] [\\fB\\-\\-force\\fR]\n+\\fBrestore\\fI \\fR[\\fIserver\\fR] \\fR[\\fIdatabase\\fR] < \\fIsnapshot\\fR\n+.br\n \\fBovsdb\\-client \\fR[\\fIoptions\\fR] \\fBmonitor\\fI \\fR[\\fIserver\\fR] \\fR[\\fIdatabase\\fR] \\fItable\\fR\n [\\fIcolumn\\fR[\\fB,\\fIcolumn\\fR]...]...\n .br\n@@ -44,7 +47,6 @@ ovsdb\\-client \\- command-line interface to \\fBovsdb-server\\fR(1)\n \\fBovsdb\\-client \\fR[\\fIoptions\\fR] \\fBmonitor\\-cond\\fI \\fR[\\fIserver\\fR] \\fR[\\fIdatabase\\fR] \\fIconditions\n \\fItable\\fR [\\fIcolumn\\fR[\\fB,\\fIcolumn\\fR]...]...\n .IP \"Testing Commands:\"\n-.br\n \\fBovsdb\\-client \\fR[\\fIoptions\\fR] \\fBlock\\fI \\fR[\\fIserver\\fR] \\fIlock\\fR\n .br\n \\fBovsdb\\-client \\fR[\\fIoptions\\fR] \\fBsteal\\fI \\fR[\\fIserver\\fR] \\fIlock\\fR\n@@ -203,6 +205,30 @@ database is in use.\n The output does not include ephemeral columns, which by design do not\n survive across restarts of \\fBovsdb\\-server\\fR.\n .\n+.IP \"[\\fB\\-\\-force\\fR] \\fBrestore\\fI \\fR[\\fIserver\\fR] \\fR[\\fIdatabase\\fR] < \\fIsnapshot\\fR\"\n+Reads \\fIsnapshot\\fR, which must be in the format used for OVSDB\n+standalone and active-backup databases. Then, connects to\n+\\fIserver\\fR, verifies that \\fIdatabase\\fR and \\fIsnapshot\\fR have the\n+same schema, then deletes all of the data in \\fIdatabase\\fR and\n+replaces it by \\fIsnapshot\\fR. The replacement happens atomically, in a\n+single transaction.\n+.IP\n+UUIDs for rows in the restored database will differ from those in\n+\\fIsnapshot\\fR, because the OVSDB protocol does not allow clients to\n+specify row UUIDs. Another way to restore a database,\n+which does also restore row UUIDs, is to stop\n+the server or servers, replace the database file by the snapshot, then\n+restart the database. Either way, ephemeral columns are not restored,\n+since by design they do not survive across restarts of\n+\\fBovsdb\\-server\\fR.\n+.IP\n+Normally \\fBrestore\\fR exits with a failure if \\fBsnapshot\\fR and the\n+server's database have different schemas. In such a case, it is a\n+good idea to convert the database to the new schema before restoring,\n+e.g. with \\fBovsdb\\-client convert\\fR. Use \\fB\\-\\-force\\fR to proceed\n+regardless of schema differences even though the restore might fail\n+with an error or succeed with surprising results.\n+.\n .IP \"\\fBmonitor\\fI \\fR[\\fIserver\\fR] \\fR[\\fIdatabase\\fR] \\fItable\\fR [\\fIcolumn\\fR[\\fB,\\fIcolumn\\fR]...]...\"\n .IQ \"\\fBmonitor\\-cond\\fI \\fR[\\fIserver\\fR] \\fR[\\fIdatabase\\fR] \\fIconditions\\fR \\fItable\\fR [\\fIcolumn\\fR[\\fB,\\fIcolumn\\fR]...]...\"\n Connects to \\fIserver\\fR and monitors the contents of rows that match conditions in\ndiff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c\nindex bfffc08effb0..056aa25c8983 100644\n--- a/ovsdb/ovsdb-client.c\n+++ b/ovsdb/ovsdb-client.c\n@@ -41,6 +41,7 @@\n #include \"ovsdb-data.h\"\n #include \"ovsdb-error.h\"\n #include \"poll-loop.h\"\n+#include \"row.h\"\n #include \"sort.h\"\n #include \"svec.h\"\n #include \"stream.h\"\n@@ -85,6 +86,9 @@ static bool timestamp;\n * actually works.) */\n static int db_change_aware = -1;\n \n+/* --force: Ignore schema differences for \"restore\" command? */\n+static bool force;\n+\n /* Format for table output. */\n static struct table_style table_style = TABLE_STYLE_DEFAULT;\n \n@@ -196,6 +200,7 @@ parse_options(int argc, char *argv[])\n enum {\n OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,\n OPT_TIMESTAMP,\n+ OPT_FORCE,\n VLOG_OPTION_ENUMS,\n DAEMON_OPTION_ENUMS,\n TABLE_OPTION_ENUMS,\n@@ -207,6 +212,7 @@ parse_options(int argc, char *argv[])\n {\"timestamp\", no_argument, NULL, OPT_TIMESTAMP},\n {\"db-change-aware\", no_argument, &db_change_aware, 1},\n {\"no-db-change-aware\", no_argument, &db_change_aware, 0},\n+ {\"force\", no_argument, NULL, OPT_FORCE},\n VLOG_LONG_OPTIONS,\n DAEMON_LONG_OPTIONS,\n #ifdef HAVE_OPENSSL\n@@ -249,6 +255,10 @@ parse_options(int argc, char *argv[])\n timestamp = true;\n break;\n \n+ case OPT_FORCE:\n+ force = true;\n+ break;\n+\n case '?':\n exit(EXIT_FAILURE);\n \n@@ -304,6 +314,8 @@ usage(void)\n \" dump contents of DATABASE on SERVER to stdout\\n\"\n \"\\n backup [SERVER] [DATABASE] > DB\\n\"\n \" dump database contents in the form of a database file\\n\"\n+ \"\\n [--force] restore [SERVER] [DATABASE] < DB\\n\"\n+ \" restore database contents from a database file\\n\"\n \"\\n lock [SERVER] LOCK\\n\"\n \" create or wait for LOCK in SERVER\\n\"\n \"\\n steal [SERVER] LOCK\\n\"\n@@ -1607,6 +1619,101 @@ do_backup(struct jsonrpc *rpc, const char *database,\n }\n \n static void\n+do_restore(struct jsonrpc *rpc, const char *database,\n+ int argc OVS_UNUSED, char *argv[] OVS_UNUSED)\n+{\n+ if (isatty(STDIN_FILENO)) {\n+ ovs_fatal(0, \"not reading backup from a terminal; \"\n+ \"please redirect stdin from a file\");\n+ }\n+\n+ struct ovsdb *backup;\n+ check_ovsdb_error(ovsdb_file_open(\"/dev/stdin\", true, &backup, NULL));\n+\n+ const struct ovsdb_schema *schema = backup->schema;\n+ struct ovsdb_schema *schema2 = fetch_schema(rpc, database);\n+ if (!ovsdb_schema_equal(schema, schema2)) {\n+ struct ds s = DS_EMPTY_INITIALIZER;\n+ if (strcmp(schema->version, schema2->version)) {\n+ ds_put_format(&s, \"backup schema has version \\\"%s\\\" but \"\n+ \"database schema has version \\\"%s\\\"\",\n+ schema->version, schema2->version);\n+ } else {\n+ ds_put_format(&s, \"backup schema and database schema are \"\n+ \"both version %s but still differ\",\n+ schema->version);\n+ }\n+ if (!force) {\n+ ovs_fatal(0, \"%s (use --force to override differences, or \"\n+ \"\\\"ovsdb-client convert\\\" to change the schema)\",\n+ ds_cstr(&s));\n+ }\n+ VLOG_INFO(\"%s\", ds_cstr(&s));\n+ ds_destroy(&s);\n+ }\n+\n+ struct json *txn = json_array_create_empty();\n+ json_array_add(txn, json_string_create(schema->name));\n+ struct shash_node *node;\n+ SHASH_FOR_EACH (node, &backup->tables) {\n+ const char *table_name = node->name;\n+ struct ovsdb_table *table = node->data;\n+\n+ struct json *del_op = json_object_create();\n+ json_object_put_string(del_op, \"op\", \"delete\");\n+ json_object_put_string(del_op, \"table\", table_name);\n+ json_object_put(del_op, \"where\", json_array_create_empty());\n+ json_array_add(txn, del_op);\n+\n+ const struct ovsdb_row *row;\n+ HMAP_FOR_EACH (row, hmap_node, &table->rows) {\n+ struct json *ins_op = json_object_create();\n+ json_object_put_string(ins_op, \"op\", \"insert\");\n+ json_object_put_string(ins_op, \"table\", table_name);\n+ json_object_put(ins_op, \"uuid-name\",\n+ json_string_create_nocopy(\n+ ovsdb_data_row_name(ovsdb_row_get_uuid(row))));\n+ struct json *row_json = json_object_create();\n+ json_object_put(ins_op, \"row\", row_json);\n+\n+ struct shash_node *node2;\n+ SHASH_FOR_EACH (node2, &table->schema->columns) {\n+ const struct ovsdb_column *column = node2->data;\n+ const struct ovsdb_datum *datum = &row->fields[column->index];\n+ const struct ovsdb_type *type = &column->type;\n+ if (column->persistent\n+ && column->index >= OVSDB_N_STD_COLUMNS\n+ && !ovsdb_datum_is_default(datum, type)) {\n+ struct json *value = ovsdb_datum_to_json_with_row_names(\n+ datum, type);\n+ json_object_put(row_json, column->name, value);\n+ }\n+ }\n+ json_array_add(txn, ins_op);\n+ }\n+ }\n+ struct jsonrpc_msg *rq = jsonrpc_create_request(\"transact\", txn, NULL);\n+ struct jsonrpc_msg *reply;\n+ check_txn(jsonrpc_transact_block(rpc, rq, &reply), &reply);\n+ if (reply->result->type != JSON_ARRAY) {\n+ ovs_fatal(0, \"result is not array\");\n+ }\n+ for (size_t i = 0; i < json_array(reply->result)->n; i++) {\n+ struct json *json = json_array(reply->result)->elems[i];\n+ if (json->type != JSON_OBJECT) {\n+ ovs_fatal(0, \"result array element is not object\");\n+ }\n+ struct shash *object = json_object(json);\n+ if (shash_find(object, \"error\")) {\n+ ovs_fatal(0, \"server returned error reply: %s\",\n+ json_to_string(json, JSSF_SORT));\n+ }\n+ }\n+ jsonrpc_msg_destroy(reply);\n+}\n+\n+\n+static void\n do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,\n int argc OVS_UNUSED, char *argv[] OVS_UNUSED)\n {\n@@ -1821,6 +1928,7 @@ static const struct ovsdb_client_command all_commands[] = {\n { \"needs-conversion\", NEED_RPC, 1, 1, do_needs_conversion },\n { \"dump\", NEED_DATABASE, 0, INT_MAX, do_dump },\n { \"backup\", NEED_DATABASE, 0, 0, do_backup },\n+ { \"restore\", NEED_DATABASE, 0, 0, do_restore },\n { \"lock\", NEED_RPC, 1, 1, do_lock_create },\n { \"steal\", NEED_RPC, 1, 1, do_lock_steal },\n { \"unlock\", NEED_RPC, 1, 1, do_lock_unlock },\ndiff --git a/ovsdb/ovsdb.7.xml b/ovsdb/ovsdb.7.xml\nindex 5461f252a03a..8169120c88f2 100644\n--- a/ovsdb/ovsdb.7.xml\n+++ b/ovsdb/ovsdb.7.xml\n@@ -410,9 +410,16 @@\n </p>\n \n <p>\n- To restore from a backup, stop the database server or servers, overwrite\n- the database file with the backup (e.g. with <code>cp</code>), and then\n- restart the servers.\n+ Multiple options are also available when the time comes to restore a\n+ database from a backup. One option is to stop the database server or\n+ servers, overwrite the database file with the backup (e.g. with\n+ <code>cp</code>), and then restart the servers. Another way is to use\n+ <code>ovsdb-client restore</code>, which connects to a running database\n+ server and replaces the data in one of its databases by a provided\n+ snapshot. Using <code>ovsdb-client restore</code> has the disadvantage\n+ that UUIDs of rows in the restored database will differ from those in the\n+ snapshot, because the OVSDB protocol does not allow clients to specify row\n+ UUIDs.\n </p>\n \n <p>\n", "prefixes": [ "ovs-dev", "RFC", "49/52" ] }