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