This reverts commit 69124f104991e36e254c0be4a5f8155609f1d3fe.
[bootmanager.git] / source / steps / CheckForNewDisks.py
1 #!/usr/bin/python
2 #
3 # $Id$
4 # $URL$
5 #
6 # Copyright (c) 2003 Intel Corporation
7 # All rights reserved.
8 #
9 # Copyright (c) 2004-2006 The Trustees of Princeton University
10 # All rights reserved.
11
12 import string
13
14 import InstallPartitionDisks
15 from Exceptions import *
16 import systeminfo
17 import utils
18 import os
19
20 import ModelOptions
21
22
23 def Run( vars, log ):
24     """
25     Find any new large block devices we can add to the vservers volume group
26     
27     Expect the following variables to be set:
28     SYSIMG_PATH          the path where the system image will be mounted
29     MINIMUM_DISK_SIZE       any disks smaller than this size, in GB, are not used
30     NODE_MODEL_OPTIONS   the node's model options
31     
32     Set the following variables upon successfully running:
33     ROOT_MOUNTED             the node root file system is mounted
34     """
35
36     log.write( "\n\nStep: Checking for unused disks to add to LVM.\n" )
37
38     # make sure we have the variables we need
39     try:
40         SYSIMG_PATH= vars["SYSIMG_PATH"]
41         if SYSIMG_PATH == "":
42             raise ValueError, "SYSIMG_PATH"
43
44         MINIMUM_DISK_SIZE= int(vars["MINIMUM_DISK_SIZE"])
45
46         PARTITIONS= vars["PARTITIONS"]
47         if PARTITIONS == None:
48             raise ValueError, "PARTITIONS"
49         
50         NODE_MODEL_OPTIONS= vars["NODE_MODEL_OPTIONS"]
51     except KeyError, var:
52         raise BootManagerException, "Missing variable in vars: %s\n" % var
53     except ValueError, var:
54         raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
55
56     all_devices= systeminfo.get_block_device_list(vars, log)
57     
58     # will contain the new devices to add to the volume group
59     new_devices= []
60
61     # total amount of new space in gb
62     extended_gb_size= 0
63     
64     for device in all_devices.keys():
65
66         (major,minor,blocks,gb_size,readonly)= all_devices[device]
67
68         if device[:14] == "/dev/planetlab":
69             log.write( "Skipping device %s in volume group.\n" % device )
70             continue
71
72         if readonly:
73             log.write( "Skipping read only device %s\n" % device )
74             continue
75
76         if gb_size < MINIMUM_DISK_SIZE:
77             log.write( "Skipping too small device %s (%4.2f)\n" %
78                        (device,gb_size) )
79             continue
80
81         log.write( "Checking device %s to see if it is part " \
82                    "of the volume group.\n" % device )
83
84         # this is the lvm partition, if it exists on that device
85         lvm_partition= InstallPartitionDisks.get_partition_path_from_device( device, vars, log )
86         cmd = "pvdisplay %s | grep -q 'planetlab'" % lvm_partition
87         already_added= utils.sysexec_noerr(cmd, log)
88
89         if already_added:
90             log.write( "It appears %s is part of the volume group, continuing.\n" %
91                        device )
92             continue
93
94         # just to be extra paranoid, ignore the device if it already has
95         # an lvm partition on it (new disks won't have this, and that is
96         # what this code is for, so it should be ok).
97         cmd = "sfdisk -l %s | grep -q 'Linux LVM'" % device 
98         has_lvm= utils.sysexec_noerr(cmd, log)
99         if has_lvm:
100             log.write( "It appears %s has lvm already setup on it.\n" % device)
101             paranoid = False
102             if paranoid:
103                 log.write("To paranoid to add %s to vservers lvm.\n" % device)
104                 continue
105         
106         if not InstallPartitionDisks.single_partition_device( device, vars, log ):
107             log.write( "Unable to partition %s, not using it.\n" % device )
108             continue
109
110         log.write( "Successfully partitioned %s\n" % device )
111
112         if NODE_MODEL_OPTIONS & ModelOptions.RAWDISK:
113             log.write( "Running on a raw disk node, not using it.\n" )
114             continue
115
116         part_path= InstallPartitionDisks.get_partition_path_from_device( device,
117                                                                          vars, log )
118
119         log.write( "Attempting to add %s to the volume group\n" % device )
120
121         if not InstallPartitionDisks.create_lvm_physical_volume( part_path,
122                                                                  vars, log ):
123             log.write( "Unable to create lvm physical volume %s, not using it.\n" %
124                        part_path )
125             continue
126
127         log.write( "Adding %s to list of devices to add to " \
128                    "planetlab volume group.\n" % device )
129
130         extended_gb_size= extended_gb_size + gb_size
131         new_devices.append( part_path )
132         
133
134     if len(new_devices) > 0:
135
136         log.write( "Extending planetlab volume group.\n" )
137         
138         log.write( "Unmounting disks.\n" )
139         try:
140             # backwards compat, though, we should never hit this case post PL 3.2
141             os.stat("%s/rcfs/taskclass"%SYSIMG_PATH)
142             utils.sysexec_chroot_noerr( SYSIMG_PATH, "umount /rcfs", log )
143         except OSError, e:
144             pass
145
146         # umount in order to extend disk size
147         utils.sysexec_noerr( "umount %s/proc" % SYSIMG_PATH, log )
148         utils.sysexec_noerr( "umount %s/vservers" % SYSIMG_PATH, log )
149         utils.sysexec_noerr( "umount %s" % SYSIMG_PATH, log )
150         utils.sysexec( "vgchange -an", log )
151         
152         vars['ROOT_MOUNTED']= 0
153
154         while True:
155             cmd = "vgextend planetlab %s" % string.join(new_devices," ")
156             if not utils.sysexec_noerr( cmd, log ):
157                 log.write( "Failed to add physical volumes %s to " \
158                            "volume group, continuing.\n" % string.join(new_devices," "))
159                 res = 1
160                 break
161             
162             # now, get the number of unused extents, and extend the vserver
163             # logical volume by that much.
164             remaining_extents= \
165                InstallPartitionDisks.get_remaining_extents_on_vg( vars, log )
166
167             log.write( "Extending vservers logical volume.\n" )
168             utils.sysexec( "vgchange -ay", log )
169             cmd = "lvextend -l +%s %s" % (remaining_extents, PARTITIONS["vservers"])
170             if not utils.sysexec_noerr(cmd, log):
171                 log.write( "Failed to extend vservers logical volume, continuing\n" )
172                 res = 1
173                 break
174
175             log.write( "making the ext filesystem match new logical volume size.\n" )
176
177             vars['ROOT_MOUNTED']= 1
178             cmd = "mount %s %s" % (PARTITIONS["root"],SYSIMG_PATH)
179             utils.sysexec_noerr( cmd, log )
180             cmd = "mount %s %s/vservers" % \
181                 (PARTITIONS["vservers"],SYSIMG_PATH)
182             utils.sysexec_noerr( cmd, log )
183             cmd = "ext2online %s/vservers" % SYSIMG_PATH
184             resize = utils.sysexec_noerr(cmd,log)
185             utils.sysexec_noerr( "umount %s/vservers" % SYSIMG_PATH, log )
186             utils.sysexec_noerr( "umount %s" % SYSIMG_PATH, log )
187             vars['ROOT_MOUNTED']= 0
188
189             utils.sysexec( "vgchange -an", log )
190
191             if not resize:
192                 log.write( "Failed to resize vservers partition, continuing.\n" )
193                 res = 1
194                 break
195             else:
196                 log.write( "Extended vservers partition by %4.2f GB\n" %
197                            extended_gb_size )
198                 res = 1
199                 break
200
201     else:
202         log.write( "No new disk devices to add to volume group.\n" )
203         res = 1
204
205     return res