code to load-balance boots among hosts
authorGreg Price <price@mit.edu>
Sun, 29 Jun 2008 03:28:08 +0000 (23:28 -0400)
committerGreg Price <price@mit.edu>
Sun, 29 Jun 2008 03:28:08 +0000 (23:28 -0400)
svn path=/trunk/packages/sipb-xen-remote-server/; revision=658

files/usr/sbin/sipb-xen-remote-create [new file with mode: 0755]

diff --git a/files/usr/sbin/sipb-xen-remote-create b/files/usr/sbin/sipb-xen-remote-create
new file mode 100755 (executable)
index 0000000..c4a62cc
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+"""
+Picks a host to "create" (boot) a VM on, and does so.
+
+For now, a very dumb algorithm for which host to boot on:
+the one with fewer machines running.
+
+TODO: load-balance based on something like actual free RAM
+
+TODO: use a lock to avoid creating the same VM twice in a race
+"""
+
+
+from subprocess import PIPE, Popen, call
+import sys
+import yaml
+
+
+def choose_host():
+    # Query each of the hosts.
+    # TODO get `servers` from a real list of all the VM hosts (instead of
+    # hardcoding the list here)
+    servers = ['black-mesa.mit.edu', 'sx-blade-2.mit.edu']
+    pipes = [(server,
+              Popen(['remctl', server, 'remote', 'web', 'info'], stdout=PIPE))
+             for server in servers]
+    outputs = [(s, p.communicate()[0]) for (s, p) in pipes]
+    for (s, p) in pipes:
+        if p.returncode != 0:
+            raise RuntimeError("remctl to host %s returned non-zero exit status %d"
+                               % (s, p.returncode)) 
+    results = [(s, yaml.load(o, yaml.CSafeLoader)) for (s, o) in outputs]
+    # XXX will the output of 'xm info' always be parseable YAML?
+
+    return max( (int(o['free_memory']), s) for (s, o) in results )[1]
+
+
+def main(argv):
+    if len(argv) < 2:
+        print >>sys.stderr, "usage: sipb-xen-remote-create <machine> [<other args...>]"
+        return 2
+    machine_name = argv[1]
+    args = argv[2:]
+
+
+    p = Popen(['/usr/sbin/sipb-xen-remote-proxy-web', 'listvms'], stdout=PIPE)
+    output = p.communicate()[0]
+    if p.returncode != 0:
+        raise RuntimeError("Command '%s' returned non-zero exit status %d"
+                           % ('sipb-xen-remote-proxy-web', p.returncode)) 
+    vms = yaml.load(output, yaml.CSafeLoader)
+
+    if machine_name in vms:
+        host = vms[machine_name]['host']
+        print >>sys.stderr, ("machine '%s' is already running on host %s"
+                             % (machine_name, host))
+        return 1
+
+
+    host = choose_host()
+    print 'Creating on host %s...' % host
+    return call(['remctl', host, 'remote', 'control',
+                 machine_name, 'create'] + args)
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
+
+# vim:et:sw=4:ts=4