#!/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 import invirt.database def maxMemory(owner, xmlist): """ Return the memory available for a new machine. """ machines = invirt.database.Machine.query().filter_by(owner=owner) (quota_total, quota_single) = invirt.database.Owner.getMemoryQuotas(owner) active_machines = [m for m in machines if m.name in xmlist] mem_usage = sum([x.memory for x in active_machines]) return min(quota_single, quota_total-mem_usage) def choose_host(): # Query each of the hosts. results = bcast('availability') return max((int(o), s) for (s, o) in results)[1] def main(argv): if len(argv) < 3: print >> sys.stderr, "usage: invirt-remote-create []" 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 if operation == "create": invirt.database.connect() machine = invirt.database.Machine.query().filter_by(name=machine_name).first() owner = machine.owner vm_memory = machine.memory max_memory = maxMemory(owner, vms.keys()) if vm_memory > max_memory: print >>sys.stderr, "owner %s requested %d MB of memory for vm %s; %d MB allowed" % (owner, vm_memory, machine_name, max_memory) 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