2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

ovsdb-server: Add new RPC "set_db_change_aware".

The _Server database recently added to ovsdb-server can be used to dump out
information about databases, but monitoring updates to _Server is not yet
very useful because for historical reasons ovsdb-server drops all of its
OVSDB connections whenever databases are added or removed or otherwise
change in some major way.  It is not a good idea to change this behavior
for all clients, because some of them rely on it, but this commit
introduces a new RPC that allows clients that understand _Server to
suppress the connection-closing behavior.

Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Ben Pfaff 2017-12-06 11:37:03 -08:00
parent 6bb9b060d5
commit 10621d7953
7 changed files with 299 additions and 54 deletions

View File

@ -146,6 +146,19 @@ notifications (see below) to the request, it must be unique among all active
monitors. ``ovsdb-server`` rejects attempt to create two monitors with the
same identifier.
4.1.7 Monitor Cancellation
--------------------------
When a database monitored by a session is removed, and database change
awareness is enabled for the session (see Section 4.1.16), the database server
spontaneously cancels all monitors (including conditional monitors described in
Section 4.1.12) for the removed database. For each canceled monitor, it issues
a notification in the following form::
"method": "monitor_canceled"
"params": [<json-value>]
"id": null
4.1.12 Monitor_cond
-------------------
@ -371,6 +384,36 @@ The response object contains the following members::
running OVSDB server process. A fresh UUID is generated when the process
restarts.
4.1.16 Database Change Awareness
--------------------------------
RFC 7047 does not provide a way for a client to find out about some kinds of
configuration changes, such as about databases added or removed while a client
is connected to the server, or databases changing between read/write and
read-only due to a transition between active and backup roles. Traditionally,
``ovsdb-server`` disconnects all of its clients when this happens, because this
prompts a well-written client to reassess what is available from the server
when it reconnects.
OVS 2.9 provides a way for clients to keep track of these kinds of changes, by
monitoring the ``Database`` table in the ``_Server`` database introduced in
this release (see ``ovsdb-server(5)`` for details). By itself, this does not
suppress ``ovsdb-server`` disconnection behavior, because a client might
monitor this database without understanding its special semantics. Instead,
``ovsdb-server`` provides a special request::
"method": "set_db_change_aware"
"params": [<boolean>]
"id": <nonnull-json-value>
If the boolean in the request is true, it suppresses the connection-closing
behavior for the current connection, and false restores the default behavior.
The reply is always the same::
"result": {}
"error": null
"id": same "id" as request
5.1 Notation
------------

View File

@ -13,6 +13,40 @@
one row per database. As its database configuration and status changes,
the server automatically and immediately updates the table to match.
</p>
<p>
The OVSDB protocol specified in RFC 7047 does not provide a way for an
OVSDB client to find out about some kinds of configuration changes, such
as about databases added or removed while a client is connected to the
server, or databases changing between read/write and read-only due to a
transition between active and backup roles. This table provides a
solution: clients can monitor the table's contents to find out about
important changes.
</p>
<p>
Traditionally, <code>ovsdb-server</code> disconnects all of its clients
when a significant configuration change occurs, because this prompts a
well-written client to reassess what is available from the server when it
reconnects. Because this table provides an alternative and more
efficient way to find out about those changes, OVS 2.9 also introduces
the <code>set_db_change_aware</code> RPC, documented in
<code>ovsdb-server</code>(7), to allow clients to suppress this
disconnection behavior.
</p>
<p>
When a database is removed from the server, in addition to
<code>Database</code> table updates, the server sends <code>cancel</code>
messages, as described in RFC 7047 section 4.1.4, in reply to outstanding
transactions for the removed database. The server also cancels any
outstanding monitoring initiated by <code>monitor</code> or
<code>monitor_cond</code> requested on the removed database, sending the
<code>monitor_canceled</code> RPC described in
<code>ovsdb-server</code>(7). Only clients that disable disconnection
with <code>set_db_change_aware</code> receive these messages.
</p>
<p>
Clients can use the <code>_uuid</code> column in this table as a
generation number. The server generates a fresh <code>_uuid</code> every

View File

@ -57,12 +57,15 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
/* Sessions. */
static struct ovsdb_jsonrpc_session *ovsdb_jsonrpc_session_create(
struct ovsdb_jsonrpc_remote *, struct jsonrpc_session *, bool);
static void ovsdb_jsonrpc_session_preremove_db(struct ovsdb_jsonrpc_remote *,
struct ovsdb *);
static void ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *);
static void ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_remote *);
static void ovsdb_jsonrpc_session_get_memory_usage_all(
const struct ovsdb_jsonrpc_remote *, struct simap *usage);
static void ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *);
static void ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *);
static void ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *,
bool force);
static void ovsdb_jsonrpc_session_set_all_options(
struct ovsdb_jsonrpc_remote *, const struct ovsdb_jsonrpc_options *);
static bool ovsdb_jsonrpc_active_session_get_status(
@ -83,6 +86,8 @@ static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *,
static struct ovsdb_jsonrpc_trigger *ovsdb_jsonrpc_trigger_find(
struct ovsdb_jsonrpc_session *, const struct json *id, size_t hash);
static void ovsdb_jsonrpc_trigger_complete(struct ovsdb_jsonrpc_trigger *);
static void ovsdb_jsonrpc_trigger_preremove_db(struct ovsdb_jsonrpc_session *,
struct ovsdb *);
static void ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *);
static void ovsdb_jsonrpc_trigger_complete_done(
struct ovsdb_jsonrpc_session *);
@ -99,6 +104,8 @@ static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel(
struct ovsdb_jsonrpc_session *,
struct json_array *params,
const struct json *request_id);
static void ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *,
struct ovsdb *);
static void ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *);
static void ovsdb_jsonrpc_monitor_flush_all(struct ovsdb_jsonrpc_session *);
static bool ovsdb_jsonrpc_monitor_needs_flush(struct ovsdb_jsonrpc_session *);
@ -157,34 +164,25 @@ ovsdb_jsonrpc_server_create(bool read_only)
bool
ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *svr, struct ovsdb *db)
{
/* The OVSDB protocol doesn't have a way to notify a client that a
* database has been added. If some client tried to use the database
* that we're adding and failed, then forcing it to reconnect seems like
* a reasonable way to make it try again.
*
* If this is too big of a hammer in practice, we could be more selective,
* e.g. disconnect only connections that actually tried to use a database
* with 'db''s name. */
ovsdb_jsonrpc_server_reconnect(svr);
ovsdb_jsonrpc_server_reconnect(svr, false);
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
/* Removes 'db' from the set of databases served out by 'svr'. */
void
ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *svr,
struct ovsdb *db)
{
/* There might be pointers to 'db' from 'svr', such as monitors or
* outstanding transactions. Disconnect all JSON-RPC connections to avoid
* accesses to freed memory.
*
* If this is too big of a hammer in practice, we could be more selective,
* e.g. disconnect only connections that actually reference 'db'. */
ovsdb_jsonrpc_server_reconnect(svr);
struct shash_node *node;
SHASH_FOR_EACH (node, &svr->remotes) {
struct ovsdb_jsonrpc_remote *remote = node->data;
return ovsdb_server_remove_db(&svr->up, db);
ovsdb_jsonrpc_session_preremove_db(remote, db);
}
ovsdb_jsonrpc_server_reconnect(svr, false);
ovsdb_server_remove_db(&svr->up, db);
}
void
@ -333,17 +331,20 @@ ovsdb_jsonrpc_server_free_remote_status(
free(status->locks_lost);
}
/* Forces all of the JSON-RPC sessions managed by 'svr' to disconnect and
* reconnect. */
/* Makes all of the JSON-RPC sessions managed by 'svr' disconnect. (They will
* then generally reconnect.).
*
* If 'force' is true, disconnects all sessions. Otherwise, disconnects only
* sesions that aren't database change aware. */
void
ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *svr)
ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *svr, bool force)
{
struct shash_node *node;
SHASH_FOR_EACH (node, &svr->remotes) {
struct ovsdb_jsonrpc_remote *remote = node->data;
ovsdb_jsonrpc_session_reconnect_all(remote);
ovsdb_jsonrpc_session_reconnect_all(remote, force);
}
}
@ -353,7 +354,7 @@ ovsdb_jsonrpc_server_set_read_only(struct ovsdb_jsonrpc_server *svr,
{
if (svr->read_only != read_only) {
svr->read_only = read_only;
ovsdb_jsonrpc_server_reconnect(svr);
ovsdb_jsonrpc_server_reconnect(svr, false);
}
}
@ -426,6 +427,20 @@ struct ovsdb_jsonrpc_session {
struct ovsdb_session up;
struct ovsdb_jsonrpc_remote *remote;
/* RFC 7047 does not contemplate how to alert clients to changes to the set
* of databases, e.g. databases that are added or removed while the
* database server is running. Traditionally, ovsdb-server disconnects all
* of its clients when this happens; a well-written client will reassess
* what is available from the server upon reconnection.
*
* OVS 2.9 introduces a way for clients to monitor changes to the databases
* being served, through the Database table in the _Server database that
* OVSDB adds in this version. ovsdb-server suppresses the connection
* close for clients that identify themselves as taking advantage of this
* mechanism. When this member is true, it indicates that the client
* requested such suppression. */
bool db_change_aware;
/* Triggers. */
struct hmap triggers; /* Hmap of "struct ovsdb_jsonrpc_trigger"s. */
@ -472,6 +487,20 @@ ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote *remote,
return s;
}
/* Database 'db' is about to be removed from the database server. To prepare,
* this function removes all references to 'db' from 'remote'. */
static void
ovsdb_jsonrpc_session_preremove_db(struct ovsdb_jsonrpc_remote *remote,
struct ovsdb *db)
{
struct ovsdb_jsonrpc_session *s;
LIST_FOR_EACH (s, node, &remote->sessions) {
ovsdb_jsonrpc_monitor_preremove_db(s, db);
ovsdb_jsonrpc_trigger_preremove_db(s, db);
}
}
static void
ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *s)
{
@ -600,17 +629,23 @@ ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *remote)
}
}
/* Forces all of the JSON-RPC sessions managed by 'remote' to disconnect and
* reconnect. */
/* Makes all of the JSON-RPC sessions managed by 'remote' disconnect. (They
* will then generally reconnect.).
*
* If 'force' is true, disconnects all sessions. Otherwise, disconnects only
* sesions that aren't database change aware. */
static void
ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *remote)
ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *remote,
bool force)
{
struct ovsdb_jsonrpc_session *s, *next;
LIST_FOR_EACH_SAFE (s, next, node, &remote->sessions) {
jsonrpc_session_force_reconnect(s->js);
if (!jsonrpc_session_is_alive(s->js)) {
ovsdb_jsonrpc_session_close(s);
if (force || !s->db_change_aware) {
jsonrpc_session_force_reconnect(s->js);
if (!jsonrpc_session_is_alive(s->js)) {
ovsdb_jsonrpc_session_close(s);
}
}
}
}
@ -852,6 +887,17 @@ ovsdb_jsonrpc_session_unlock__(struct ovsdb_lock_waiter *waiter)
ovsdb_lock_waiter_destroy(waiter);
}
static struct jsonrpc_msg *
syntax_error_reply(const struct jsonrpc_msg *request, const char *details)
{
struct ovsdb_error *error = ovsdb_syntax_error(
request->params, NULL, "%s: %s", request->method, details);
struct jsonrpc_msg *msg = jsonrpc_create_error(ovsdb_error_to_json(error),
request->id);
ovsdb_error_destroy(error);
return msg;
}
static struct jsonrpc_msg *
ovsdb_jsonrpc_session_unlock(struct ovsdb_jsonrpc_session *s,
struct jsonrpc_msg *request)
@ -866,24 +912,21 @@ ovsdb_jsonrpc_session_unlock(struct ovsdb_jsonrpc_session *s,
error = ovsdb_jsonrpc_session_parse_lock_name(request, &lock_name);
if (error) {
goto error;
return jsonrpc_create_error(ovsdb_error_to_json_free(error),
request->id);
}
/* Report error if this session has not issued a "lock" or "steal" for this
* lock. */
waiter = ovsdb_session_get_lock_waiter(&s->up, lock_name);
if (!waiter) {
error = ovsdb_syntax_error(
request->params, NULL, "\"unlock\" without \"lock\" or \"steal\"");
goto error;
return syntax_error_reply(request,
"\"unlock\" without \"lock\" or \"steal\"");
}
ovsdb_jsonrpc_session_unlock__(waiter);
return jsonrpc_create_reply(json_object_create(), request->id);
error:
return jsonrpc_create_error(ovsdb_error_to_json_free(error), request->id);
}
static struct jsonrpc_msg *
@ -897,6 +940,21 @@ execute_transaction(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
return NULL;
}
static struct jsonrpc_msg *
ovsdb_jsonrpc_session_set_db_change_aware(struct ovsdb_jsonrpc_session *s,
const struct jsonrpc_msg *request)
{
const struct json_array *params = json_array(request->params);
if (params->n != 1
|| (params->elems[0]->type != JSON_TRUE &&
params->elems[0]->type != JSON_FALSE)) {
return syntax_error_reply(request, "true or false parameter expected");
}
s->db_change_aware = json_boolean(params->elems[0]);
return jsonrpc_create_reply(json_object_create(), request->id);
}
static void
ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s,
struct jsonrpc_msg *request)
@ -957,6 +1015,8 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s,
reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_STEAL);
} else if (!strcmp(request->method, "unlock")) {
reply = ovsdb_jsonrpc_session_unlock(s, request);
} else if (!strcmp(request->method, "set_db_change_aware")) {
reply = ovsdb_jsonrpc_session_set_db_change_aware(s, request);
} else if (!strcmp(request->method, "echo")) {
reply = jsonrpc_create_reply(json_clone(request->params), request->id);
} else {
@ -1092,14 +1152,34 @@ ovsdb_jsonrpc_trigger_complete(struct ovsdb_jsonrpc_trigger *t)
}
static void
ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *s)
ovsdb_jsonrpc_trigger_remove__(struct ovsdb_jsonrpc_session *s,
struct ovsdb *db)
{
struct ovsdb_jsonrpc_trigger *t, *next;
HMAP_FOR_EACH_SAFE (t, next, hmap_node, &s->triggers) {
ovsdb_jsonrpc_trigger_complete(t);
if (!db || t->trigger.db == db) {
ovsdb_jsonrpc_trigger_complete(t);
}
}
}
/* Database 'db' is about to be removed from the database server. To prepare,
* this function removes all references from triggers in 's' to 'db'. */
static void
ovsdb_jsonrpc_trigger_preremove_db(struct ovsdb_jsonrpc_session *s,
struct ovsdb *db)
{
ovs_assert(db);
ovsdb_jsonrpc_trigger_remove__(s, db);
}
/* Removes all triggers from 's'. */
static void
ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *s)
{
ovsdb_jsonrpc_trigger_remove__(s, NULL);
}
static void
ovsdb_jsonrpc_trigger_complete_done(struct ovsdb_jsonrpc_session *s)
{
@ -1519,15 +1599,42 @@ ovsdb_jsonrpc_monitor_cancel(struct ovsdb_jsonrpc_session *s,
}
static void
ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s)
ovsdb_jsonrpc_monitor_remove__(struct ovsdb_jsonrpc_session *s,
struct ovsdb *db)
{
struct ovsdb_jsonrpc_monitor *m, *next;
HMAP_FOR_EACH_SAFE (m, next, node, &s->monitors) {
ovsdb_jsonrpc_monitor_destroy(m);
if (!db || m->db == db) {
if (db && jsonrpc_session_is_connected(s->js)
&& s->db_change_aware) {
struct jsonrpc_msg *notify = jsonrpc_create_notify(
"monitor_canceled",
json_array_create_1(json_clone(m->monitor_id)));
ovsdb_jsonrpc_session_send(s, notify);
}
ovsdb_jsonrpc_monitor_destroy(m);
}
}
}
/* Database 'db' is about to be removed from the database server. To prepare,
* this function removes all references from monitors in 's' to 'db'. */
static void
ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *s,
struct ovsdb *db)
{
ovs_assert(db);
ovsdb_jsonrpc_monitor_remove__(s, db);
}
/* Cancels all monitors in 's'. */
static void
ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s)
{
ovsdb_jsonrpc_monitor_remove__(s, NULL);
}
static struct json *
ovsdb_jsonrpc_monitor_compose_update(struct ovsdb_jsonrpc_monitor *m,
bool initial)

View File

@ -27,7 +27,7 @@ struct uuid;
struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(bool read_only);
bool ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *,
struct ovsdb *);
bool ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *,
void ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *,
struct ovsdb *);
void ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *);
@ -64,7 +64,7 @@ bool ovsdb_jsonrpc_server_get_remote_status(
void ovsdb_jsonrpc_server_free_remote_status(
struct ovsdb_jsonrpc_remote_status *);
void ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *);
void ovsdb_jsonrpc_server_reconnect(struct ovsdb_jsonrpc_server *, bool force);
void ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *);
void ovsdb_jsonrpc_server_wait(struct ovsdb_jsonrpc_server *);

View File

@ -75,6 +75,13 @@ struct ovsdb_client_command {
/* --timestamp: Print a timestamp before each update on "monitor" command? */
static bool timestamp;
/* --db-change-aware, --no-db-change-aware: Enable db_change_aware feature for
* "monitor" command?
*
* (This option is undocumented because it is expected to be useful only for
* testing that the db_change_aware feature actually works.) */
static int db_change_aware;
/* --force: Ignore schema differences for "restore" command? */
static bool force;
@ -201,6 +208,8 @@ parse_options(int argc, char *argv[])
{"timestamp", no_argument, NULL, OPT_TIMESTAMP},
{"force", no_argument, NULL, OPT_FORCE},
{"timeout", required_argument, NULL, 't'},
{"db-change-aware", no_argument, &db_change_aware, 1},
{"no-db-change-aware", no_argument, &db_change_aware, 0},
VLOG_LONG_OPTIONS,
DAEMON_LONG_OPTIONS,
#ifdef HAVE_OPENSSL
@ -1034,7 +1043,6 @@ do_monitor__(struct jsonrpc *rpc, const char *database,
const char *table_name = argv[0];
struct unixctl_server *unixctl;
struct ovsdb_schema *schema;
struct jsonrpc_msg *request;
struct json *monitor, *monitor_requests, *request_id;
bool exiting = false;
bool blocked = false;
@ -1102,11 +1110,29 @@ do_monitor__(struct jsonrpc *rpc, const char *database,
free(nodes);
}
if (db_change_aware) {
struct jsonrpc_msg *request = jsonrpc_create_request(
"set_db_change_aware",
json_array_create_1(json_boolean_create(true)),
NULL);
struct jsonrpc_msg *reply;
int error = jsonrpc_transact_block(rpc, request, &reply);
if (error) {
ovs_fatal(error, "%s: error setting db_change_aware", server);
}
if (reply->type == JSONRPC_ERROR) {
ovs_fatal(0, "%s: set_db_change_aware failed (%s)",
server, json_to_string(reply->error, 0));
}
jsonrpc_msg_destroy(reply);
}
monitor = json_array_create_3(json_string_create(database),
json_null_create(), monitor_requests);
const char *method = version == OVSDB_MONITOR_V2 ? "monitor_cond"
: "monitor";
struct jsonrpc_msg *request;
request = jsonrpc_create_request(method, monitor, NULL);
request_id = json_clone(request->id);
jsonrpc_send(rpc, request);

View File

@ -1240,7 +1240,7 @@ ovsdb_server_disable_monitor_cond(struct unixctl_conn *conn,
struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_;
ovsdb_jsonrpc_disable_monitor_cond();
ovsdb_jsonrpc_server_reconnect(jsonrpc);
ovsdb_jsonrpc_server_reconnect(jsonrpc, true);
unixctl_command_reply(conn, NULL);
}
@ -1298,7 +1298,7 @@ ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED,
const char *argv[] OVS_UNUSED, void *jsonrpc_)
{
struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_;
ovsdb_jsonrpc_server_reconnect(jsonrpc);
ovsdb_jsonrpc_server_reconnect(jsonrpc, true);
unixctl_command_reply(conn, NULL);
}
@ -1400,10 +1400,9 @@ ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
static void
remove_db(struct server_config *config, struct shash_node *node)
{
struct db *db;
struct db *db = node->data;
db = node->data;
ovs_assert(ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db));
ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db);
close_db(db);
shash_delete(config->all_dbs, node);

View File

@ -169,14 +169,31 @@ AT_CLEANUP
AT_SETUP([ovsdb-server/add-db and remove-db])
AT_KEYWORDS([ovsdb server positive])
on_exit 'kill `cat ovsdb-server.pid`'
on_exit 'kill `cat *.pid`'
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:db.sock db1], [0])
AT_CHECK([ovsdb-server -vfile -vvlog:off --log-file --detach --no-chdir --pidfile --remote=punix:db.sock db1], [0])
CHECK_DBS([ordinals
])
# Remove the database.
AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/remove-db ordinals], [0])
CHECK_DBS([])
# Start monitoring processes.
AT_CHECK([ovsdb-client --detach --pidfile=ovsdb-client-1.pid --no-db-change-aware --no-headings monitor _Server Database name > db-change-unaware.stdout 2> db-change-unaware.stderr])
AT_CHECK([ovsdb-client --detach --pidfile=ovsdb-client-2.pid --db-change-aware --no-headings monitor _Server Database name > db-change-aware.stdout 2> db-change-aware.stderr])
AT_CAPTURE_FILE([db-change-unaware.stdout])
AT_CAPTURE_FILE([db-change-unaware.stderr])
AT_CAPTURE_FILE([db-change-aware.stdout])
AT_CAPTURE_FILE([db-change-aware.stderr])
# Add the first database back.
AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db1], [0])
CHECK_DBS([ordinals
])
@ -243,6 +260,25 @@ AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], [0])
CHECK_DBS([constraints
])
AT_CHECK([ovsdb-client list-tables unix:db.sock constraints], [0], [ignore], [ignore])
# Check the monitoring results.
AT_CHECK([uuidfilt db-change-aware.stdout], [0], [dnl
<0> initial _Server
<1> insert ordinals
<2> insert constraints
<1> delete ordinals
<2> delete constraints
<3> insert constraints
])
AT_CHECK([uuidfilt db-change-unaware.stdout], [0], [dnl
<0> initial _Server
])
OVS_APP_EXIT_AND_WAIT([ovsdb-server])
AT_CLEANUP