In invirt-remote:
[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 if subcommand == "lvcreate-all":
26     from invirt import database
27     import re
28     database.connect()
29     for d in Disk.select():
30         check(re.match('^[A-Za-z0-9]+$', d.guest_device_name))
31         machine = Machine.get(d.machine_id)
32         check(re.match('^[A-Za-z0-9][A-Za-z0-9._-]*$', machine.name))
33         lvname = prefix + machine.name + "_" + d.guest_device_name
34         if not os.path.exists("/dev/%s/%s" % (vg, lvname)):
35             # LV doesn't exist
36             print >>sys.stderr, "Creating LV %s..." % (lvname,)
37             rv = call(["/sbin/lvcreate", "-L", str(d.size) + "M", "-n", lvname, vg])
38             if rv != 0:
39                 print >>sys.stderr, "Error creating LV %s\n" %(lvname,)
40                 sys.exit(1)
41 else:
42     machine = sys.argv[2]
43     disk = sys.argv[3]
44     lvname = prefix + machine + "_" + disk
45     lvpath = "/dev/" + vg + "/" + lvname
46 if subcommand == "lvremove":
47     def error():
48         print >>sys.stderr, "Error removing LV %s\n" % lvname
49         sys.exit(1)
50     
51     # Rename the LV to something else so we can wipe it before reusing
52     # the space
53     while True:
54         new_lvname = "old_%s_%s" % (lvname, ''.join(random.choice(string.ascii_letters) for i in xrange(6)))
55         new_lvpath = "/dev/%s/%s" % (vg, new_lvname)
56         p = Popen(["/sbin/lvrename", lvpath, new_lvpath], stdout=PIPE, stderr=PIPE)
57         rv = p.wait()
58         if rv == 5 and 'already exists in volume group' in p.stderr.read():
59             continue
60         elif rv != 0:
61             error()
62         else:
63             break
64     ensureoff(machine)
65     
66     # Fork. The child process wipes the LV and then deletes
67     # it. There's not really anything sane to do with errors (since
68     # this is running non-interactively), so let's just drop them on
69     # the floor for now.
70     if os.fork() == 0:
71         call(["/usr/bin/ionice", "-c", "2", "-n", "7", "/bin/dd", "if=/dev/zero", "of=%s" % new_lvpath])
72         call(["/sbin/lvchange", "-a", "n", new_lvpath])
73         call(["/sbin/lvchange", "-a", "ey", new_lvpath])
74         call(["/sbin/lvremove", "--force", new_lvpath])
75 elif subcommand == "lvresize":
76     size = sys.argv[4]
77     ensureoff(machine)
78     p = Popen(["/sbin/lvresize", "-L", size + "M", lvpath],
79               stdin=PIPE, stderr=PIPE)
80     print >> p.stdin, 'y'
81     err = p.stderr.read()
82     if p.wait() != 0 and 'matches existing size' not in err:
83         print >> sys.stderr, "Error resizing LV %s:\n" %(lvname,)
84         print >> sys.stderr, err
85         sys.exit(1)
86     print >> sys.stderr, err
87 elif subcommand == "lvrename":
88     newmachine = sys.argv[4]
89     newlvname = prefix + newmachine + "_" + disk
90     ensureoff(machine)
91     ensureoff(newmachine)    
92     rv = call(["/sbin/lvrename", vg, lvname, newlvname])
93     if rv != 0:
94         print >>sys.stderr, "Error renaming LV %s\n" %(lvname,)
95         sys.exit(1)
96 elif subcommand == "lvcreate":
97     size = sys.argv[4]
98     rv = call(["/sbin/lvcreate", "-L", size + "M", "-n", lvname, vg])
99     if rv != 0:
100         print >>sys.stderr, "Error creating LV %s\n" %(lvname,)
101         sys.exit(1)
102