ovs-vsctl: Add the ability to perform multiple operations in a single run.
authorBen Pfaff <blp@nicira.com>
Fri, 16 Oct 2009 16:42:21 +0000 (09:42 -0700)
committerBen Pfaff <blp@nicira.com>
Fri, 16 Oct 2009 16:42:21 +0000 (09:42 -0700)
CC: Ian Campbell <Ian.Campbell@citrix.com>
tests/ovs-vsctl.at
utilities/ovs-vsctl.8.in
utilities/ovs-vsctl.in

index 834ecc6..5f19665 100644 (file)
@@ -7,6 +7,15 @@ m4_define([RUN_OVS_VSCTL],
 m4_foreach([command], [$@], [ovs-vsctl --no-reload --config=conf command
 ])])
 
+dnl RUN_OVS_VSCTL_TOGETHER(COMMAND, ...)
+dnl
+dnl Executes each ovs-vsctl COMMAND on a file named "conf" in the
+dnl current directory, in a single run of ovs-vsctl.  Creates "conf" if it
+dnl does not already exist.
+m4_define([RUN_OVS_VSCTL_TOGETHER],
+  [: >> conf
+   ovs-vsctl --no-reload --config=conf m4_join([ -- ], $@)])
+
 dnl CHECK_BRIDGES([BRIDGE, PARENT, VLAN], ...)
 dnl
 dnl Verifies that "ovs-vsctl list-br" prints the specified list of bridges,
@@ -24,6 +33,12 @@ m4_define([_CHECK_BRIDGE],
    # an integer instead of a string and that can cause type mismatches inside
    # python if not done carefully.)
    AT_CHECK([RUN_OVS_VSCTL([--oneline br-to-vlan $1])], [0], [$3
+])
+
+   # Check multiple queries in a single run.
+   AT_CHECK([RUN_OVS_VSCTL_TOGETHER([br-to-parent $1], [br-to-vlan $1])], [0],
+[$2
+$3
 ])])
 m4_define([CHECK_BRIDGES],
   [dnl Check that the bridges appear on list-br, without --oneline.
@@ -152,7 +167,7 @@ AT_CLEANUP
 
 AT_SETUP([add-br a b, add-port a a1, add-port b b1, del-br a])
 AT_KEYWORDS([ovs-vsctl])
-AT_CHECK([RUN_OVS_VSCTL(
+AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
    [add-br a], 
    [add-br b], 
    [add-port a a1],
@@ -206,7 +221,7 @@ AT_CLEANUP
 
 AT_SETUP([add-br a, add-bond a bond0 a1 a2 a3, del-port bond0])
 AT_KEYWORDS([ovs-vsctl])
-AT_CHECK([RUN_OVS_VSCTL(
+AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
   [add-br a], 
   [add-bond a bond0 a1 a2 a3],
   [del-port bond0])])
index bc4cb11..7f6326e 100644 (file)
@@ -12,6 +12,7 @@ ovs\-vsctl \- utility for querying and configuring \fBovs\-vswitchd\fR
 .
 .SH SYNOPSIS
 \fBovs\-vsctl\fR [\fIoptions\fR] \fIcommand \fR[\fIargs\fR\&...]
+[\fB\-\-\fR \fIcommand \fR[\fIargs\fR\&...]]
 .
 .SH DESCRIPTION
 The \fBovs\-vsctl\fR program configures \fBovs\-vswitchd\fR(8), mainly
@@ -22,7 +23,8 @@ when \fBovs\-vswitchd\fR is running, but it can also be used when
 changes will only take effect when \fBovs\-vswitchd\fR is started.
 .PP
 By default, each time \fBovs\-vsctl\fR runs, it examines and,
-depending on the requested command, possibly applies changes to an
+depending on the requested command or commands, possibly applies
+changes to an
 \fBovs\-vswitchd.conf\fR file.  Then, if it applied any changes and if
 \fBovs\-vswitchd\fR is running, it tells \fBovs\-vswitchd\fR to reload
 the modified configuration file and waits for the reload to complete
@@ -99,10 +101,11 @@ By default, \fBovs\-vsctl\fR logs its arguments and the details of any
 changes that it makes to the system log.  This option disables this
 logging.
 .IP "\fB\-\-oneline\fR"
-Modifies the output format so that the output for a command is printed
+Modifies the output format so that the output for each command is printed
 on a single line.  New-line characters that would otherwise separate
-lines are printed as \fB\\n\fR, and any instances of \fB\\fR that
+lines are printed as \fB\\n\fR, and any instances of \fB\\\fR that
 would otherwise appear in the output are doubled.
+Prints a blank line for each command that has no output.
 .
 .SH COMMANDS
 The commands implemented by \fBovs\-vsctl\fR are described in the
@@ -185,6 +188,16 @@ list.
 .IP "\fBiface\-to\-br \fIiface\fR"
 Prints the name of the bridge that contains \fIiface\fR on standard
 output.
+.SH "EXAMPLES"
+Create a new bridge named br0 and add port eth0 to it:
+.IP
+.B "ovs-vsctl add\-br br0"
+.br
+.B "ovs-vsctl add\-port br0 eth0"
+.PP
+Alternatively, perform both operations in a single atomic transaction:
+.IP 
+.B "ovs-vsctl add\-br br0 \-\- add\-port br0 eth0"
 .
 .SH "EXIT STATUS"
 .IP "0"
index d8b4404..cc9f52b 100755 (executable)
@@ -480,17 +480,66 @@ def cmd_br_to_parent(cfg, bridge):
     parent, vlan = find_bridge(cfg, bridge)
     return (parent,)
     
+cmdTable = {'add-br': (cmd_add_br, True, lambda n: n == 1 or n == 3),
+            'del-br': (cmd_del_br, True, 1),
+            'list-br': (cmd_list_br, False, 0),
+            'br-exists': (cmd_br_exists, False, 1),
+            'list-ports': (cmd_list_ports, False, 1),
+            'add-port': (cmd_add_port, True, 2),
+            'add-bond': (cmd_add_bond, True, lambda n: n >= 4),
+            'del-port': (cmd_del_port, True, lambda n: n == 1 or n == 2),
+            'port-to-br': (cmd_port_to_br, False, 1),
+            'br-to-vlan': (cmd_br_to_vlan, False, 1),
+            'br-to-parent': (cmd_br_to_parent, False, 1),
+            'list-ifaces': (cmd_list_ifaces, False, 1),
+            'iface-to-br': (cmd_iface_to_br, False, 1)}
+
+# Break up commands at -- boundaries.
+def split_commands(args):
+    commands = []
+    command = []
+    for arg in args:
+        if arg == '--':
+            if command:
+                commands.append(command)
+            command = []
+        else:
+            command.append(arg)
+    if command:
+        commands.append(command)
+    return commands
+
+def check_command(args):
+    command, args = args[0], args[1:]
+    if command not in cmdTable:
+        sys.stderr.write("%s: unknown command '%s' (use --help for help)\n"
+                         % (argv0, command))
+        sys.exit(1)
+
+    function, is_mutator, nargs = cmdTable[command]
+    if callable(nargs) and not nargs(len(args)):
+        sys.stderr.write("%s: '%s' command does not accept %d arguments (use --help for help)\n" % (argv0, command, len(args)))
+        sys.exit(1)
+    elif not callable(nargs) and len(args) != nargs:
+        sys.stderr.write("%s: '%s' command takes %d arguments but %d were supplied (use --help for help)\n" % (argv0, command, nargs, len(args)))
+        sys.exit(1)
+
+def run_command(cfg, args):
+    command, args = args[0], args[1:]
+    function, need_lock, nargs = cmdTable[command]
+    return function(cfg, *args)
+
 def main():
     # Parse command line.
     try:
-        options, args = getopt.gnu_getopt(sys.argv[1:], "c:t:hV",
-                                          ["config=",
-                                           "target=",
-                                           "no-reload",
-                                           "no-syslog",
-                                           "oneline",
-                                           "help",
-                                           "version"])
+        options, args = getopt.getopt(sys.argv[1:], "c:t:hV",
+                                      ["config=",
+                                       "target=",
+                                       "no-reload",
+                                       "no-syslog",
+                                       "oneline",
+                                       "help",
+                                       "version"])
     except getopt.GetoptError, msg:
         sys.stderr.write("%s: %s (use --help for help)\n" % (argv0, msg))
         sys.exit(1)
@@ -525,52 +574,35 @@ def main():
         syslog.openlog("ovs-vsctl")
         log("Called as %s" % ' '.join(sys.argv[1:]))
 
-    # Execute commands.
-    if not args:
+    # Break arguments into a series of commands.
+    commands = split_commands(args)
+    if not commands:
         sys.stderr.write("%s: missing command name (use --help for help)\n"
                          % argv0)
         sys.exit(1)
 
-    commands = {'add-br': (cmd_add_br, True, lambda n: n == 1 or n == 3),
-                'del-br': (cmd_del_br, True, 1),
-                'list-br': (cmd_list_br, False, 0),
-                'br-exists': (cmd_br_exists, False, 1),
-                'list-ports': (cmd_list_ports, False, 1),
-                'add-port': (cmd_add_port, True, 2),
-                'add-bond': (cmd_add_bond, True, lambda n: n >= 4),
-                'del-port': (cmd_del_port, True, lambda n: n == 1 or n == 2),
-                'port-to-br': (cmd_port_to_br, False, 1),
-                'br-to-vlan': (cmd_br_to_vlan, False, 1),
-                'br-to-parent': (cmd_br_to_parent, False, 1),
-                'list-ifaces': (cmd_list_ifaces, False, 1),
-                'iface-to-br': (cmd_iface_to_br, False, 1)}
-    command = args[0]
-    args = args[1:]
-    if command not in commands:
-        sys.stderr.write("%s: unknown command '%s' (use --help for help)\n"
-                         % (argv0, command))
-        sys.exit(1)
+    # Check command syntax.
+    need_lock = False
+    for command in commands:
+        check_command(command)
+        if cmdTable[command[0]][1]:
+            need_lock = True
 
-    function, is_mutator, nargs = commands[command]
-    if callable(nargs) and not nargs(len(args)):
-        sys.stderr.write("%s: '%s' command does not accept %d arguments (use --help for help)\n" % (argv0, command, len(args)))
-        sys.exit(1)
-    elif not callable(nargs) and len(args) != nargs:
-        sys.stderr.write("%s: '%s' command takes %d arguments but %d were supplied (use --help for help)\n" % (argv0, command, nargs, len(args)))
-        sys.exit(1)
-    else:
-        cfg = cfg_read(VSWITCHD_CONF, is_mutator)
-        output = function(cfg, *args)
-        if output != None:
-            if oneline:
-                print '\\n'.join([str(s).replace('\\', '\\\\')
-                                  for s in output])
-            else:
-                for line in output:
-                    print line
-        if is_mutator:
-            cfg_save(cfg, VSWITCHD_CONF)
-        sys.exit(0)
+    # Execute commands.
+    cfg = cfg_read(VSWITCHD_CONF, need_lock)
+    for command in commands:
+        output = run_command(cfg, command)
+        if oneline:
+            if output == None:
+                output = ()
+            print '\\n'.join([str(s).replace('\\', '\\\\')
+                              for s in output])
+        elif output != None:
+            for line in output:
+                print line
+    if need_lock:
+        cfg_save(cfg, VSWITCHD_CONF)
+    sys.exit(0)
 
 if __name__ == "__main__":
     try: