[ovs-dev] [PATCH 3/3 v2] ovsdb-server: Add and remove databases during run time.

Gurucharan Shetty shettyg at nicira.com
Tue Jun 25 08:18:36 UTC 2013


The commit allows a user to add a database file to a
ovsdb-server during run time. One can also remove a
database file from ovsdb-server's control.

Feature #14595.
Signed-off-by: Gurucharan Shetty <gshetty at nicira.com>
---
 ovsdb/jsonrpc-server.c  |    9 ++
 ovsdb/jsonrpc-server.h  |    2 +
 ovsdb/ovsdb-server.1.in |   24 ++++
 ovsdb/ovsdb-server.c    |  296 ++++++++++++++++++++++++++++++++++++++---------
 ovsdb/server.c          |   13 +++
 ovsdb/server.h          |    1 +
 tests/ovsdb-server.at   |  118 +++++++++++++++++++
 7 files changed, 407 insertions(+), 56 deletions(-)

diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
index 9f99d64..016dd33 100644
--- a/ovsdb/jsonrpc-server.c
+++ b/ovsdb/jsonrpc-server.c
@@ -132,6 +132,15 @@ ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *svr, struct ovsdb *db)
     return ovsdb_server_add_db(&svr->up, db);
 }
 
+/* Removes 'db' from the set of databases served out by 'svr'.  Returns
+ * true if successful, false if there is no database associated with 'db'. */
+bool
+ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *svr,
+                                struct ovsdb *db)
+{
+    return ovsdb_server_remove_db(&svr->up, db);
+}
+
 void
 ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *svr)
 {
diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h
index f2395fc..e6a1642 100644
--- a/ovsdb/jsonrpc-server.h
+++ b/ovsdb/jsonrpc-server.h
@@ -26,6 +26,8 @@ struct simap;
 struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(void);
 bool ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *,
                                  struct ovsdb *);
+bool ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *,
+                                     struct ovsdb *);
 void ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *);
 
 /* Options for a remote. */
diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in
index ceefef5..4339620 100644
--- a/ovsdb/ovsdb-server.1.in
+++ b/ovsdb/ovsdb-server.1.in
@@ -150,6 +150,30 @@ not list remotes added indirectly because they were read from the
 database by configuring a
 \fBdb:\fIdb\fB,\fItable\fB,\fIcolumn\fR remote.
 .
+.IP "\fBovsdb\-server/add\-db \fIdatabase\fR"
+Adds the \fIdatabase\fR to the running \fBovsdb\-server\fR.  The database
+file must already have been created and initialized using, for example,
+\fBovsdb\-tool create\fR.
+.
+.IP "\fBovsdb\-server/remove\-db \fIdatabase\fR"
+Removes \fIdatabase\fR from the running \fBovsdb\-server\fR.  \fIdatabase\fR
+must be a database name as listed by \fBovsdb-server/list\-dbs\fR.
+.IP
+If a remote has been configured that points to the specified
+\fIdatabase\fR (e.g. \fB\-\-remote=db:\fIdatabase\fB,\fR... on the
+command line), then it is automatically removed.
+.IP
+Any public key infrastructure options specified through this database
+(e.g. \fB\-\-private\-key=db:\fIdatabase,\fR... on the command line)
+are no longer checked for new changes, but any files previously
+configured are still used. (Adding \fIdatabase\fR back will cause the
+public key infrastructure options specified through it to update
+again.)
+.
+.IP "\fBovsdb\-server/list\-dbs"
+Outputs a list of the currently configured databases added either through
+the command line or through the \fBovsdb\-server/add\-db\fR command.
+.
 .so lib/vlog-unixctl.man
 .so lib/memory-unixctl.man
 .so lib/coverage-unixctl.man
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index 72c13c6..cd6961a 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -78,20 +78,21 @@ static unixctl_cb_func ovsdb_server_exit;
 static unixctl_cb_func ovsdb_server_compact;
 static unixctl_cb_func ovsdb_server_reconnect;
 
-struct add_remote_aux {
+struct load_config_aux {
     struct sset *remotes;
+    struct sset *dbnames;
     struct shash *all_dbs;
     FILE *config_tmpfile;
+    struct ovsdb_jsonrpc_server *jsonrpc;
 };
 static unixctl_cb_func ovsdb_server_add_remote;
-
-struct remove_remote_aux {
-    struct sset *remotes;
-    FILE *config_tmpfile;
-};
 static unixctl_cb_func ovsdb_server_remove_remote;
 static unixctl_cb_func ovsdb_server_list_remotes;
 
+static unixctl_cb_func ovsdb_server_add_database;
+static unixctl_cb_func ovsdb_server_remove_database;
+static unixctl_cb_func ovsdb_server_list_databases;
+
 static void open_db(struct ovsdb_jsonrpc_server *jsonrpc,
                     struct db *db, struct shash *all_dbs);
 
@@ -108,8 +109,8 @@ static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
                                  const struct sset *remotes,
                                  struct shash *all_dbs);
 
-static void save_config(FILE *config_file, const struct sset *);
-static void load_config(FILE *config_file, struct sset *);
+static void save_config(FILE *config_file, const struct load_config_aux *);
+static void load_config(FILE *config_file, struct load_config_aux *);
 
 int
 main(int argc, char *argv[])
@@ -118,15 +119,14 @@ main(int argc, char *argv[])
     char *run_command = NULL;
     struct unixctl_server *unixctl;
     struct ovsdb_jsonrpc_server *jsonrpc;
-    struct sset remotes;
+    struct sset remotes, dbnames;
+    const char *dbname;
     struct process *run_process;
     bool exiting;
     int retval;
     long long int status_timer = LLONG_MIN;
-    struct add_remote_aux add_remote_aux;
-    struct remove_remote_aux remove_remote_aux;
     FILE *config_tmpfile;
-
+    struct load_config_aux load_config_aux;
     struct db *db;
     struct shash all_dbs;
     struct shash_node *node;
@@ -149,25 +149,36 @@ main(int argc, char *argv[])
     if (!config_tmpfile) {
         ovs_fatal(errno, "failed to create temporary file");
     }
-    save_config(config_tmpfile, &remotes);
+
+    sset_init(&dbnames);
+    if (argc > 0) {
+        for (i = 0; i < argc; i++) {
+            sset_add(&dbnames, argv[i]);
+         }
+    } else {
+        char *default_db = xasprintf("%s/conf.db", ovs_dbdir());
+        sset_add(&dbnames, default_db);
+        free(default_db);
+    }
+
+    load_config_aux.remotes = &remotes;
+    load_config_aux.dbnames = &dbnames;
+    load_config_aux.config_tmpfile = config_tmpfile;
+
+    save_config(config_tmpfile, &load_config_aux);
 
     daemonize_start();
 
     /* Load the saved config. */
-    load_config(config_tmpfile, &remotes);
-
-    shash_init(&all_dbs);
+    load_config(config_tmpfile, &load_config_aux);
     jsonrpc = ovsdb_jsonrpc_server_create();
 
-    if (argc > 0) {
-        for (i = 0; i < argc; i++) {
-            db = xzalloc(sizeof *db);
-            db->filename = argv[i];
-            open_db(jsonrpc, db, &all_dbs);
-         }
-    } else {
+    shash_init(&all_dbs);
+    load_config_aux.all_dbs = &all_dbs;
+    load_config_aux.jsonrpc = jsonrpc;
+    SSET_FOR_EACH(dbname, &dbnames) {
         db = xzalloc(sizeof *db);
-        db->filename = xasprintf("%s/conf.db", ovs_dbdir());
+        db->filename = strdup(dbname);
         open_db(jsonrpc, db, &all_dbs);
     }
 
@@ -209,20 +220,20 @@ main(int argc, char *argv[])
     unixctl_command_register("ovsdb-server/reconnect", "", 0, 0,
                              ovsdb_server_reconnect, jsonrpc);
 
-    add_remote_aux.remotes = &remotes;
-    add_remote_aux.all_dbs = &all_dbs;
-    add_remote_aux.config_tmpfile = config_tmpfile;
     unixctl_command_register("ovsdb-server/add-remote", "REMOTE", 1, 1,
-                             ovsdb_server_add_remote, &add_remote_aux);
-
-    remove_remote_aux.remotes = &remotes;
-    remove_remote_aux.config_tmpfile = config_tmpfile;
+                             ovsdb_server_add_remote, &load_config_aux);
     unixctl_command_register("ovsdb-server/remove-remote", "REMOTE", 1, 1,
-                             ovsdb_server_remove_remote, &remove_remote_aux);
-
+                             ovsdb_server_remove_remote, &load_config_aux);
     unixctl_command_register("ovsdb-server/list-remotes", "", 0, 0,
                              ovsdb_server_list_remotes, &remotes);
 
+    unixctl_command_register("ovsdb-server/add-db", "DB", 1, 1,
+                             ovsdb_server_add_database, &load_config_aux);
+    unixctl_command_register("ovsdb-server/remove-db", "DB", 1, 1,
+                             ovsdb_server_remove_database, &load_config_aux);
+    unixctl_command_register("ovsdb-server/list-dbs", "", 0, 0,
+                             ovsdb_server_list_databases, &all_dbs);
+
     exiting = false;
     while (!exiting) {
         memory_run();
@@ -429,6 +440,28 @@ parse_db_string_column(const struct shash *all_dbs,
     return NULL;
 }
 
+static bool
+ssl_path_valid(const struct shash *all_dbs, const char *path)
+{
+    const struct ovsdb_column *column;
+    const struct ovsdb_table *table;
+    char *retval;
+    const struct db *db;
+
+    if (!path) {
+        return true;
+    }
+
+    retval = (strncmp("db:", path, 3)
+              ? NULL
+              : parse_db_column(all_dbs, path, &db, &table, &column));
+    if (retval) {
+        free(retval);
+        return false;
+    }
+    return true;
+}
+
 static OVS_UNUSED const char *
 query_db_string(const struct shash *all_dbs, const char *name)
 {
@@ -860,6 +893,8 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
 {
     struct shash resolved_remotes;
     const char *name;
+    static char *ssl_error_message;
+    static bool ssl_reconfigure;
 
     /* Configure remotes. */
     shash_init(&resolved_remotes);
@@ -873,11 +908,28 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
     ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes);
     shash_destroy_free_data(&resolved_remotes);
 
-    /* Configure SSL. */
+    /* During ovsd-server run, a database that is referenced by a SSL path
+     * may have been removed. If a SSL path is invalid, raise an error. */
+    if (ssl_reconfigure) {
+        if (!ssl_path_valid(all_dbs, private_key_file) || \
+            !ssl_path_valid(all_dbs, certificate_file) || \
+            !ssl_path_valid(all_dbs, ca_cert_file)) {
+            if (!ssl_error_message) {
+                ssl_error_message = xasprintf("SSL paths no longer valid.");
+                VLOG_ERR("%s", ssl_error_message);
+            }
+            return;
+        } else if (ssl_error_message) {
+            VLOG_INFO("SSL paths are valid again.");
+            free(ssl_error_message);
+            ssl_error_message = NULL;
+        }
+    }
     stream_ssl_set_key_and_cert(query_db_string(all_dbs, private_key_file),
                                 query_db_string(all_dbs, certificate_file));
     stream_ssl_set_ca_cert_file(query_db_string(all_dbs, ca_cert_file),
                                 bootstrap_ca_cert);
+    ssl_reconfigure = true;
 }
 
 static void
@@ -954,7 +1006,7 @@ static void
 ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
                         const char *argv[], void *aux_)
 {
-    struct add_remote_aux *aux = aux_;
+    struct load_config_aux *aux = aux_;
     const char *remote = argv[1];
 
     const struct ovsdb_column *column;
@@ -968,7 +1020,7 @@ ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
                                 &db, &table, &column));
     if (!retval) {
         if (sset_add(aux->remotes, remote)) {
-            save_config(aux->config_tmpfile, aux->remotes);
+            save_config(aux->config_tmpfile, aux);
         }
         unixctl_command_reply(conn, NULL);
     } else {
@@ -983,13 +1035,13 @@ static void
 ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
                            const char *argv[], void *aux_)
 {
-    struct remove_remote_aux *aux = aux_;
+    struct load_config_aux *aux = aux_;
     struct sset_node *node;
 
     node = sset_find(aux->remotes, argv[1]);
     if (node) {
         sset_delete(aux->remotes, node);
-        save_config(aux->config_tmpfile, aux->remotes);
+        save_config(aux->config_tmpfile, aux);
         unixctl_command_reply(conn, NULL);
     } else {
         unixctl_command_reply_error(conn, "no such remote");
@@ -1017,6 +1069,117 @@ ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED,
     ds_destroy(&s);
 }
 
+
+/* "ovsdb-server/add-db DB": adds the DB to ovsdb-server. */
+static void
+ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                          const char *argv[], void *aux_)
+{
+    struct load_config_aux *aux = aux_;
+    const char *filename = argv[1];
+    struct db *db;
+    struct ovsdb_error *error;
+
+    db = xzalloc(sizeof *db);
+    db->filename = strdup(filename);
+
+    error = ovsdb_file_open(db->filename, false,
+                            &db->db, &db->file);
+    if (error) {
+        VLOG_ERR("%s", ovsdb_error_to_string(error));
+        free(db->filename);
+        free(db);
+        free(error);
+        unixctl_command_reply_error(conn, "Failed to open the database file.");
+        return;
+    }
+
+    if (!ovsdb_jsonrpc_server_add_db(aux->jsonrpc, db->db)) {
+        VLOG_ERR("%s: duplicate database name", db->db->schema->name);
+        ovsdb_destroy(db->db);
+        free(db->filename);
+        free(db);
+        unixctl_command_reply_error(conn, "Failed to open the database file.");
+        return;
+    }
+
+    shash_add_once(aux->all_dbs, db->filename, db);
+    sset_add(aux->dbnames, filename);
+    save_config(aux->config_tmpfile, aux);
+
+    unixctl_command_reply(conn, NULL);
+}
+
+static void
+ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                             const char *argv[], void *aux_)
+{
+    struct load_config_aux *aux = aux_;
+    struct shash *all_dbs = aux->all_dbs;
+    struct sset *remotes = aux->remotes;
+    struct db *db;
+    const struct db *dbp;
+    struct shash_node *node;
+    const char *remote, *next;
+    const struct ovsdb_column *column;
+    const struct ovsdb_table *table;
+    char *retval;
+
+    node = shash_find(all_dbs, argv[1]);
+    if (node) {
+        if (!ovsdb_jsonrpc_server_remove_db(aux->jsonrpc,
+                                           ((struct db *)node->data)->db)) {
+            unixctl_command_reply_error(conn,
+                                        "Database not in jsonrpc server.");
+            return;
+        }
+
+        /* Remove any remotes associated with the database. */
+        SSET_FOR_EACH_SAFE(remote, next, remotes) {
+            if (!strncmp("db:", remote, 3)) {
+                retval =  parse_db_column(all_dbs, remote, &dbp, &table,
+                                          &column);
+                if (!retval && !strcmp(dbp->filename, argv[1])) {
+                    sset_find_and_delete(remotes, remote);
+                } else if (retval) {
+                    free(retval);
+                }
+            }
+        }
+
+        db = node->data;
+        ovsdb_destroy(db->db);
+        shash_delete(all_dbs, node);
+        free(db->filename);
+        free(db);
+    } else {
+        unixctl_command_reply_error(conn, "Failed to find the database.");
+        return;
+    }
+
+    sset_find_and_delete(aux->dbnames, argv[1]);
+    save_config(aux->config_tmpfile, aux);
+    unixctl_command_reply(conn, NULL);
+}
+
+static void
+ovsdb_server_list_databases(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                            const char *argv[] OVS_UNUSED, void *all_dbs_)
+{
+    struct shash *all_dbs = all_dbs_;
+    struct shash_node *node;
+    struct ds s;
+
+    ds_init(&s);
+
+    SHASH_FOR_EACH(node, all_dbs) {
+        ds_put_format(&s, "%s\n", node->name);
+    }
+
+    unixctl_command_reply(conn, ds_cstr(&s));
+    ds_destroy(&s);
+}
+
 static void
 parse_options(int *argcp, char **argvp[],
               struct sset *remotes, char **unixctl_pathp, char **run_command)
@@ -1142,24 +1305,33 @@ usage(void)
 }
 
 /* Truncates and replaces the contents of 'config_file' by a representation
- * of 'remotes'. */
+ * of 'aux->remotes' and 'aux->dbnames'. */
 static void
-save_config(FILE *config_file, const struct sset *remotes)
+save_config(FILE *config_file, const struct load_config_aux *aux)
 {
-    const char *remote;
-    struct json *json;
+    const char *remote, *dbname;
+    struct json *obj, *arr1, *arr2;
     char *s;
 
     if (ftruncate(fileno(config_file), 0) == -1) {
         VLOG_FATAL("failed to truncate temporary file (%s)", strerror(errno));
     }
 
-    json = json_array_create_empty();
-    SSET_FOR_EACH (remote, remotes) {
-        json_array_add(json, json_string_create(remote));
+    arr1 = json_array_create_empty();
+    SSET_FOR_EACH (remote, aux->remotes) {
+        json_array_add(arr1, json_string_create(remote));
     }
-    s = json_to_string(json, 0);
-    json_destroy(json);
+
+    arr2 = json_array_create_empty();
+    SSET_FOR_EACH (dbname, aux->dbnames) {
+        json_array_add(arr2, json_string_create(dbname));
+    }
+
+    obj = json_object_create();
+    json_object_put(obj, "remotes", arr1);
+    json_object_put(obj, "dbnames", arr2);
+    s = json_to_string(obj, 0);
+    json_destroy(obj);
 
     if (fseek(config_file, 0, SEEK_SET) != 0
         || fputs(s, config_file) == EOF
@@ -1169,15 +1341,18 @@ save_config(FILE *config_file, const struct sset *remotes)
     free(s);
 }
 
-/* Clears and replaces 'remotes' by a configuration read from 'config_file',
- * which must have been previously written by save_config(). */
+/* Clears and replaces 'aux->remotes' and 'aux->dbnames' by a configuration
+ * read from 'config_file', which must have been previously written by
+ * save_config(). */
 static void
-load_config(FILE *config_file, struct sset *remotes)
+load_config(FILE *config_file, struct load_config_aux *aux)
 {
-    struct json *json;
+    struct json *json, *json_arr;
     size_t i;
+    struct shash_node *node;
 
-    sset_clear(remotes);
+    sset_clear(aux->remotes);
+    sset_clear(aux->dbnames);
 
     if (fseek(config_file, 0, SEEK_SET) != 0) {
         VLOG_FATAL("seek failed in temporary file (%s)", strerror(errno));
@@ -1186,10 +1361,19 @@ load_config(FILE *config_file, struct sset *remotes)
     if (json->type == JSON_STRING) {
         VLOG_FATAL("reading json failed (%s)", json_string(json));
     }
-    ovs_assert(json->type == JSON_ARRAY);
-    for (i = 0; i < json->u.array.n; i++) {
-        const struct json *remote = json->u.array.elems[i];
-        sset_add(remotes, json_string(remote));
+    ovs_assert(json->type == JSON_OBJECT);
+
+    SHASH_FOR_EACH (node, json_object(json)) {
+        json_arr = node->data;
+        ovs_assert(json_arr->type == JSON_ARRAY);
+        for (i = 0; i < json_arr->u.array.n; i++) {
+            const struct json *elem = json_arr->u.array.elems[i];
+            if (!strcmp(node->name, "remotes")) {
+                sset_add(aux->remotes, json_string(elem));
+            } else if (!strcmp(node->name, "dbnames")) {
+                sset_add(aux->dbnames, json_string(elem));
+            }
+        }
     }
     json_destroy(json);
 }
diff --git a/ovsdb/server.c b/ovsdb/server.c
index bf4ef3c..82f55cb 100644
--- a/ovsdb/server.c
+++ b/ovsdb/server.c
@@ -132,6 +132,19 @@ ovsdb_server_add_db(struct ovsdb_server *server, struct ovsdb *db)
     return shash_add_once(&server->dbs, db->schema->name, db);
 }
 
+/* Removes 'db' from the set of databases served out by 'server'.  Returns
+ * true if successful, false if there is no db associated with
+ * db->schema->name. */
+bool
+ovsdb_server_remove_db(struct ovsdb_server *server, struct ovsdb *db)
+{
+    void *data = shash_find_and_delete(&server->dbs, db->schema->name);
+    if (data) {
+        return true;
+    }
+    return false;
+}
+
 /* Destroys 'server'. */
 void
 ovsdb_server_destroy(struct ovsdb_server *server)
diff --git a/ovsdb/server.h b/ovsdb/server.h
index 561f01e..047cbb7 100644
--- a/ovsdb/server.h
+++ b/ovsdb/server.h
@@ -83,6 +83,7 @@ struct ovsdb_server {
 
 void ovsdb_server_init(struct ovsdb_server *);
 bool ovsdb_server_add_db(struct ovsdb_server *, struct ovsdb *);
+bool ovsdb_server_remove_db(struct ovsdb_server *, struct ovsdb *);
 void ovsdb_server_destroy(struct ovsdb_server *);
 
 struct ovsdb_lock_waiter *ovsdb_server_lock(struct ovsdb_server *,
diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
index 2368cbc..d775aa7 100644
--- a/tests/ovsdb-server.at
+++ b/tests/ovsdb-server.at
@@ -164,6 +164,124 @@ AT_CHECK(
 OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP
 
+AT_SETUP([ovsdb-server/add-db and remove-db])
+AT_KEYWORDS([ovsdb server positive])
+ON_EXIT([kill `cat ovsdb-server.pid`])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+ordinal_schema > schema1
+constraint_schema > schema2
+AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
+
+# Start ovsdb-server with just a single database - db1.
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db1], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [db1
+])
+
+# Add the second database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [db1
+db2
+])
+
+# The databases are responsive.
+AT_CHECK([ovsdb-client list-tables unix:socket constraints], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-client list-tables unix:socket ordinals], [0], [ignore], [ignore])
+
+# Add an already added database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [2],
+  [], [Failed to open the database file.
+ovs-appctl: ovsdb-server: server returned an error
+])
+
+# Add a non-existing database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db3], [2],
+  [], [Failed to open the database file.
+ovs-appctl: ovsdb-server: server returned an error
+])
+
+# Add a remote through a db path in db1.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote db:ordinals,ordinals,name], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [db:ordinals,ordinals,name
+punix:socket
+])
+
+# Removing db1 should also remove the remote.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db db1], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [db2
+])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes],
+  [0], [punix:socket
+])
+AT_CHECK([ovsdb-client list-tables unix:socket ordinals], [1], [ignore], [ignore])
+
+# Remove db2.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db db2], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [])
+AT_CHECK([ovsdb-client list-tables unix:socket constraints], [1], [ignore], [ignore])
+
+# Remove a non-existant database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db db1], [2],
+  [], [Failed to find the database.
+ovs-appctl: ovsdb-server: server returned an error
+])
+AT_CLEANUP
+
+AT_SETUP([ovsdb-server/add-db and remove-db with --monitor])
+AT_KEYWORDS([ovsdb server positive])
+# Start ovsdb-server, initially with one db.
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+ordinal_schema > schema
+AT_CHECK([ovsdb-tool create db1 schema], [0], [ignore], [ignore])
+ON_EXIT([kill `cat *.pid`])
+AT_CHECK([ovsdb-server -v -vvlog:off --monitor --detach --no-chdir --pidfile --log-file db1])
+
+# Add the second database.
+constraint_schema > schema2
+AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [db1
+db2
+])
+
+# Kill the daemon process, making it look like a segfault,
+# and wait for a new daemon process to get spawned.
+cp ovsdb-server.pid old.pid
+AT_CHECK([kill -SEGV `cat ovsdb-server.pid`])
+OVS_WAIT_WHILE([kill -0 `cat old.pid`])
+OVS_WAIT_UNTIL(
+  [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [db1
+db2
+])
+
+# Remove the recently added database.
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db db2])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [db1
+])
+
+# Kill the daemon process, making it look like a segfault,
+# and wait for a new daemon process to get spawned.
+cp ovsdb-server.pid old.pid
+AT_CHECK([kill -SEGV `cat ovsdb-server.pid`])
+OVS_WAIT_WHILE([kill -0 `cat old.pid`])
+OVS_WAIT_UNTIL(
+  [test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != `cat old.pid`])
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs],
+  [0], [db1
+])
+AT_CLEANUP
+
 AT_SETUP([--remote=db: implementation])
 AT_KEYWORDS([ovsdb server positive])
 OVS_RUNDIR=`pwd`; export OVS_RUNDIR
-- 
1.7.9.5




More information about the dev mailing list