4483ce187d9141356f27efbd733bc9232444d022
[invirt/packages/invirt-remote.git] / files / usr / sbin / sipb-xen-remote-create
1 #!/usr/bin/python
2 """
3 Picks a host to "create" (boot) a VM on, and does so.
4
5 For now, a very dumb algorithm for which host to boot on:
6 the one with fewer machines running.
7
8 TODO: load-balance based on something like actual free RAM
9
10 TODO: use a lock to avoid creating the same VM twice in a race
11 """
12
13
14 from subprocess import PIPE, Popen, call
15 import sys
16 import yaml
17
18
19 def choose_host():
20     # Query each of the hosts.
21     # TODO get `servers` from a real list of all the VM hosts (instead of
22     # hardcoding the list here)
23     servers = ['black-mesa.mit.edu', 'sx-blade-2.mit.edu']
24     pipes = [(server,
25               Popen(['remctl', server, 'remote', 'web', 'info'], stdout=PIPE))
26              for server in servers]
27     outputs = [(s, p.communicate()[0]) for (s, p) in pipes]
28     for (s, p) in pipes:
29         if p.returncode != 0:
30             raise RuntimeError("remctl to host %s returned non-zero exit status %d"
31                                % (s, p.returncode)) 
32     results = [(s, yaml.load(o, yaml.CSafeLoader)) for (s, o) in outputs]
33     # XXX will the output of 'xm info' always be parseable YAML?
34
35     return max( (int(o['free_memory']), s) for (s, o) in results )[1]
36
37
38 def main(argv):
39     if len(argv) < 2:
40         print >>sys.stderr, "usage: sipb-xen-remote-create <machine> [<other args...>]"
41         return 2
42     machine_name = argv[1]
43     args = argv[2:]
44
45
46     p = Popen(['/usr/sbin/sipb-xen-remote-proxy-web', 'listvms'], stdout=PIPE)
47     output = p.communicate()[0]
48     if p.returncode != 0:
49         raise RuntimeError("Command '%s' returned non-zero exit status %d"
50                            % ('sipb-xen-remote-proxy-web', p.returncode)) 
51     vms = yaml.load(output, yaml.CSafeLoader)
52
53     if machine_name in vms:
54         host = vms[machine_name]['host']
55         print >>sys.stderr, ("machine '%s' is already running on host %s"
56                              % (machine_name, host))
57         return 1
58
59
60     host = choose_host()
61     print 'Creating on host %s...' % host
62     sys.stdout.flush()
63     return call(['remctl', host, 'remote', 'control',
64                  machine_name, 'create'] + args)
65
66 if __name__ == '__main__':
67     sys.exit(main(sys.argv))
68
69 # vim:et:sw=4:ts=4