Rewrite to use ansible.
authorRichard W.M. Jones <rjones@redhat.com>
Mon, 12 May 2014 12:50:12 +0000 (13:50 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Mon, 12 May 2014 14:34:36 +0000 (15:34 +0100)
18 files changed:
README
configure.ac
lib.py
mclu.conf
mclu.py
mclu.spec.in
mclu_build.py
mclu_console.py
mclu_import.py
mclu_list.py
mclu_migrate.py
mclu_off.py
mclu_on.py
mclu_reboot.py
mclu_start.py
mclu_status.py
mclu_stop.py
mclu_viewer.py

diff --git a/README b/README
index f63c742..0c4e473 100644 (file)
--- a/README
+++ b/README
@@ -4,13 +4,14 @@ The key features:
 
  - Entirely command line driven.
 
- - No required dependencies except libvirt and ssh.
-
- - Only designed for tiny clusters (up to around 10 hosts).
+ - No required dependencies except ansible (on the client only),
+   libvirt and ssh.
 
  - Nothing to install on the nodes except libvirtd and sshd.
 
- - Single, simple configuration file.
+ - Only designed for small clusters (up to around 10-20 hosts).
+
+ - Simple configuration.
 
 Example commands
 ----------------------------------------------------------------------
@@ -57,6 +58,9 @@ To run without installing:
 
  - Edit the configuration file (mclu.conf).
 
+ - Add the hosts group (usually called '[cluster]') to /etc/ansible/hosts.
+   You can set $ANSIBLE_HOSTS to change the location of this file.
+
  - Run commands such as:
 
    ./run status
@@ -68,6 +72,8 @@ To install:
 
  - Edit the configuration file (/etc/mclu/mclu.conf).
 
+ - Add the hosts group (usually called '[cluster]') to /etc/ansible/hosts.
+
  - Run commands such as:
 
    mclu status
index 3ba8958..de668bc 100644 (file)
@@ -40,6 +40,14 @@ if test "x$SSH" = "xno"; then
     AC_MSG_ERROR([SSH client is required])
 fi
 
+dnl Ansible client (required).
+dnl Actually the ansible command line tool is not used, but we do use
+dnl the Python library.  XXX Should check for that instead.
+AC_PATH_PROG([ANSIBLE],[ansible],[no])
+if test "x$ANSIBLE" = "xno"; then
+    AC_MSG_ERROR([ansible is required])
+fi
+
 dnl Wake-on-LAN client (optional).
 AC_PATH_PROG([WOL],[wol],[no])
 
diff --git a/lib.py b/lib.py
index 961b5b0..1430f14 100644 (file)
--- a/lib.py
+++ b/lib.py
 import sys
 import os
 import re
-import libvirt
-
-# Helper function to ping all the nodes.
-def ping_nodes (nodes):
-    for node in nodes.values():
-        node.ping ()
 
-# Helper function to get node objects from a list of node names.
-def get_nodes_by_name (all_nodes, names, all):
-    if not all:
-        return map (lambda name : get_node_by_name (all_nodes, name), names)
-    else:
-        return all_nodes.values()
-
-def get_node_by_name (nodes, name):
-    if name in nodes:
-        return nodes[name]
-    else:
-        sys.exit ("error: node does not exist: %s" % name)
+import libvirt
+import ansible.runner
+import ansible.inventory
 
 # Get separate list of running and inactive guests.
-def get_all_guests (c, nodes):
+def get_all_guests (c):
     running = {}
     inactive = {}
 
     # Find running guests.
-    for node in nodes:
+    runner = ansible.runner.Runner (
+        remote_user = 'root',
+        module_name = 'virt',
+        module_args = 'command=list_vms', # XXX ignore state=shutdown
+        pattern = c['nodes_group'],
+    )
+    data = runner.run ()
+
+    for node in data['contacted'].keys():
         # Get the flat list of guests from this node:
-        doms = node.guests ()
+        vms = data['contacted'][node]['list_vms']
         # Store which node the guest is running on, and turn list into a map.
-        for dom in doms:
-            name = dom.name()
-            if name in running:
-                sys.exit ("error: virtual machine %s is running on two nodes!" % name)
-            running[name] = { 'dom' : dom, 'node' : node }
+        for vm in vms:
+            if node in running:
+                sys.exit ("error: virtual machine %s is running on two nodes!" % node)
+            running[vm] = { 'vm' : vm, 'node' : node }
 
     # Find inactive guests (XML configuration files).
-    for name in get_guest_configs (c, nodes):
+    for name in get_guest_configs (c):
         if name not in running:
             inactive[name] = name
 
     return running, inactive
 
 # Get the names of guests from the XML configuration files in xmls_dir.
-def get_guest_configs (c, nodes):
+def get_guest_configs (c):
     names = []
     for filename in sorted (os.listdir (c['xmls_dir'])):
         m = re.search (r'^(.*)\.xml$', filename)
@@ -71,38 +63,32 @@ def get_guest_configs (c, nodes):
             names.append (m.group (1))
     return names
 
-# Convert virDomainState to string.
-# Copied from virt-manager.
-def pretty_run_status (status):
-    if status == libvirt.VIR_DOMAIN_RUNNING:
-        return "running"
-    elif status == libvirt.VIR_DOMAIN_PAUSED:
-        return "paused"
-    elif status == libvirt.VIR_DOMAIN_SHUTDOWN:
-        return "shutting down"
-    elif status == libvirt.VIR_DOMAIN_SHUTOFF:
-        return "shutoff"
-    elif status == libvirt.VIR_DOMAIN_CRASHED:
-        return "crashed"
-    elif status == libvirt.VIR_DOMAIN_PMSUSPENDED:
-        return "suspended"
-
 # Start a guest running on a given node.  The node must not be
 # running anywhere already.
-def start_guest (c, node, guest_name):
+def start_guest (c, node_name, guest_name):
     fp = open ("%s/%s.xml" % (c['xmls_dir'], guest_name), "r")
     xml = fp.read ()
     fp.close ()
 
-    conn = node.get_connection()
+    conn = libvirt.open (uri_of_node (node_name))
+    if conn == None:
+        sys.exit ("error: could not open a libvirt connection to %s" %
+                  node_name)
     conn.createXML (xml)
 
-def pick_any_node_which_is_up (nodes):
-    node = None
-    for n in nodes.values():
-        if n.ping ():
-            node = n
-            break
-    if not node:
-        sys.exit ("error: no nodes are up, use mclu on [node|--all]")
-    return node
+def pick_any_node_which_is_up (c):
+    inventory = ansible.inventory.Inventory ()
+    runner = ansible.runner.Runner (
+        remote_user = 'root',
+        module_name = 'ping',
+        inventory = inventory,
+        pattern = c['nodes_group'],
+    )
+    data = runner.run ()
+    if len (data['contacted']) == 0:
+        sys.exit ("error: no nodes are up, use mclu on")
+    return data['contacted'].keys()[0]
+
+# XXX Make this configurable.
+def uri_of_node (node_name):
+    return "qemu+ssh://root@%s/system" % node_name
index 8ed1c39..300b79e 100644 (file)
--- a/mclu.conf
+++ b/mclu.conf
@@ -26,41 +26,18 @@ images_dir = /var/lib/libvirt/images
 # nodes.  But it must be available on the machine running 'mclu'.
 xmls_dir = %(config_dir)s/xmls/
 
-# The nodes section lists all nodes.  The keys don't need to be
-# sequential, but must start with 'node'.  The values are the short
-# names of the nodes.  If a node goes out of service permanently, you
-# can just comment it out here.
-[nodes]
-node0 = ham0
-node1 = ham1
-node2 = ham2
-node3 = ham3
-
-# You need one section per node listed in [nodes].
-# Possible fields are:
-#   host
-#     Hostname or IP address of the node, if omitted it uses the
-#     node name as the hostname
-#   mac
-#     MAC (ethernet) address (only used for wake-on-LAN)
-#   uri
-#     Libvirt URI used to access the remote libvirt daemon running
-#     on the node.  The default is: qemu+ssh://root@%(host)s/system
-#     Note that you must allow passwordless root ssh access (eg.
-#     using ssh-agent).
-[ham0]
-host = ham0.home.annexia.org
-mac = 74:d4:35:55:85:3f
-#uri = qemu+ssh://root@%(host)s/system
-[ham1]
-host = ham1.home.annexia.org
-mac = 74:d4:35:51:ab:86
-#uri = qemu+ssh://root@%(host)s/system
-[ham2]
-host = ham2.home.annexia.org
-mac = 74:d4:35:55:82:96
-#uri = qemu+ssh://root@%(host)s/system
-[ham3]
-host = ham3.home.annexia.org
-mac = 74:d4:35:55:84:b4
-#uri = qemu+ssh://root@%(host)s/system
+# The name of the ansible group which contains the list of nodes
+# in the cluster.  You have to edit /etc/ansible/hosts and add a
+# section:
+#
+#   [cluster]
+#   ham0 mac=74:d4:35:55:85:3f
+#   ham1 mac=74:d4:35:51:ab:86
+#   ham2 mac=74:d4:35:55:82:96
+#   ham3 mac=74:d4:35:55:84:b4
+#
+# The mac=... (MAC addresses) are optional, to support wake-on-LAN.
+#
+# If you don't want to edit /etc/ansible/hosts then you can export
+# $ANSIBLE_HOSTS to name another file instead.
+nodes_group = cluster
diff --git a/mclu.py b/mclu.py
index 7c6ad81..0a439ec 100755 (executable)
--- a/mclu.py
+++ b/mclu.py
@@ -23,7 +23,19 @@ import re
 import sys
 
 import config
-from node import Node
+import mclu_build
+import mclu_console
+import mclu_import
+import mclu_info
+import mclu_list
+import mclu_migrate
+import mclu_off
+import mclu_on
+import mclu_reboot
+import mclu_start
+import mclu_status
+import mclu_stop
+import mclu_viewer
 
 parser = argparse.ArgumentParser (
     prog='mclu',
@@ -38,31 +50,18 @@ parser.add_argument (
 
 # Add subcommands.
 subparsers = parser.add_subparsers ()
-import mclu_build
 mclu_build.cmdline (subparsers)
-import mclu_console
 mclu_console.cmdline (subparsers)
-import mclu_import
 mclu_import.cmdline (subparsers)
-import mclu_info
 mclu_info.cmdline (subparsers)
-import mclu_list
 mclu_list.cmdline (subparsers)
-import mclu_migrate
 mclu_migrate.cmdline (subparsers)
-import mclu_off
 mclu_off.cmdline (subparsers)
-import mclu_on
 mclu_on.cmdline (subparsers)
-import mclu_reboot
 mclu_reboot.cmdline (subparsers)
-import mclu_start
 mclu_start.cmdline (subparsers)
-import mclu_status
 mclu_status.cmdline (subparsers)
-import mclu_stop
 mclu_stop.cmdline (subparsers)
-import mclu_viewer
 mclu_viewer.cmdline (subparsers)
 
 args = parser.parse_args()
@@ -79,9 +78,7 @@ else:
 # section, so we have to rely on setting names not overlapping.
 conf_defaults = {
     "home" : os.getenv ("HOME"),
-    "host" : "SET.THIS.IN.MCLU.CONF",
     "config_dir" : config_dir,
-    "uri" : "qemu+ssh://root@%(host)s/system",
 }
 
 # Read the configuration file.
@@ -95,35 +92,18 @@ if not os.path.isdir (images_dir):
 xmls_dir = conf.get ("global", "xmls_dir")
 if not os.path.isdir (xmls_dir):
     sys.exit ("configuration error: [globals] 'xmls_dir' (%s) directory does not exist", xmls_dir)
-
-# Get the list of node names.
-node_names = conf.items ("nodes")
-node_names = filter (lambda (x, _) : re.search (r'^node', x), node_names)
-node_names = [ value for _, value in node_names ]
-if not node_names:
-    sys.exit ("configuration error: [nodes] section in configuration file is empty")
-
-# Get information about each node.
-nodes = {}
-for node_name in node_names:
-    host = conf.get (node_name, "host")
-    if not host:
-        host = node_name
-    mac = conf.get (node_name, "mac")
-    uri = conf.get (node_name, "uri")
-    node = Node (node_name, host, mac, uri)
-    nodes[node_name] = node
+nodes_group = conf.get ("global", "nodes_group")
 
 # A config dict with less-used configuration settings.
 c = {
     "config_file" : args.f.name,
     "config_dir" : config_dir,
     "images_dir" : images_dir,
-    "node_names" : node_names,
+    "nodes_group" : nodes_group,
     "xmls_dir" : xmls_dir,
 
     "conf" : conf,
 }
 
 # Run the subcommand.
-args.run (c, args, nodes)
+args.run (c, args)
index 8a28572..244658b 100644 (file)
@@ -12,9 +12,11 @@ Source0:         @PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz
 BuildRequires:   python-devel
 BuildRequires:   libvirt-python
 BuildRequires:   /usr/bin/ssh
+BuildRequires:   ansible
 
 Requires:        libvirt-python
 Requires:        /usr/bin/ssh
+Requires:        ansible
 
 # These are optional: comment them out to get a less functional mclu.
 BuildRequires:   /usr/bin/wol
index 431602b..929f45a 100644 (file)
@@ -62,26 +62,19 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
+def run (c, args):
     # Did the user request a particular node?  If not, we'll run it
     # on any node which is up.
     m = re.match (r'^(.*):(.*)$', args.name)
     if m:
         node_name = m.group (1)
         vm_name = m.group (2)
-        if node_name in nodes:
-            node = nodes[node_name]
-            if not node.ping ():
-                sys.exit ("error: requested node (%s) is not up, use mclu on %s" %
-                          (node_name, node_name))
-        else:
-            sys.exit ("error: requested node (%s) does not exist" % node_name)
     else:
-        node = lib.pick_any_node_which_is_up (nodes)
+        node = lib.pick_any_node_which_is_up (c)
         vm_name = args.name
 
     # Get all the guests, so we can tell if the name is a duplicate.
-    running, inactive = lib.get_all_guests (c, nodes.values ())
+    running, inactive = lib.get_all_guests (c)
 
     if vm_name in running or vm_name in inactive:
         sys.exit ("error: node name (%s) already exists" % vm_name)
@@ -118,5 +111,5 @@ def run (c, args, nodes):
     fp.close ()
 
     # Start the guest.
-    lib.start_guest (c, node, vm_name)
-    print "guest built and started on node %s" % node.name
+    lib.start_guest (c, node_name, vm_name)
+    print "guest built and started on node %s" % node_name
index 9da4f4b..b4299cd 100644 (file)
@@ -34,28 +34,31 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
-    running, _ = lib.get_all_guests (c, nodes.values ())
+def run (c, args):
+    running, _ = lib.get_all_guests (c)
 
     m = re.match (r'^(.*):(.*)$', args.vm)
-    node_name = None
     if m:
         # We don't actually care about the node, but we check it
         # is the expected one below.
-        node_name = m.group (1)
+        node_name_check = m.group (1)
         vm_name = m.group (2)
     else:
+        node_name_check = None
         vm_name = args.vm
 
     if vm_name not in running:
         sys.exit ("error: vm %s not found or not running" % vm_name)
 
-    dom = running[vm_name]['dom']
-    node = running[vm_name]['node']
+    vm = running[vm_name]['vm']
+    node_name = running[vm_name]['node']
 
-    if node_name and node.name != node_name:
+    if node_name_check and node_name != node_name_check:
         sys.exit ("error: vm %s is not running on node %s, did you mean %s:%s ?" %
-                  (vm_name, node_name, node.name, vm_name))
+                  (vm_name, node_name_check, node_name, vm_name))
 
     # Run the virsh console command.
-    subprocess.call (["virsh", "-c", node.uri, "console", vm_name])
+    subprocess.call (["virsh",
+                      "-c", lib.uri_of_node (node_name),
+                      "console",
+                      vm_name])
index f808182..52ef161 100644 (file)
@@ -53,26 +53,19 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
+def run (c, args):
     # Did the user request a particular node?  If not, we'll run it
     # on any node which is up.
     m = re.match (r'^(.*):(.*)$', args.name)
     if m:
         node_name = m.group (1)
         vm_name = m.group (2)
-        if node_name in nodes:
-            node = nodes[node_name]
-            if not node.ping ():
-                sys.exit ("error: requested node (%s) is not up, use mclu on %s" %
-                          (node_name, node_name))
-        else:
-            sys.exit ("error: requested node (%s) does not exist" % node_name)
     else:
-        node = lib.pick_any_node_which_is_up (nodes)
+        node = lib.pick_any_node_which_is_up (c)
         vm_name = args.name
 
     # Get all the guests, so we can tell if the name is a duplicate.
-    running, inactive = lib.get_all_guests (c, nodes.values ())
+    running, inactive = lib.get_all_guests (c)
 
     if vm_name in running or vm_name in inactive:
         sys.exit ("error: node name (%s) already exists" % vm_name)
@@ -106,5 +99,5 @@ def run (c, args, nodes):
     fp.close ()
 
     # Start the guest.
-    lib.start_guest (c, node, vm_name)
-    print "guest imported and started on node %s" % node.name
+    lib.start_guest (c, node_name, vm_name)
+    print "guest imported and started on node %s" % node_name
index d3bbe7f..1ddd445 100644 (file)
@@ -36,7 +36,7 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
+def run (c, args):
     show_running = True
     show_inactive = True
     if not args.running or not args.inactive:
@@ -47,14 +47,13 @@ def run (c, args, nodes):
             show_running = False
             show_inactive = True
 
-    running, inactive = lib.get_all_guests (c, nodes.values ())
+    running, inactive = lib.get_all_guests (c)
 
     if show_running:
         for guest in running.values():
-            node_name = guest['node'].name
-            dom_name = guest['dom'].name()
-            dom_state = lib.pretty_run_status (guest['dom'].state()[0])
-            print "%s:%s\t%s" % (node_name, dom_name, dom_state)
+            node_name = guest['node']
+            dom_name = guest['vm']
+            print "%s:%s\trunning" % (node_name, dom_name)
 
     if show_inactive:
         for name in inactive.values():
index 33e2ae6..36ba398 100644 (file)
@@ -39,19 +39,19 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
-    running, _ = lib.get_all_guests (c, nodes.values ())
+def run (c, args):
+    running, _ = lib.get_all_guests (c)
 
     # Identify the VMs to be migrated.
     migrate_vms = []
     for vm in running.values():
-        node = vm['node']
-        dom = vm['dom']
+        node_name = vm['node']
+        vm_name = vm['vm']
         # Form the name of this VM (eg. "ham0:vm") so we can match it
         # against the wildcards (eg. "ham0:*")
-        name = node.name + ":" + dom.name()
+        name = node_name + ":" + vm_name
         for wc in args.wildcards:
-            if fnmatch.fnmatch (name, wc) or fnmatch.fnmatch (dom.name(), wc):
+            if fnmatch.fnmatch (name, wc) or fnmatch.fnmatch (vm_name, wc):
                 migrate_vms.append (vm)
 
     if not migrate_vms:
@@ -60,17 +60,18 @@ def run (c, args, nodes):
     # Get destination node.  It can be written either 'dest' or 'dest:'
     m = re.match (r'(.*):$', args.dest)
     if m:
-        args.dest = m.group (1)
+        dest = m.group (1)
+    else:
+        dest = args.dest
 
-    if args.dest not in nodes:
-        sys.exit ("error: destination node (%s) does not exist" % args.dest)
-    dest = nodes[args.dest]
-
-    dconn = libvirt.open (dest.uri)
+    dconn = libvirt.open (lib.uri_of_node (dest))
     if dconn == None:
-        sys.exit ("error: could not open a libvirt connection to %s (URI: %s)" %
-                  (dest.host, dest.uri))
+        sys.exit ("error: could not open a libvirt connection to %s" % dest)
 
     for vm in migrate_vms:
-        dom = vm['dom']
+        sconn = libvirt.open (lib.uri_of_node (vm['node']))
+        if sconn == None:
+            sys.exit ("error: could not open a libvirt connection to %s" %
+                      vm['node'])
+        dom = sconn.lookupByName (vm['vm'])
         dom.migrate (dconn, libvirt.VIR_MIGRATE_LIVE)
index 10ae06a..3851545 100644 (file)
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-import sys
+import argparse
 import os
 import subprocess
+import sys
+import time
+
+import ansible.inventory
+import ansible.runner
 
-import argparse
 import lib
 
 def cmdline (subparsers):
@@ -29,38 +33,47 @@ def cmdline (subparsers):
         help='power off a node (or nodes)'
     )
     p.add_argument (
-        '--all', action='store_const', const=True,
-        help='power off all nodes'
-    )
-    p.add_argument (
-        'nodes', nargs='*',
-        help='node name to be powered off'
+        'wildcard',
+        help='node name(s) to be powered off (wildcard may be used)'
     )
     p.set_defaults (run=run)
 
-def run (c, args, all_nodes):
-    nodes = lib.get_nodes_by_name (all_nodes, args.nodes, args.all)
+def run (c, args):
+    inventory = ansible.inventory.Inventory ()
+    inventory.subset (subset_pattern = args.wildcard)
+    nodes = inventory.get_hosts (c['nodes_group'])
 
     # Check the nodes have no guests.
+    running, _ = lib.get_all_guests (c)
     for node in nodes:
-        guests = node.guests ()
-        if guests != []:
-            names = map (lambda x : x.name(), guests)
-            sys.exit ("error: node %s has running guests %s, migrate them off or stop them first" % (node.name, names))
+        for vm in running.values():
+            if vm['node'] == node.name:
+                sys.exit ("error: node %s has running guests, migrate them off or stop them first" % node.name)
 
     # Power them off.
-    up = 0
-    for node in nodes:
-        if node.ping (force=True):
-            node.shutdown ()
-            up += 1
+    runner = ansible.runner.Runner (
+        remote_user = 'root',
+        module_name = 'command',
+        module_args = '/sbin/poweroff',
+        inventory = inventory,
+        pattern = c['nodes_group'],
+    )
+    data = runner.run ()
 
+    # Wait for them to power off.
     pings = 60
-    while pings > 0 and up > 0:
-        if not node.up:
-            if not node.ping (force=True):
-                up -= 1
+    runner = ansible.runner.Runner (
+        remote_user = 'root',
+        module_name = 'ping',
+        inventory = inventory,
+        pattern = c['nodes_group'],
+    )
+    while pings > 0:
+        data = runner.run ()
+        if len (data['contacted']) == 0:
+            break
         pings -= 1
+        time.sleep (1)
 
     if pings == 0:
         sys.exit ('warning: some nodes did not power off')
index 31ff86c..7183f93 100644 (file)
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-import sys
+import argparse
 import os
+import sys
+import time
 import subprocess
 
-import argparse
+import ansible.inventory
+import ansible.runner
+
+import config
 import lib
 
 def cmdline (subparsers):
@@ -29,34 +34,40 @@ def cmdline (subparsers):
         help='power on a node (or nodes)'
     )
     p.add_argument (
-        '--all', action='store_const', const=True,
-        help='wake up all nodes'
-    )
-    p.add_argument (
-        'nodes', nargs='*',
-        help='node name to be woken up'
+        'wildcard',
+        help='node name(s) to be woken up (wildcard may be used)'
     )
     p.set_defaults (run=run)
 
-def run (c, args, all_nodes):
-    nodes = lib.get_nodes_by_name (all_nodes, args.nodes, args.all)
+def run (c, args):
+    inventory = ansible.inventory.Inventory ()
+    inventory.subset (subset_pattern = args.wildcard)
+    nodes = inventory.get_hosts (c['nodes_group'])
 
     # Wake them up.
-    up = 0
     for node in nodes:
-        if node.ping (force=True):
-            up += 1
+        vars = node.get_variables()
+        if 'mac' in vars:
+            devnull = open (os.devnull, "w")
+            subprocess.check_call ([config.WOL, vars['mac']],
+                                   stdout = devnull, stderr = devnull)
         else:
-            node.wake()
+            print "warning: no mac= line in ansible hosts file for %s (ignored)" % node.name
 
     # Wait for them to come up.
     pings = 30
-    while pings > 0 and up < len (nodes):
-        for node in nodes:
-            if not node.up:
-                if node.ping (force=True):
-                    up += 1
+    runner = ansible.runner.Runner (
+        remote_user = 'root',
+        module_name = 'ping',
+        inventory = inventory,
+        pattern = c['nodes_group'],
+    )
+    while pings > 0:
+        data = runner.run ()
+        if len (data['dark']) == 0:
+            break
         pings -= 1
+        time.sleep (1)
 
     if pings == 0:
         sys.exit ('warning: some nodes did not wake up')
index c8eddf5..07917d1 100644 (file)
@@ -18,6 +18,8 @@
 
 import argparse
 import fnmatch
+import subprocess
+
 import libvirt
 
 import lib
@@ -37,18 +39,22 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
-    running, _ = lib.get_all_guests (c, nodes.values ())
+def run (c, args):
+    running, _ = lib.get_all_guests (c)
 
     for vm in running.values():
-        node = vm['node']
-        dom = vm['dom']
+        node_name = vm['node']
+        vm_name = vm['vm']
         # Form the name of this VM (eg. "ham0:vm") so we can match it
         # against the wildcards (eg. "ham0:*")
-        name = node.name + ":" + dom.name()
+        name = node_name + ":" + vm_name
         for wc in args.wildcards:
-            if fnmatch.fnmatch (name, wc) or fnmatch.fnmatch (dom.name(), wc):
+            if fnmatch.fnmatch (name, wc) or fnmatch.fnmatch (vm_name, wc):
                 if args.force:
-                    dom.reset(0)
+                    subprocess.check_call (["virsh",
+                                            "-c", lib.uri_of_node (node_name),
+                                            "reset", vm_name])
                 else:
-                    dom.reboot(0)
+                    subprocess.check_call (["virsh",
+                                            "-c", lib.uri_of_node (node_name),
+                                            "reboot", vm_name])
index 50d58c9..01a2f1a 100644 (file)
@@ -41,8 +41,8 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
-    _, inactive = lib.get_all_guests (c, nodes.values ())
+def run (c, args):
+    _, inactive = lib.get_all_guests (c)
 
     # User supplied a list of node:VMs.
     for a in args.vms:
@@ -50,20 +50,18 @@ def run (c, args, nodes):
         if m:
             node_name = m.group (1)
             wc = m.group (2)
-            if node_name not in nodes:
-                sys.exit ("error: node %s does not exist" % node_name)
-            node = nodes[node_name]
         else:
             wc = a
-            node = lib.pick_any_node_which_is_up (nodes)
+            node_name = lib.pick_any_node_which_is_up (c)
         started = []
         for vm_name in inactive:
             if fnmatch.fnmatch (vm_name, wc):
                 if args.viewer:
-                    subprocess.Popen ([config.VIRT_VIEWER, "-c",
-                                       node.uri, vm_name],
+                    subprocess.Popen ([config.VIRT_VIEWER,
+                                       "-c", lib.uri_of_node (node_name),
+                                       vm_name],
                                       close_fds=True)
-                lib.start_guest (c, node, vm_name)
+                lib.start_guest (c, node_name, vm_name)
                 started.append (vm_name)
 
         if not started:
index 81b9fb0..add55ab 100644 (file)
@@ -18,6 +18,8 @@
 
 import argparse
 
+import ansible.runner
+
 import lib
 
 def cmdline (subparsers):
@@ -27,19 +29,14 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
-    for node_name in sorted (nodes.keys ()):
-        node = nodes[node_name]
-        print "%s (%s)" % (node_name, node.host),
-        if node.ping():
-            print "\tup",
-            if node.ssh_ping():
-                print "\tssh: OK",
-                if node.libvirt_ping():
-                    print "\tlibvirt: OK"
-                else:
-                    print "\tlibvirt: dead"
-            else:
-                print "\tssh: dead"
-        else:
-            print "\tdown"
+def run (c, args):
+    runner = ansible.runner.Runner (
+        remote_user = 'root',
+        module_name = 'ping',
+        pattern = c['nodes_group'],
+    )
+    data = runner.run ()
+    for name in sorted (data['contacted']):
+        print "%s\tup" % name
+    for name in sorted (data['dark']):
+        print "%s\tdown" % name
index bd7f116..883b67a 100644 (file)
@@ -18,6 +18,8 @@
 
 import argparse
 import fnmatch
+import subprocess
+
 import libvirt
 
 import lib
@@ -37,18 +39,22 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
-    running, _ = lib.get_all_guests (c, nodes.values ())
+def run (c, args):
+    running, _ = lib.get_all_guests (c)
 
     for vm in running.values():
-        node = vm['node']
-        dom = vm['dom']
+        node_name = vm['node']
+        vm_name = vm['vm']
         # Form the name of this VM (eg. "ham0:vm") so we can match it
         # against the wildcards (eg. "ham0:*")
-        name = node.name + ":" + dom.name()
+        name = node_name + ":" + vm_name
         for wc in args.wildcards:
-            if fnmatch.fnmatch (name, wc) or fnmatch.fnmatch (dom.name(), wc):
+            if fnmatch.fnmatch (name, wc) or fnmatch.fnmatch (vm_name, wc):
                 if args.force:
-                    dom.destroy()
+                    subprocess.check_call (["virsh",
+                                            "-c", lib.uri_of_node (node_name),
+                                            "destroy", vm_name])
                 else:
-                    dom.shutdown()
+                    subprocess.check_call (["virsh",
+                                            "-c", lib.uri_of_node (node_name),
+                                            "shutdown", vm_name])
index 66cb5e6..7c4018b 100644 (file)
@@ -35,28 +35,30 @@ def cmdline (subparsers):
     )
     p.set_defaults (run=run)
 
-def run (c, args, nodes):
-    running, _ = lib.get_all_guests (c, nodes.values ())
+def run (c, args):
+    running, _ = lib.get_all_guests (c)
 
     m = re.match (r'^(.*):(.*)$', args.vm)
-    node_name = None
     if m:
         # We don't actually care about the node, but we check it
         # is the expected one below.
-        node_name = m.group (1)
+        node_name_check = m.group (1)
         vm_name = m.group (2)
     else:
+        node_name_check = None
         vm_name = args.vm
 
     if vm_name not in running:
         sys.exit ("error: vm %s not found or not running" % vm_name)
 
-    dom = running[vm_name]['dom']
-    node = running[vm_name]['node']
+    vm = running[vm_name]['vm']
+    node_name = running[vm_name]['node']
 
-    if node_name and node.name != node_name:
+    if node_name_check and node_name != node_name_check:
         sys.exit ("error: vm %s is not running on node %s, did you mean %s:%s ?" %
-                  (vm_name, node_name, node.name, vm_name))
+                  (vm_name, node_name_check, node_name, vm_name))
 
     # Run the virsh console command.
-    subprocess.call ([config.VIRT_VIEWER, "-c", node.uri, vm_name])
+    subprocess.call ([config.VIRT_VIEWER,
+                      "-c", lib.uri_of_node (node_name),
+                      vm_name])