shebags mention python2 explicitly
[bootmanager.git] / source / steps / CheckForNewDisks.py
1 #!/usr/bin/python2
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 as var:
49         raise BootManagerException("Missing variable in vars: {}\n".format(var))
50     except ValueError as var:
51         raise BootManagerException("Variable in vars, shouldn't be: {}\n".format(var))
52
53     devices_dict = systeminfo.get_block_devices_dict(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     utils.display_disks_status(PARTITIONS, "In CheckForNewDisks", log)
62
63     for device, details in devices_dict.items():
64
65         (major, minor, blocks, gb_size, readonly) = details
66
67         if device[:14] == "/dev/planetlab":
68             log.write("Skipping device {} in volume group.\n".format(device))
69             continue
70
71         if readonly:
72             log.write("Skipping read only device {}\n".format(device))
73             continue
74
75         if gb_size < MINIMUM_DISK_SIZE:
76             log.write("Skipping too small device {} ({:4.2f}) Gb\n"\
77                       .format(device, gb_size))
78             continue
79
80         log.write("Checking device {} to see if it is part " \
81                    "of the volume group.\n".format(device))
82
83         # Thierry - June 2015
84         # when introducing the 'upgrade' verb, we ran into the situation
85         # where 'pvdisplay' at this point displays e.g. /dev/sda, instead
86         # of /dev/sda1
87         # we thus consider that if either of these is known, then
88         # the disk is already part of LVM
89         first_partition = InstallPartitionDisks.get_partition_path_from_device(device, vars, log)
90         probe_first_part = "pvdisplay {} | grep -q planetlab".format(first_partition)
91         probe_device     = "pvdisplay {} | grep -q planetlab".format(device)
92         already_added = utils.sysexec_noerr(probe_first_part, log, shell=True) \
93                      or utils.sysexec_noerr(probe_device, log, shell=True) 
94
95         if already_added:
96             log.write("It appears {} is part of the volume group, continuing.\n"\
97                       .format(device))
98             continue
99
100         # just to be extra paranoid, ignore the device if it already has
101         # an lvm partition on it (new disks won't have this, and that is
102         # what this code is for, so it should be ok).
103         cmd = "parted --script --list {} | grep -q lvm$".format(device)
104         has_lvm = utils.sysexec_noerr(cmd, log, shell=True)
105         if has_lvm:
106             log.write("It appears {} has lvm already setup on it.\n".format(device))
107             paranoid = False
108             if paranoid:
109                 log.write("Too paranoid to add {} to vservers lvm.\n".format(device))
110                 continue
111         
112         if not InstallPartitionDisks.single_partition_device(device, vars, log):
113             log.write("Unable to partition {}, not using it.\n".format(device))
114             continue
115
116         log.write("Successfully partitioned {}\n".format(device))
117
118         if NODE_MODEL_OPTIONS & ModelOptions.RAWDISK:
119             log.write("Running on a raw disk node, not using it.\n")
120             continue
121
122         part_path = InstallPartitionDisks.get_partition_path_from_device(device,
123                                                                          vars, log)
124
125         log.write("Attempting to add {} to the volume group\n".format(device))
126
127         if not InstallPartitionDisks.create_lvm_physical_volume(part_path,
128                                                                  vars, log):
129             log.write("Unable to create lvm physical volume {}, not using it.\n"\
130                       .format(part_path))
131             continue
132
133         log.write("Adding {} to list of devices to add to "
134                    "planetlab volume group.\n".format(device))
135
136         extended_gb_size = extended_gb_size + gb_size
137         new_devices.append(part_path)
138         
139
140     if len(new_devices) > 0:
141
142         log.write("Extending planetlab volume group.\n")
143         
144         log.write("Unmounting disks.\n")
145         try:
146             # backwards compat, though, we should never hit this case post PL 3.2
147             os.stat("{}/rcfs/taskclass".format(SYSIMG_PATH))
148             utils.sysexec_chroot_noerr(SYSIMG_PATH, "umount /rcfs", log)
149         except OSError as e:
150             pass
151
152         # umount in order to extend disk size
153         utils.sysexec_noerr("umount {}/proc".format(SYSIMG_PATH), log)
154         utils.sysexec_noerr("umount {}/vservers".format(SYSIMG_PATH), log)
155         utils.sysexec_noerr("umount {}".format(SYSIMG_PATH), log)
156         utils.sysexec("vgchange -an", log)
157         
158         vars['ROOT_MOUNTED'] = 0
159
160         while True:
161             cmd = "vgextend planetlab {}".format(" ".join(new_devices))
162             if not utils.sysexec_noerr(cmd, log):
163                 log.write("Failed to add physical volumes {} to "\
164                            "volume group, continuing.\n".format(" ".join(new_devices)))
165                 res = 1
166                 break
167             
168             # now, get the number of unused extents, and extend the vserver
169             # logical volume by that much.
170             remaining_extents = \
171                InstallPartitionDisks.get_remaining_extents_on_vg(vars, log)
172
173             log.write("Extending vservers logical volume.\n")
174             utils.sysexec("vgchange -ay", log)
175             cmd = "lvextend -l +{} {}".format(remaining_extents, PARTITIONS["vservers"])
176             if not utils.sysexec_noerr(cmd, log):
177                 log.write("Failed to extend vservers logical volume, continuing\n")
178                 res = 1
179                 break
180
181             log.write("making the ext filesystem match new logical volume size.\n")
182
183             vars['ROOT_MOUNTED'] = 1
184             cmd = "mount {} {}".format(PARTITIONS["root"], SYSIMG_PATH)
185             utils.sysexec_noerr(cmd, log)
186             cmd = "mount {} {}/vservers".format(PARTITIONS["vservers"], SYSIMG_PATH)
187             utils.sysexec_noerr(cmd, log)
188             cmd = "resize2fs {}".format(PARTITIONS["vservers"])
189             resize = utils.sysexec_noerr(cmd,log)
190             utils.sysexec_noerr("umount {}/vservers".format(SYSIMG_PATH), log)
191             utils.sysexec_noerr("umount {}".format(SYSIMG_PATH), log)
192             vars['ROOT_MOUNTED'] = 0
193
194             utils.sysexec("vgchange -an", log)
195
196             if not resize:
197                 log.write("Failed to resize vservers partition, continuing.\n")
198                 res = 1
199                 break
200             else:
201                 log.write("Extended vservers partition by {:4.2f} Gb\n"\
202                           .format(extended_gb_size))
203                 res = 1
204                 break
205
206     else:
207         log.write("No new disk devices to add to volume group.\n")
208         res = 1
209
210     return res