Make invirt-lvm lvcreate-all use sqlalchemy correctly.
[invirt/packages/invirt-remote.git] / host / usr / sbin / invirt-lvm
1 #!/usr/bin/env python
2
3 import sys
4 import time
5 import os
6 import random
7 import string
8 from subprocess import call, PIPE, Popen
9 from invirt.config import structs as config
10
11 def check(b):
12     if not b:
13         exit(1)
14
15 vg = "xenvg"
16 prefix = "d_"
17
18 subcommand = sys.argv[1]
19
20 def ensureoff(machine):
21     # Make sure the machine is off, but we don't care about errors if it is already off.
22     rv = call(["/usr/sbin/xm", "destroy", prefix + machine],
23               stderr=PIPE)
24
25 machine_specific = subcommand not in ['lvcreate-all', 'vgcapacity']
26
27 if machine_specific:
28     machine = sys.argv[2]
29     disk = sys.argv[3]
30     lvname = prefix + machine + "_" + disk
31     lvpath = "/dev/" + vg + "/" + lvname
32
33 if subcommand == "lvcreate-all":
34     from invirt.database import models, connect
35     import re
36     connect()
37     for d in models.Disk.query().all():
38         check(re.match('^[A-Za-z0-9]+$', d.guest_device_name))
39         machine = models.Machine.query().filter_by(machine_id=d.machine_id).one()
40         check(re.match('^[A-Za-z0-9][A-Za-z0-9._-]*$', machine.name))
41         lvname = prefix + machine.name + "_" + d.guest_device_name
42         if not os.path.exists("/dev/%s/%s" % (vg, lvname)):
43             # LV doesn't exist
44             print >>sys.stderr, "Creating LV %s..." % (lvname,)
45             rv = call(["/sbin/lvcreate", "-L", str(d.size) + "M", "-n", lvname, vg])
46             if rv != 0:
47                 print >>sys.stderr, "Error creating LV %s\n" %(lvname,)
48                 sys.exit(1)
49 elif subcommand == "lvremove":
50     def error():
51         print >>sys.stderr, "Error removing LV %s\n" % lvname
52         sys.exit(1)
53     
54     # Rename the LV to something else so we can wipe it before reusing
55     # the space
56     while True:
57         new_lvname = "old_%s_%s" % (lvname, ''.join(random.choice(string.ascii_letters) for i in xrange(6)))
58         new_lvpath = "/dev/%s/%s" % (vg, new_lvname)
59         p = Popen(["/sbin/lvrename", lvpath, new_lvpath], stdout=PIPE, stderr=PIPE)
60         rv = p.wait()
61         if rv == 5 and 'already exists in volume group' in p.stderr.read():
62             continue
63         elif rv != 0:
64             error()
65         else:
66             break
67     ensureoff(machine)
68     
69     # Touch a file corresponding to the new name of the LV; a separate
70     # daemon will handle wiping and deleting it.
71     open(os.path.join('/var/lib/invirt-remote/cleanup', new_lvname), 'w')
72 elif subcommand == "lvresize":
73     size = sys.argv[4]
74     ensureoff(machine)
75     p = Popen(["/sbin/lvresize", "-L", size + "M", lvpath],
76               stdin=PIPE, stderr=PIPE)
77     print >> p.stdin, 'y'
78     err = p.stderr.read()
79     if p.wait() != 0 and 'matches existing size' not in err:
80         print >> sys.stderr, "Error resizing LV %s:\n" %(lvname,)
81         print >> sys.stderr, err
82         sys.exit(1)
83     print >> sys.stderr, err
84 elif subcommand == "lvrename":
85     newmachine = sys.argv[4]
86     newlvname = prefix + newmachine + "_" + disk
87     ensureoff(machine)
88     ensureoff(newmachine)    
89     rv = call(["/sbin/lvrename", vg, lvname, newlvname])
90     if rv != 0:
91         print >>sys.stderr, "Error renaming LV %s\n" %(lvname,)
92         sys.exit(1)
93 elif subcommand == "lvcreate":
94     size = sys.argv[4]
95     rv = call(["/sbin/lvcreate", "-L", size + "M", "-n", lvname, vg])
96     if rv != 0:
97         print >>sys.stderr, "Error creating LV %s\n" %(lvname,)
98         sys.exit(1)
99 elif subcommand == "vgcapacity":
100     p = Popen(["/sbin/vgs", "-o", "vg_extent_size,vg_extent_count,vg_free_count", 
101                             "--noheadings", "--units", "k", "--nosuffix", "--separator", ":", 
102                             vg],
103               stdout=PIPE, stderr=PIPE)
104     out,err = p.communicate()
105     
106     try:
107         fields = out.strip().split(':')
108         extent_size = float(fields[0]) # in kibibytes
109         extent_count = int(fields[1])
110         free_count = int(fields[2])
111         total_space_TiB = extent_size * extent_count / 1024.**3
112         free_space_TiB = extent_size * free_count / 1024.**3
113         print >>sys.stdout, "Total: %.3f TiB" % (total_space_TiB,)
114         print >>sys.stdout, "Free: %.3f TiB" % (free_space_TiB,)
115     except:
116         print >>sys.stderr, "Error obtaining vg capacity:\n%s\n" % (err,)
117         sys.exit(1)
118