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 <gshe...@nicira.com> --- ovsdb/jsonrpc-server.c | 10 ++ ovsdb/jsonrpc-server.h | 2 + ovsdb/ovsdb-server.1.in | 18 +++ ovsdb/ovsdb-server.c | 348 +++++++++++++++++++++++++++++++++++++++-------- ovsdb/ovsdb.c | 3 + ovsdb/server.c | 9 ++ ovsdb/server.h | 1 + tests/ovsdb-server.at | 136 ++++++++++++++++++ 8 files changed, 470 insertions(+), 57 deletions(-) diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 9f99d64..0745ae6 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -132,6 +132,16 @@ 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 + * 'db' if successful, NULL if there is no database associated with 'db'. */ +void * +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..707aa18 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 *); +void *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 82dd9c6..2e62ec9 100644 --- a/ovsdb/ovsdb-server.1.in +++ b/ovsdb/ovsdb-server.1.in @@ -152,6 +152,24 @@ not list remotes added indirectly because they were read from the database by configuring a \fBdb:\fR[\fIdb\fB,\fR]\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 the specified \fIdatabase\fR from the running \fBovsdb\-server\fR. +If a \fIremote\fR has been configured such that it points to the specified +\fIdatabase\fR, then it is automatically removed. Any public key +infrastructure options specified through this database is no longer checked +for new changes, but the linked files are still used. (Adding the +\fIdatabase\fR back will recheck for the public key infrastructure options +specified through it.) +. +.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 ea8fe0f..a9c910b 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -73,26 +73,28 @@ static char *private_key_file; static char *certificate_file; static char *ca_cert_file; static bool bootstrap_ca_cert; +static bool ssl_reconfigure = true; 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 void open_db(const struct ovsdb_jsonrpc_server *jsonrpc, +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); static void parse_options(int *argc, char **argvp[], @@ -108,8 +110,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 +120,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 +150,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 +221,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(); @@ -300,7 +312,7 @@ main(int argc, char *argv[]) } static void -open_db(const struct ovsdb_jsonrpc_server *jsonrpc, struct db *db, +open_db(struct ovsdb_jsonrpc_server *jsonrpc, struct db *db, struct shash *all_dbs) { struct ovsdb_error *error; @@ -887,6 +899,9 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc, shash_destroy_free_data(&resolved_remotes); /* Configure SSL. */ + if (!ssl_reconfigure) { + return; + } 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), @@ -967,7 +982,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; @@ -981,7 +996,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 { @@ -996,13 +1011,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"); @@ -1030,6 +1045,204 @@ ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED, ds_destroy(&s); } +static bool +ssl_path_valid(struct shash *all_dbs, const char *config) +{ + const struct ovsdb_column *column; + const struct ovsdb_table *table; + char *retval; + const struct db *db; + + if (!config) { + return false; + } + + retval = (strncmp("db:", config, 3) + ? NULL + : parse_db_column(all_dbs, config, + &db, &table, &column)); + if (retval) { + free(retval); + return false; + } + return true; +} + +/* "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; + char *err; + + if (shash_count(aux->all_dbs)) { + /* If there are any DB paths specified without a schema, + * we cannot add a new database. */ + struct sset db_paths; + const char *db_path; + const char *remote; + + sset_init(&db_paths); + + SSET_FOR_EACH(remote, aux->remotes) { + sset_add(&db_paths, remote); + } + if (private_key_file) { + sset_add(&db_paths, private_key_file); + } + if (certificate_file) { + sset_add(&db_paths, certificate_file); + } + if (ca_cert_file) { + sset_add(&db_paths, ca_cert_file); + } + + SSET_FOR_EACH(db_path, &db_paths) { + if (!strncmp(db_path, "db:", 3)) { + const char *tokens[3]; + char *save_ptr = NULL; + char *db_path_ = strdup(db_path); + strtok_r(db_path_, ":", &save_ptr); /* "db:" */ + tokens[0] = strtok_r(NULL, ",", &save_ptr); + tokens[1] = strtok_r(NULL, ",", &save_ptr); + tokens[2] = strtok_r(NULL, ",", &save_ptr); + if (!tokens[0] || !tokens[1] || !tokens[2]) { + err = xasprintf("Failed to add the database as" + " there exists a %s with invalid" + " db path.", db_path); + unixctl_command_reply_error(conn, err); + free(err); + sset_destroy(&db_paths); + free(db_path_); + return; + } + free(db_path_); + } + } + sset_destroy(&db_paths); + } + + 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); + + /* Unflag SSL paths if it becomes valid with this db. */ + if (!ssl_reconfigure && ssl_path_valid(aux->all_dbs, private_key_file) && \ + ssl_path_valid(aux->all_dbs, certificate_file) && \ + ssl_path_valid(aux->all_dbs, ca_cert_file)) { + ssl_reconfigure = true; + } + + 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); + + /* Flag any SSL paths provided by this database. */ + 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)) { + ssl_reconfigure = false; + VLOG_ERR("SSL paths no longer valid."); + } + } + } 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) @@ -1155,24 +1368,33 @@ usage(void) } /* Truncates and replaces the contents of 'config_file' by a representation - * of 'remotes'. */ + * of 'aux->remotes' and 'aux->all_dbs'. */ 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 @@ -1182,15 +1404,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)); @@ -1199,10 +1424,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/ovsdb.c b/ovsdb/ovsdb.c index 6b53f4a..35e3153 100644 --- a/ovsdb/ovsdb.c +++ b/ovsdb/ovsdb.c @@ -25,6 +25,9 @@ #include "simap.h" #include "table.h" #include "transaction.h" +#include "vlog.h" + +VLOG_DEFINE_THIS_MODULE(ovsdb); struct ovsdb_schema * ovsdb_schema_create(const char *name, const char *version, const char *cksum) diff --git a/ovsdb/server.c b/ovsdb/server.c index bf4ef3c..1a79d31 100644 --- a/ovsdb/server.c +++ b/ovsdb/server.c @@ -132,6 +132,15 @@ 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 + * 'db' if successful, NULL if there is no db associated with + * db->schema->name. */ +void * +ovsdb_server_remove_db(struct ovsdb_server *server, struct ovsdb *db) +{ + return shash_find_and_delete(&server->dbs, db->schema->name); +} + /* Destroys 'server'. */ void ovsdb_server_destroy(struct ovsdb_server *server) diff --git a/ovsdb/server.h b/ovsdb/server.h index 561f01e..48dcd17 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 *); +void *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 acb5a44..12e1100 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -164,6 +164,142 @@ 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 database is responsive. +AT_CHECK([ovsdb-client list-tables unix:socket constraints], [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 +]) + +# Add back db1. +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db1], [0]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs], + [0], [db1 +]) + +# Add a remote that has a db path in db1. But do not provide a schema. +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-remote db:ordinals,name], [0]) +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-remotes], + [0], [db:ordinals,name +punix:socket +]) + +# Add database db2. +AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [2], [ignore], +[Failed to add the database as there exists a db:ordinals,name with invalid db path. +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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev