36 |
36 |
usually not get these errors, but if we do it's most probably a system
|
37 |
37 |
error, so they should be handled and the user instructed to report
|
38 |
38 |
them.
|
|
39 |
|
39 |
40 |
"""
|
40 |
41 |
|
41 |
42 |
|
... | ... | |
66 |
67 |
|
67 |
68 |
This should catch sysfs tree changes, or otherwise incorrect
|
68 |
69 |
assumptions about the contents of the /sys/block/... directories.
|
|
70 |
|
69 |
71 |
"""
|
70 |
72 |
pass
|
71 |
73 |
|
... | ... | |
79 |
81 |
|
80 |
82 |
This should usually mean that the installation of the Xen node
|
81 |
83 |
failed in some steps.
|
|
84 |
|
82 |
85 |
"""
|
83 |
86 |
pass
|
84 |
87 |
|
... | ... | |
92 |
95 |
|
93 |
96 |
This should usually mean that the build steps for the Xen node were
|
94 |
97 |
not followed correctly.
|
|
98 |
|
95 |
99 |
"""
|
96 |
100 |
pass
|
97 |
101 |
|
... | ... | |
100 |
104 |
"""Exception denoting actual errors.
|
101 |
105 |
|
102 |
106 |
Errors during the bootstrapping are signaled using this exception.
|
|
107 |
|
103 |
108 |
"""
|
104 |
109 |
pass
|
105 |
110 |
|
... | ... | |
109 |
114 |
|
110 |
115 |
Wrong disks given as parameters will be signaled using this
|
111 |
116 |
exception.
|
|
117 |
|
112 |
118 |
"""
|
113 |
119 |
pass
|
114 |
120 |
|
115 |
121 |
|
116 |
122 |
def Usage():
|
117 |
|
"""Shows program usage information and exits the program."""
|
|
123 |
"""Shows program usage information and exits the program.
|
118 |
124 |
|
|
125 |
"""
|
119 |
126 |
print >> sys.stderr, "Usage:"
|
120 |
127 |
print >> sys.stderr, USAGE
|
121 |
128 |
sys.exit(2)
|
... | ... | |
127 |
134 |
In case of command line errors, it will show the usage and exit the
|
128 |
135 |
program.
|
129 |
136 |
|
130 |
|
Returns:
|
131 |
|
(options, args), as returned by OptionParser.parse_args
|
|
137 |
@rtype: tuple
|
|
138 |
@return: a tuple of (options, args), as returned by
|
|
139 |
OptionParser.parse_args
|
|
140 |
|
132 |
141 |
"""
|
133 |
142 |
global verbose_flag # pylint: disable-msg=W0603
|
134 |
143 |
|
... | ... | |
167 |
176 |
difference that if the command line argument -v has been given, it
|
168 |
177 |
will print the command line and the command output on stdout.
|
169 |
178 |
|
170 |
|
Args:
|
171 |
|
the command line
|
172 |
|
Returns:
|
173 |
|
(status, output) where status is the exit status and output the
|
174 |
|
stdout and stderr of the command together
|
175 |
|
"""
|
|
179 |
@param command: the command line to be executed
|
|
180 |
@rtype: tuple
|
|
181 |
@return: a tuple of (status, output) where status is the exit status
|
|
182 |
and output the stdout and stderr of the command together
|
176 |
183 |
|
|
184 |
"""
|
177 |
185 |
if verbose_flag:
|
178 |
186 |
print command
|
179 |
187 |
result = RunCmd(command)
|
... | ... | |
187 |
195 |
|
188 |
196 |
It check that it runs on Linux 2.6, and that /sys is mounted and the
|
189 |
197 |
fact that /sys/block is a directory.
|
190 |
|
"""
|
191 |
198 |
|
|
199 |
"""
|
192 |
200 |
if os.getuid() != 0:
|
193 |
201 |
raise PrereqError("This tool runs as root only. Really.")
|
194 |
202 |
|
... | ... | |
220 |
228 |
def CheckVGExists(vgname):
|
221 |
229 |
"""Checks to see if a volume group exists.
|
222 |
230 |
|
223 |
|
Args:
|
224 |
|
vgname: the volume group name
|
|
231 |
@param vgname: the volume group name
|
225 |
232 |
|
226 |
|
Returns:
|
227 |
|
a four-tuple (exists, lv_count, vg_size, vg_free), where:
|
228 |
|
exists: True if the volume exists, otherwise False; if False,
|
|
233 |
@return: a four-tuple (exists, lv_count, vg_size, vg_free), where:
|
|
234 |
- exists: True if the volume exists, otherwise False; if False,
|
229 |
235 |
all other members of the tuple are None
|
230 |
|
lv_count: The number of logical volumes in the volume group
|
231 |
|
vg_size: The total size of the volume group (in gibibytes)
|
232 |
|
vg_free: The available space in the volume group
|
233 |
|
"""
|
|
236 |
- lv_count: The number of logical volumes in the volume group
|
|
237 |
- vg_size: The total size of the volume group (in gibibytes)
|
|
238 |
- vg_free: The available space in the volume group
|
234 |
239 |
|
|
240 |
"""
|
235 |
241 |
result = ExecCommand("vgs --nohead -o lv_count,vg_size,vg_free"
|
236 |
242 |
" --nosuffix --units g"
|
237 |
243 |
" --ignorelockingfailure %s" % vgname)
|
... | ... | |
261 |
267 |
some retries here. Since we only do a stat, we can afford to do many
|
262 |
268 |
short retries.
|
263 |
269 |
|
264 |
|
Args:
|
265 |
|
name: the device name, e.g. 'sda'
|
266 |
|
devnum: the device number, e.g. 0x803 (2051 in decimal) for sda3
|
|
270 |
@param name: the device name, e.g. 'sda'
|
|
271 |
@param devnum: the device number, e.g. 0x803 (2051 in decimal) for sda3
|
|
272 |
@raises L{SysconfigError}: in case of failure of the check
|
267 |
273 |
|
268 |
|
Returns:
|
269 |
|
None; failure of the check is signaled by raising a
|
270 |
|
SysconfigError exception
|
271 |
274 |
"""
|
272 |
|
|
273 |
275 |
path = "/dev/%s" % name
|
274 |
276 |
for _ in range(40):
|
275 |
277 |
if os.path.exists(path):
|
... | ... | |
293 |
295 |
function reads that file and converts the major:minor pair to a dev
|
294 |
296 |
number.
|
295 |
297 |
|
296 |
|
Args:
|
297 |
|
syspath: the path to a block device dir in sysfs, e.g. /sys/block/sda
|
|
298 |
@type syspath: string
|
|
299 |
@param syspath: the path to a block device dir in sysfs,
|
|
300 |
e.g. C{/sys/block/sda}
|
298 |
301 |
|
299 |
|
Returns:
|
300 |
|
the device number
|
301 |
|
"""
|
|
302 |
@return: the device number
|
302 |
303 |
|
|
304 |
"""
|
303 |
305 |
if not os.path.exists("%s/dev" % syspath):
|
304 |
306 |
raise ProgrammingError("Invalid path passed to ReadDev: %s" % syspath)
|
305 |
307 |
f = open("%s/dev" % syspath)
|
... | ... | |
320 |
322 |
function reads that file and converts the number in sectors to the
|
321 |
323 |
size in bytes.
|
322 |
324 |
|
323 |
|
Args:
|
324 |
|
syspath: the path to a block device dir in sysfs, e.g. /sys/block/sda
|
|
325 |
@type syspath: string
|
|
326 |
@param syspath: the path to a block device dir in sysfs,
|
|
327 |
e.g. C{/sys/block/sda}
|
|
328 |
|
|
329 |
@rtype: int
|
|
330 |
@return: the device size in bytes
|
325 |
331 |
|
326 |
|
Returns:
|
327 |
|
the device size in bytes
|
328 |
332 |
"""
|
329 |
333 |
|
330 |
334 |
if not os.path.exists("%s/size" % syspath):
|
... | ... | |
341 |
345 |
|
342 |
346 |
This function tries to see if a block device is a physical volume.
|
343 |
347 |
|
344 |
|
Args:
|
345 |
|
dev: the device name (e.g. sda)
|
346 |
|
Returns:
|
347 |
|
The name of the volume group to which this PV belongs, or
|
348 |
|
"" if this PV is not in use, or
|
349 |
|
None if this is not a PV
|
350 |
|
"""
|
|
348 |
@type name: string
|
|
349 |
@param name: the device name (e.g. sda)
|
|
350 |
|
|
351 |
@return: the name of the volume group to which this PV belongs, or
|
|
352 |
"" if this PV is not in use, or None if this is not a PV
|
351 |
353 |
|
|
354 |
"""
|
352 |
355 |
result = ExecCommand("pvdisplay -c /dev/%s" % name)
|
353 |
356 |
if result.failed:
|
354 |
357 |
return None
|
... | ... | |
362 |
365 |
This function examines the /sys/block tree and using information
|
363 |
366 |
therein, computes the status of the block device.
|
364 |
367 |
|
365 |
|
Returns:
|
366 |
|
[(name, size, dev, partitions, inuse), ...]
|
367 |
|
where:
|
368 |
|
name is the block device name (e.g. sda)
|
369 |
|
size the size in bytes
|
370 |
|
dev the device number (e.g. 8704 for hdg)
|
371 |
|
partitions is [(name, size, dev), ...] mirroring the disk list data
|
372 |
|
inuse is a boolean showing the in-use status of the disk, computed as the
|
373 |
|
possibility of re-reading the partition table (the meaning of the
|
374 |
|
operation varies with the kernel version, but is usually accurate;
|
375 |
|
a mounted disk/partition or swap-area or PV with active LVs on it
|
376 |
|
is busy)
|
377 |
|
"""
|
|
368 |
@return: a list like [(name, size, dev, partitions, inuse), ...], where:
|
|
369 |
- name is the block device name (e.g. sda)
|
|
370 |
- size the size in bytes
|
|
371 |
- dev is the device number (e.g. 8704 for hdg)
|
|
372 |
- partitions is [(name, size, dev), ...] mirroring the disk list
|
|
373 |
data inuse is a boolean showing the in-use status of the disk,
|
|
374 |
computed as the possibility of re-reading the partition table
|
|
375 |
(the meaning of the operation varies with the kernel version,
|
|
376 |
but is usually accurate; a mounted disk/partition or swap-area
|
|
377 |
or PV with active LVs on it is busy)
|
378 |
378 |
|
|
379 |
"""
|
379 |
380 |
dlist = []
|
380 |
381 |
for name in os.listdir("/sys/block"):
|
381 |
382 |
if (not name.startswith("hd") and
|
... | ... | |
419 |
420 |
of the results is memorised for later matching against the
|
420 |
421 |
/sys/block devices.
|
421 |
422 |
|
422 |
|
Returns:
|
423 |
|
a mountpoint: device number dictionary
|
424 |
|
"""
|
|
423 |
@rtype: dict
|
|
424 |
@return: a {mountpoint: device number} dictionary
|
425 |
425 |
|
|
426 |
"""
|
426 |
427 |
mountlines = ReadFile("/proc/mounts").splitlines()
|
427 |
428 |
mounts = {}
|
428 |
429 |
for line in mountlines:
|
... | ... | |
448 |
449 |
def DevInfo(name, dev, mountinfo):
|
449 |
450 |
"""Computes miscellaneous information about a block device.
|
450 |
451 |
|
451 |
|
Args:
|
452 |
|
name: the device name, e.g. sda
|
|
452 |
@type name: string
|
|
453 |
@param name: the device name, e.g. sda
|
453 |
454 |
|
454 |
|
Returns:
|
455 |
|
(mpath, whatvg, fileinfo), where
|
456 |
|
mpath is the mount path where this device is mounted or None
|
457 |
|
whatvg is the result of the ReadPV function
|
458 |
|
fileinfo is the output of file -bs on the device
|
459 |
|
"""
|
|
455 |
@return: a tuple (mpath, whatvg, fileinfo), where:
|
|
456 |
- mpath is the mount path where this device is mounted or None
|
|
457 |
- whatvg is the result of the ReadPV function
|
|
458 |
- fileinfo is the output of file -bs on the device
|
460 |
459 |
|
|
460 |
"""
|
461 |
461 |
if dev in mountinfo:
|
462 |
462 |
mpath = mountinfo[dev]
|
463 |
463 |
else:
|
... | ... | |
538 |
538 |
thus compute the in-use status. See the discussion in GetDiskList
|
539 |
539 |
about the meaning of 'in use'.
|
540 |
540 |
|
541 |
|
Returns:
|
542 |
|
boolean, the in-use status of the device
|
543 |
|
"""
|
|
541 |
@rtype: boolean
|
|
542 |
@return: the in-use status of the device
|
544 |
543 |
|
|
544 |
"""
|
545 |
545 |
for _ in range(3):
|
546 |
546 |
result = ExecCommand("blockdev --rereadpt /dev/%s" % name)
|
547 |
547 |
if not result.failed:
|
... | ... | |
558 |
558 |
partition table. If not successful, it writes back the old partition
|
559 |
559 |
data, and leaves the cleanup to the user.
|
560 |
560 |
|
561 |
|
Args:
|
562 |
|
the device name (e.g. sda)
|
|
561 |
@param name: the device name (e.g. sda)
|
|
562 |
|
563 |
563 |
"""
|
564 |
564 |
|
565 |
565 |
if not CheckReread(name):
|
... | ... | |
600 |
600 |
This function creates a single partition spanning the entire disk,
|
601 |
601 |
by means of fdisk.
|
602 |
602 |
|
603 |
|
Args:
|
604 |
|
the device name, e.g. sda
|
|
603 |
@param name: the device name, e.g. sda
|
|
604 |
|
605 |
605 |
"""
|
606 |
606 |
result = ExecCommand(
|
607 |
607 |
'echo ,,8e, | sfdisk /dev/%s' % name)
|
... | ... | |
620 |
620 |
This function creates a physical volume on a block device, overriding
|
621 |
621 |
all warnings. So it can wipe existing PVs and PVs which are in a VG.
|
622 |
622 |
|
623 |
|
Args:
|
624 |
|
the device name, e.g. sda
|
|
623 |
@param name: the device name, e.g. sda
|
625 |
624 |
|
626 |
625 |
"""
|
627 |
626 |
result = ExecCommand("pvcreate -yff /dev/%s1 " % name)
|
... | ... | |
638 |
637 |
This function creates a volume group named `vgname` on the disks
|
639 |
638 |
given as parameters. The physical extent size is set to 64MB.
|
640 |
639 |
|
641 |
|
Args:
|
642 |
|
disks: a list of disk names, e.g. ['sda','sdb']
|
|
640 |
@param disks: a list of disk names, e.g. ['sda','sdb']
|
643 |
641 |
|
644 |
642 |
"""
|
645 |
643 |
pnames = ["'/dev/%s1'" % disk for disk in disks]
|
... | ... | |
659 |
657 |
using the --disks option) such that all given disks are present and
|
660 |
658 |
not in use.
|
661 |
659 |
|
662 |
|
Args:
|
663 |
|
the options returned from OptParser.parse_options
|
|
660 |
@param options: the options returned from OptParser.parse_options
|
664 |
661 |
|
665 |
|
Returns:
|
666 |
|
a list of disk names, e.g. ['sda', 'sdb']
|
667 |
|
"""
|
|
662 |
@return: a list of disk names, e.g. ['sda', 'sdb']
|
668 |
663 |
|
|
664 |
"""
|
669 |
665 |
sysdisks = GetDiskList(options)
|
670 |
666 |
if not sysdisks:
|
671 |
667 |
raise PrereqError("no disks found (I looked for"
|
... | ... | |
697 |
693 |
|
698 |
694 |
|
699 |
695 |
def BootStrap():
|
700 |
|
"""Actual main routine."""
|
|
696 |
"""Actual main routine.
|
701 |
697 |
|
|
698 |
"""
|
702 |
699 |
CheckPrereq()
|
703 |
700 |
|
704 |
701 |
options, args = ParseOptions()
|
... | ... | |
736 |
733 |
|
737 |
734 |
|
738 |
735 |
def main():
|
739 |
|
"""application entry point.
|
|
736 |
"""Application entry point.
|
740 |
737 |
|
741 |
738 |
This is just a wrapper over BootStrap, to handle our own exceptions.
|
742 |
|
"""
|
743 |
739 |
|
|
740 |
"""
|
744 |
741 |
try:
|
745 |
742 |
BootStrap()
|
746 |
743 |
except PrereqError, err:
|