Merge invirt-remote-host and invirt-remote-server into invirt-remote
[invirt/packages/invirt-remote.git] / server / usr / sbin / invirt-remote-create
diff --git a/server/usr/sbin/invirt-remote-create b/server/usr/sbin/invirt-remote-create
new file mode 100755 (executable)
index 0000000..0a95d35
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+
+"""
+Picks a host to "create" (boot) a VM on, and does so.
+
+Current load-balancing algorithm: wherever there's more free RAM.
+
+TODO: use a lock to avoid creating the same VM twice in a race
+"""
+
+from invirt.remote import bcast
+from subprocess import PIPE, Popen, call
+import sys
+import yaml
+
+def choose_host():
+    # Query each of the hosts.
+    # XXX will the output of 'xm info' always be parseable YAML?
+    results = bcast('info')
+    return max((int(o['max_free_memory']), s) for (s, o) in results)[1]
+
+def main(argv):
+    if len(argv) < 3:
+        print >> sys.stderr, "usage: invirt-remote-create <operation> <machine> [<other args...>]"
+        return 2
+    operation = argv[1]
+    machine_name = argv[2]
+    args = argv[3:]
+    
+    if operation == 'install':
+        options = dict(arg.split('=', 1) for arg in args)
+        valid_keys = set(('mirror', 'dist', 'arch', 'imagesize', 'noinstall'))
+        if not set(options.keys()).issubset(valid_keys):
+            print >> sys.stderr, "Invalid argument. Use the help command to see valid arguments to install"
+            return 1
+        if any(' ' in val for val in options.values()):
+            print >> sys.stderr, "Arguments to the autoinstaller cannot contain spaces"
+            return 1
+
+    p = Popen(['/usr/sbin/invirt-remote-proxy-web', 'listvms'], stdout=PIPE)
+    output = p.communicate()[0]
+    if p.returncode != 0:
+        raise RuntimeError("Command '%s' returned non-zero exit status %d"
+                           % ('invirt-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
+    sys.stdout.flush()
+    return call(['remctl', host, 'remote', 'control',
+                 machine_name, operation] + args)
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
+
+# vim:et:sw=4:ts=4