[ovs-dev] [PATCH 4/4] ovs-vsctl: Add "wait-until" command.

Ben Pfaff blp at nicira.com
Thu Jun 24 18:41:30 UTC 2010


Requested-by: Sajjad Lateef <slateef at nicira.com>
---
 tests/ovs-vsctl.at       |   52 +++++++++++++++++++++++
 utilities/ovs-vsctl.8.in |   31 ++++++++++++++
 utilities/ovs-vsctl.c    |  102 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 185 insertions(+), 0 deletions(-)

diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
index 89ef589..f31c8ef 100644
--- a/tests/ovs-vsctl.at
+++ b/tests/ovs-vsctl.at
@@ -696,6 +696,58 @@ AT_CHECK([RUN_OVS_VSCTL([destroy b br2])],
 OVS_VSCTL_CLEANUP
 AT_CLEANUP
 
+AT_SETUP([database commands -- wait-until immediately true])
+AT_KEYWORDS([ovs-vsctl])
+OVS_VSCTL_SETUP
+AT_CHECK([RUN_OVS_VSCTL(
+    [add-br br0], 
+    [add-bond br0 bond0 eth0 eth1],
+    [set port bond0 bond_updelay=500 other-config:abc=def])],
+  [0], [], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([RUN_OVS_VSCTL([[wait-until Open_vSwitch . managers=[]]])],
+  [0], [], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([RUN_OVS_VSCTL([[wait-until Open_vSwitch . bridges!=[]]])],
+  [0], [], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([RUN_OVS_VSCTL([[wait-until Port bond0 other-config:abc=def]])],
+  [0], [], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([RUN_OVS_VSCTL([[wait-until port bond0 'bond_updelay>50' 'other-config:abc>d' 'other-config:abc<e']])],
+  [0], [], [], [OVS_VSCTL_CLEANUP])
+OVS_VSCTL_CLEANUP
+AT_CLEANUP
+
+AT_SETUP([database commands -- wait-until must wait])
+AT_KEYWORDS([ovs-vsctl])
+OVS_VSCTL_SETUP
+
+# Start ovs-vsctls in background.
+(RUN_OVS_VSCTL([[wait-until o . bridges!=[] -- get bridge br10 other-config:abc]])) > stdout1 &
+(RUN_OVS_VSCTL([[wait-until bridge br1 -- get bridge br1 other-config:abc]])) > stdout2 &
+(RUN_OVS_VSCTL([[wait-until b br1 other-config={abc=def} -- get bridge br1 other-config]])) > stdout3 &
+(RUN_OVS_VSCTL([[wait-until port bond0 'bond_updelay>50' -- get port bond0 bond-updelay]])) > stdout4 &
+
+# Give the ovs-vsctls a chance to read the database
+sleep 1
+
+AT_CHECK([RUN_OVS_VSCTL([add-br br10 -- set bridge br1 other-config:abc=quux])
+RUN_OVS_VSCTL([add-br br1 -- set bridge br1 other-config:abc=def -- add-bond br1 bond0 eth0 eth1 -- set port bond0 bond_updelay=500])],
+  [0], [], [], [OVS_VSCTL_CLEANUP])
+
+# Wait for the ovs-vsctls to finish.
+wait
+
+# Check output
+AT_CHECK([cat stdout1], [0], [quux
+], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([cat stdout2], [0], [def
+], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([cat stdout3], [0], [{abc=def}
+], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([cat stdout4], [0], [500
+], [], [OVS_VSCTL_CLEANUP])
+
+OVS_VSCTL_CLEANUP
+AT_CLEANUP
+
 dnl This test really shows a bug -- "create" followed by "list" in
 dnl the same execution shows the wrong UUID on the "list" command.
 dnl The bug is documented in ovs-vsctl.8.
diff --git a/utilities/ovs-vsctl.8.in b/utilities/ovs-vsctl.8.in
index ab487ad..cba4a0b 100644
--- a/utilities/ovs-vsctl.8.in
+++ b/utilities/ovs-vsctl.8.in
@@ -574,6 +574,37 @@ precede or follow the \fBcreate\fR command.
 .IP "\fR[\fB\-\-if\-exists\fR] \fBdestroy \fItable record\fR..."
 Deletes each specified \fIrecord\fR from \fItable\fR.  Unless
 \fB\-\-if\-exists\fR is specified, each \fIrecord\fRs must exist.
+.
+.IP "\fBwait\-until \fItable record \fR[\fIcolumn\fR[\fB:\fIkey\fR]\fB=\fIvalue\fR]..."
+Waits until \fItable\fR contains a record named \fIrecord\fR whose
+\fIcolumn\fR equals \fIvalue\fR or, if \fIkey\fR is specified, whose
+\fIcolumn\fR contains a \fIkey\fR with the specified \fIvalue\fR.  Any
+of the operators \fB!=\fR, \fB<\fR, \fB>\fR, \fB<=\fR, or \fB>=\fR may
+be substituted for \fB=\fR to test for inequality, less than, greater
+than, less than or equal to, or greater than or equal to,
+respectively.
+.IP
+If no \fIcolumn\fR[\fB:\fIkey\fR]\fB=\fIvalue\fR arguments are given,
+this command waits only until \fIrecord\fR exists.  If more than one
+such argument is given, the command waits until all of them are
+satisfied.
+.IP
+Usually \fBwait\-until\fR should be placed at the beginning of a set
+of \fBovs\-vsctl\fR commands.  For example, \fBwait\-until bridge br0
+\-\- get bridge br0 datapath_id\fR waits until a bridge named
+\fBbr0\fR is created, then prints its \fBdatapath_id\fR column,
+whereas \fBget bridge br0 datapath_id \-\- wait\-until bridge br0\fR
+will abort if no bridge named \fBbr0\fR exists when \fBovs\-vsctl\fR
+initially connects to the database.
+.IP
+Unlike all the other database commands, \fBwait\-until\fR treats its
+\fIrecord\fR argument as case-sensitive and does not allow it to be
+abbreviated.  Otherwise, \fBwait\-until br1\fR would be satisfied by a
+bridge named \fBbr10\fR.
+.IP
+Consider specifying \fB\-\-timeout=0\fR along with
+\fB\-\-wait\-until\fR, to prevent \fBovs\-vsctl\fR from terminating
+after waiting only at most 5 seconds.
 .SH "EXAMPLES"
 Create a new bridge named br0 and add port eth0 to it:
 .IP
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index 43d33ea..50784c9 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -465,6 +465,7 @@ Database commands:\n\
   clear TBL REC COL           clear values from COLumn in RECord in TBL\n\
   create TBL COL[:KEY]=VALUE  create and initialize new record\n\
   destroy TBL REC             delete REC from TBL\n\
+  wait-until TBL REC [COL[:KEY]=VALUE]  wait until condition is true\n\
 Potentially unsafe database commands require --force option.\n\
 \n\
 Options:\n\
@@ -2640,6 +2641,106 @@ cmd_destroy(struct vsctl_context *ctx)
         }
     }
 }
+
+static bool
+is_condition_satified(const struct vsctl_table_class *table,
+                      const struct ovsdb_idl_row *row, const char *arg,
+                      struct ovsdb_symbol_table *symtab)
+{
+    static const char *operators[] = {
+        "=", "!=", "<", ">", "<=", ">="
+    };
+    enum { N_OPERATORS = ARRAY_SIZE(operators) };
+
+    const struct ovsdb_idl_column *column;
+    char *key_string, *value_string;
+    struct ovsdb_datum have_datum;
+    const char *operator;
+    unsigned int idx;
+    char *error;
+    int cmp;
+
+    error = parse_column_key_value(arg, table, &column, &key_string,
+                                   &operator, operators, N_OPERATORS,
+                                   &value_string);
+    die_if_error(error);
+    if (!value_string) {
+        vsctl_fatal("%s: missing value", arg);
+    }
+
+    ovsdb_idl_txn_read(row, column, &have_datum);
+    if (key_string) {
+        union ovsdb_atom want_key, want_value;
+
+        if (column->type.value.type == OVSDB_TYPE_VOID) {
+            vsctl_fatal("cannot specify key to check for non-map column %s",
+                        column->name);
+        }
+
+        die_if_error(ovsdb_atom_from_string(&want_key, &column->type.key,
+                                            key_string, symtab));
+        die_if_error(ovsdb_atom_from_string(&want_value, &column->type.value,
+                                            value_string, symtab));
+
+        idx = ovsdb_datum_find_key(&have_datum,
+                                   &want_key, column->type.key.type);
+        if (idx != UINT_MAX) {
+            cmp = ovsdb_atom_compare_3way(&have_datum.values[idx],
+                                          &want_value,
+                                          column->type.value.type);
+        }
+
+        ovsdb_atom_destroy(&want_key, column->type.key.type);
+        ovsdb_atom_destroy(&want_value, column->type.value.type);
+    } else {
+        struct ovsdb_datum want_datum;
+
+        die_if_error(ovsdb_datum_from_string(&want_datum, &column->type,
+                                             value_string, symtab));
+        idx = 0;
+        cmp = ovsdb_datum_compare_3way(&have_datum, &want_datum,
+                                       &column->type);
+        ovsdb_datum_destroy(&want_datum, &column->type);
+    }
+    ovsdb_datum_destroy(&have_datum, &column->type);
+
+    free(key_string);
+    free(value_string);
+
+    return (idx == UINT_MAX ? false
+            : !strcmp(operator, "=") ? cmp == 0
+            : !strcmp(operator, "!=") ? cmp != 0
+            : !strcmp(operator, "<") ? cmp < 0
+            : !strcmp(operator, ">") ? cmp > 0
+            : !strcmp(operator, "<=") ? cmp <= 0
+            : !strcmp(operator, ">=") ? cmp >= 0
+            : (abort(), 0));
+}
+
+static void
+cmd_wait_until(struct vsctl_context *ctx)
+{
+    const char *table_name = ctx->argv[1];
+    const char *record_id = ctx->argv[2];
+    const struct vsctl_table_class *table;
+    const struct ovsdb_idl_row *row;
+    int i;
+
+    table = get_table(table_name);
+
+    row = get_row__(ctx, table, record_id, false);
+    if (!row) {
+        ctx->try_again = true;
+        return;
+    }
+
+    for (i = 3; i < ctx->argc; i++) {
+        if (!is_condition_satified(table, row, ctx->argv[i], ctx->symtab)) {
+            ctx->try_again = true;
+            return;
+        }
+    }
+}
 
 static struct json *
 where_uuid_equals(const struct uuid *uuid)
@@ -2895,6 +2996,7 @@ static const struct vsctl_command_syntax all_commands[] = {
     {"clear", 3, INT_MAX, cmd_clear, NULL, ""},
     {"create", 2, INT_MAX, cmd_create, post_create, "--id="},
     {"destroy", 1, INT_MAX, cmd_destroy, NULL, "--if-exists"},
+    {"wait-until", 2, INT_MAX, cmd_wait_until, NULL, ""},
 
     {NULL, 0, 0, NULL, NULL, NULL},
 };
-- 
1.7.1





More information about the dev mailing list