Statistics
| Branch: | Tag: | Revision:

root / tools / lvmstrap @ f2af0bec

History | View | Annotate | Download (25.4 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 577d45d4 Iustin Pop
# Copyright (C) 2006, 2007, 2011 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Program which configures LVM on the Ganeti nodes.
23 a8083063 Iustin Pop
24 a8083063 Iustin Pop
This program wipes disks and creates a volume group on top of them. It
25 a8083063 Iustin Pop
can also show disk information to help you decide which disks you want
26 a8083063 Iustin Pop
to wipe.
27 a8083063 Iustin Pop
28 a8083063 Iustin Pop
The error handling is done by raising our own exceptions from most of
29 a8083063 Iustin Pop
the functions; these exceptions then handled globally in the main()
30 a8083063 Iustin Pop
function. The exceptions that each function can raise are not
31 a8083063 Iustin Pop
documented individually, since almost every error path ends in a
32 a8083063 Iustin Pop
raise.
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
Another two exceptions that are handled globally are IOError and
35 a8083063 Iustin Pop
OSError. The idea behind this is, since we run as root, we should
36 a8083063 Iustin Pop
usually not get these errors, but if we do it's most probably a system
37 a8083063 Iustin Pop
error, so they should be handled and the user instructed to report
38 a8083063 Iustin Pop
them.
39 454723b5 Iustin Pop
40 a8083063 Iustin Pop
"""
41 a8083063 Iustin Pop
42 a8083063 Iustin Pop
43 a8083063 Iustin Pop
import os
44 a8083063 Iustin Pop
import sys
45 a8083063 Iustin Pop
import optparse
46 a8083063 Iustin Pop
import time
47 b98bb41e Iustin Pop
import errno
48 a8083063 Iustin Pop
49 3374afa9 Guido Trotter
from ganeti.utils import RunCmd, ReadFile
50 a8083063 Iustin Pop
from ganeti import constants
51 e194129a Stephen Shirley
from ganeti import cli
52 577d45d4 Iustin Pop
from ganeti import compat
53 a8083063 Iustin Pop
54 d1687c6f Iustin Pop
USAGE = ("\tlvmstrap diskinfo\n"
55 d1687c6f Iustin Pop
         "\tlvmstrap [--vgname=NAME] [--allow-removable]"
56 d1687c6f Iustin Pop
         " { --alldisks | --disks DISKLIST }"
57 a8083063 Iustin Pop
         " create")
58 a8083063 Iustin Pop
59 a8083063 Iustin Pop
verbose_flag = False
60 a8083063 Iustin Pop
61 577d45d4 Iustin Pop
#: Supported disk types (as prefixes)
62 577d45d4 Iustin Pop
SUPPORTED_TYPES = [
63 577d45d4 Iustin Pop
  "hd",
64 577d45d4 Iustin Pop
  "sd",
65 577d45d4 Iustin Pop
  "md",
66 577d45d4 Iustin Pop
  "ubd",
67 577d45d4 Iustin Pop
  ]
68 577d45d4 Iustin Pop
69 a8083063 Iustin Pop
70 a8083063 Iustin Pop
class Error(Exception):
71 a8083063 Iustin Pop
  """Generic exception"""
72 a8083063 Iustin Pop
  pass
73 a8083063 Iustin Pop
74 a8083063 Iustin Pop
75 a8083063 Iustin Pop
class ProgrammingError(Error):
76 a8083063 Iustin Pop
  """Exception denoting invalid assumptions in programming.
77 a8083063 Iustin Pop
78 a8083063 Iustin Pop
  This should catch sysfs tree changes, or otherwise incorrect
79 a8083063 Iustin Pop
  assumptions about the contents of the /sys/block/... directories.
80 454723b5 Iustin Pop
81 a8083063 Iustin Pop
  """
82 a8083063 Iustin Pop
  pass
83 a8083063 Iustin Pop
84 a8083063 Iustin Pop
85 a8083063 Iustin Pop
class SysconfigError(Error):
86 a8083063 Iustin Pop
  """Exception denoting invalid system configuration.
87 a8083063 Iustin Pop
88 a8083063 Iustin Pop
  If the system configuration is somehow wrong (e.g. /dev files
89 a8083063 Iustin Pop
  missing, or having mismatched major/minor numbers relative to
90 a8083063 Iustin Pop
  /sys/block devices), this exception will be raised.
91 a8083063 Iustin Pop
92 a8083063 Iustin Pop
  This should usually mean that the installation of the Xen node
93 a8083063 Iustin Pop
  failed in some steps.
94 454723b5 Iustin Pop
95 a8083063 Iustin Pop
  """
96 a8083063 Iustin Pop
  pass
97 a8083063 Iustin Pop
98 a8083063 Iustin Pop
99 a8083063 Iustin Pop
class PrereqError(Error):
100 a8083063 Iustin Pop
  """Exception denoting invalid prerequisites.
101 a8083063 Iustin Pop
102 a8083063 Iustin Pop
  If the node does not meet the requirements for cluster membership, this
103 a8083063 Iustin Pop
  exception will be raised. Things like wrong kernel version, or no
104 a8083063 Iustin Pop
  free disks, etc. belong here.
105 a8083063 Iustin Pop
106 a8083063 Iustin Pop
  This should usually mean that the build steps for the Xen node were
107 a8083063 Iustin Pop
  not followed correctly.
108 454723b5 Iustin Pop
109 a8083063 Iustin Pop
  """
110 a8083063 Iustin Pop
  pass
111 a8083063 Iustin Pop
112 a8083063 Iustin Pop
113 a8083063 Iustin Pop
class OperationalError(Error):
114 a8083063 Iustin Pop
  """Exception denoting actual errors.
115 a8083063 Iustin Pop
116 a8083063 Iustin Pop
  Errors during the bootstrapping are signaled using this exception.
117 454723b5 Iustin Pop
118 a8083063 Iustin Pop
  """
119 a8083063 Iustin Pop
  pass
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
122 a8083063 Iustin Pop
class ParameterError(Error):
123 a8083063 Iustin Pop
  """Exception denoting invalid input from user.
124 a8083063 Iustin Pop
125 a8083063 Iustin Pop
  Wrong disks given as parameters will be signaled using this
126 a8083063 Iustin Pop
  exception.
127 454723b5 Iustin Pop
128 a8083063 Iustin Pop
  """
129 a8083063 Iustin Pop
  pass
130 a8083063 Iustin Pop
131 7c0d6283 Michael Hanselmann
132 a8083063 Iustin Pop
def Usage():
133 454723b5 Iustin Pop
  """Shows program usage information and exits the program.
134 a8083063 Iustin Pop
135 454723b5 Iustin Pop
  """
136 a8083063 Iustin Pop
  print >> sys.stderr, "Usage:"
137 a8083063 Iustin Pop
  print >> sys.stderr, USAGE
138 a8083063 Iustin Pop
  sys.exit(2)
139 a8083063 Iustin Pop
140 a8083063 Iustin Pop
141 a8083063 Iustin Pop
def ParseOptions():
142 a8083063 Iustin Pop
  """Parses the command line options.
143 a8083063 Iustin Pop
144 a8083063 Iustin Pop
  In case of command line errors, it will show the usage and exit the
145 a8083063 Iustin Pop
  program.
146 a8083063 Iustin Pop
147 454723b5 Iustin Pop
  @rtype: tuple
148 454723b5 Iustin Pop
  @return: a tuple of (options, args), as returned by
149 454723b5 Iustin Pop
      OptionParser.parse_args
150 454723b5 Iustin Pop
151 a8083063 Iustin Pop
  """
152 7260cfbe Iustin Pop
  global verbose_flag # pylint: disable-msg=W0603
153 a8083063 Iustin Pop
154 a8083063 Iustin Pop
  parser = optparse.OptionParser(usage="\n%s" % USAGE,
155 a8083063 Iustin Pop
                                 version="%%prog (ganeti) %s" %
156 a8083063 Iustin Pop
                                 constants.RELEASE_VERSION)
157 a8083063 Iustin Pop
158 a8083063 Iustin Pop
  parser.add_option("--alldisks", dest="alldisks",
159 a8083063 Iustin Pop
                    help="erase ALL disks", action="store_true",
160 a8083063 Iustin Pop
                    default=False)
161 a8083063 Iustin Pop
  parser.add_option("-d", "--disks", dest="disks",
162 a8083063 Iustin Pop
                    help="Choose disks (e.g. hda,hdg)",
163 a8083063 Iustin Pop
                    metavar="DISKLIST")
164 9cdb9578 Iustin Pop
  parser.add_option(cli.VERBOSE_OPT)
165 d1687c6f Iustin Pop
  parser.add_option("-r", "--allow-removable",
166 d1687c6f Iustin Pop
                    action="store_true", dest="removable_ok", default=False,
167 d1687c6f Iustin Pop
                    help="allow and use removable devices too")
168 a8083063 Iustin Pop
  parser.add_option("-g", "--vg-name", type="string",
169 a8083063 Iustin Pop
                    dest="vgname", default="xenvg", metavar="NAME",
170 a8083063 Iustin Pop
                    help="the volume group to be created [default: xenvg]")
171 a8083063 Iustin Pop
172 a8083063 Iustin Pop
173 a8083063 Iustin Pop
  options, args = parser.parse_args()
174 a8083063 Iustin Pop
  if len(args) != 1:
175 a8083063 Iustin Pop
    Usage()
176 a8083063 Iustin Pop
177 a8083063 Iustin Pop
  verbose_flag = options.verbose
178 a8083063 Iustin Pop
179 a8083063 Iustin Pop
  return options, args
180 a8083063 Iustin Pop
181 a8083063 Iustin Pop
182 577d45d4 Iustin Pop
def IsPartitioned(disk):
183 577d45d4 Iustin Pop
  """Returns whether a given disk should be used partitioned or as-is.
184 577d45d4 Iustin Pop
185 577d45d4 Iustin Pop
  Currently only md devices are used as is.
186 577d45d4 Iustin Pop
187 577d45d4 Iustin Pop
  """
188 577d45d4 Iustin Pop
  return not disk.startswith('md')
189 577d45d4 Iustin Pop
190 577d45d4 Iustin Pop
191 577d45d4 Iustin Pop
def DeviceName(disk):
192 577d45d4 Iustin Pop
  """Returns the appropriate device name for a disk.
193 577d45d4 Iustin Pop
194 577d45d4 Iustin Pop
  For non-partitioned devices, it returns the name as is, otherwise it
195 577d45d4 Iustin Pop
  returns the first partition.
196 577d45d4 Iustin Pop
197 577d45d4 Iustin Pop
  """
198 577d45d4 Iustin Pop
  if IsPartitioned(disk):
199 577d45d4 Iustin Pop
    device = '/dev/%s1' % disk
200 577d45d4 Iustin Pop
  else:
201 577d45d4 Iustin Pop
    device = '/dev/%s' % disk
202 577d45d4 Iustin Pop
  return device
203 577d45d4 Iustin Pop
204 577d45d4 Iustin Pop
205 a8083063 Iustin Pop
def ExecCommand(command):
206 a8083063 Iustin Pop
  """Executes a command.
207 a8083063 Iustin Pop
208 a8083063 Iustin Pop
  This is just a wrapper around commands.getstatusoutput, with the
209 a8083063 Iustin Pop
  difference that if the command line argument -v has been given, it
210 a8083063 Iustin Pop
  will print the command line and the command output on stdout.
211 a8083063 Iustin Pop
212 454723b5 Iustin Pop
  @param command: the command line to be executed
213 454723b5 Iustin Pop
  @rtype: tuple
214 454723b5 Iustin Pop
  @return: a tuple of (status, output) where status is the exit status
215 454723b5 Iustin Pop
      and output the stdout and stderr of the command together
216 a8083063 Iustin Pop
217 454723b5 Iustin Pop
  """
218 a8083063 Iustin Pop
  if verbose_flag:
219 a8083063 Iustin Pop
    print command
220 a8083063 Iustin Pop
  result = RunCmd(command)
221 a8083063 Iustin Pop
  if verbose_flag:
222 a8083063 Iustin Pop
    print result.output
223 a8083063 Iustin Pop
  return result
224 a8083063 Iustin Pop
225 a8083063 Iustin Pop
226 a8083063 Iustin Pop
def CheckPrereq():
227 a8083063 Iustin Pop
  """Check the prerequisites of this program.
228 a8083063 Iustin Pop
229 a8083063 Iustin Pop
  It check that it runs on Linux 2.6, and that /sys is mounted and the
230 a8083063 Iustin Pop
  fact that /sys/block is a directory.
231 a8083063 Iustin Pop
232 454723b5 Iustin Pop
  """
233 a8083063 Iustin Pop
  if os.getuid() != 0:
234 a8083063 Iustin Pop
    raise PrereqError("This tool runs as root only. Really.")
235 a8083063 Iustin Pop
236 f4ad2ef0 Iustin Pop
  osname, _, release, _, _ = os.uname()
237 a8083063 Iustin Pop
  if osname != 'Linux':
238 f4bc1f2c Michael Hanselmann
    raise PrereqError("This tool only runs on Linux"
239 f4bc1f2c Michael Hanselmann
                      " (detected OS: %s)." % osname)
240 a8083063 Iustin Pop
241 a8083063 Iustin Pop
  if not release.startswith("2.6."):
242 f4bc1f2c Michael Hanselmann
    raise PrereqError("Wrong major kernel version (detected %s, needs"
243 f4bc1f2c Michael Hanselmann
                      " 2.6.*)" % release)
244 a8083063 Iustin Pop
245 a8083063 Iustin Pop
  if not os.path.ismount("/sys"):
246 f4bc1f2c Michael Hanselmann
    raise PrereqError("Can't find a filesystem mounted at /sys."
247 f4bc1f2c Michael Hanselmann
                      " Please mount /sys.")
248 a8083063 Iustin Pop
249 a8083063 Iustin Pop
  if not os.path.isdir("/sys/block"):
250 f4bc1f2c Michael Hanselmann
    raise SysconfigError("Can't find /sys/block directory. Has the"
251 f4bc1f2c Michael Hanselmann
                         " layout of /sys changed?")
252 a8083063 Iustin Pop
253 a8083063 Iustin Pop
  if not os.path.ismount("/proc"):
254 f4bc1f2c Michael Hanselmann
    raise PrereqError("Can't find a filesystem mounted at /proc."
255 f4bc1f2c Michael Hanselmann
                      " Please mount /proc.")
256 a8083063 Iustin Pop
257 a8083063 Iustin Pop
  if not os.path.exists("/proc/mounts"):
258 a8083063 Iustin Pop
    raise SysconfigError("Can't find /proc/mounts")
259 a8083063 Iustin Pop
260 a8083063 Iustin Pop
261 a8083063 Iustin Pop
def CheckVGExists(vgname):
262 a8083063 Iustin Pop
  """Checks to see if a volume group exists.
263 a8083063 Iustin Pop
264 454723b5 Iustin Pop
  @param vgname: the volume group name
265 a8083063 Iustin Pop
266 454723b5 Iustin Pop
  @return: a four-tuple (exists, lv_count, vg_size, vg_free), where:
267 454723b5 Iustin Pop
      - exists: True if the volume exists, otherwise False; if False,
268 a8083063 Iustin Pop
        all other members of the tuple are None
269 454723b5 Iustin Pop
      - lv_count: The number of logical volumes in the volume group
270 454723b5 Iustin Pop
      - vg_size: The total size of the volume group (in gibibytes)
271 454723b5 Iustin Pop
      - vg_free: The available space in the volume group
272 a8083063 Iustin Pop
273 454723b5 Iustin Pop
  """
274 f4bc1f2c Michael Hanselmann
  result = ExecCommand("vgs --nohead -o lv_count,vg_size,vg_free"
275 f4bc1f2c Michael Hanselmann
                       " --nosuffix --units g"
276 f4bc1f2c Michael Hanselmann
                       " --ignorelockingfailure %s" % vgname)
277 a8083063 Iustin Pop
  if not result.failed:
278 a8083063 Iustin Pop
    try:
279 a8083063 Iustin Pop
      lv_count, vg_size, vg_free = result.stdout.strip().split()
280 a8083063 Iustin Pop
    except ValueError:
281 a8083063 Iustin Pop
      # This means the output of vgdisplay can't be parsed
282 a8083063 Iustin Pop
      raise PrereqError("cannot parse output of vgs (%s)" % result.stdout)
283 a8083063 Iustin Pop
  else:
284 a8083063 Iustin Pop
    lv_count = vg_size = vg_free = None
285 a8083063 Iustin Pop
286 a8083063 Iustin Pop
  return not result.failed, lv_count, vg_size, vg_free
287 a8083063 Iustin Pop
288 a8083063 Iustin Pop
289 a8083063 Iustin Pop
def CheckSysDev(name, devnum):
290 a8083063 Iustin Pop
  """Checks consistency between /sys and /dev trees.
291 a8083063 Iustin Pop
292 a8083063 Iustin Pop
  In /sys/block/<name>/dev and /sys/block/<name>/<part>/dev are the
293 a8083063 Iustin Pop
  kernel-known device numbers. The /dev/<name> block/char devices are
294 a8083063 Iustin Pop
  created by userspace and thus could differ from the kernel
295 a8083063 Iustin Pop
  view. This function checks the consistency between the device number
296 a8083063 Iustin Pop
  read from /sys and the actual device number in /dev.
297 a8083063 Iustin Pop
298 a8083063 Iustin Pop
  Note that since the system could be using udev which removes and
299 a8083063 Iustin Pop
  recreates the device nodes on partition table rescan, we need to do
300 a8083063 Iustin Pop
  some retries here. Since we only do a stat, we can afford to do many
301 a8083063 Iustin Pop
  short retries.
302 a8083063 Iustin Pop
303 454723b5 Iustin Pop
  @param name: the device name, e.g. 'sda'
304 454723b5 Iustin Pop
  @param devnum: the device number, e.g. 0x803 (2051 in decimal) for sda3
305 454723b5 Iustin Pop
  @raises L{SysconfigError}: in case of failure of the check
306 a8083063 Iustin Pop
307 a8083063 Iustin Pop
  """
308 a8083063 Iustin Pop
  path = "/dev/%s" % name
309 f4ad2ef0 Iustin Pop
  for _ in range(40):
310 a8083063 Iustin Pop
    if os.path.exists(path):
311 a8083063 Iustin Pop
      break
312 a8083063 Iustin Pop
    time.sleep(0.250)
313 a8083063 Iustin Pop
  else:
314 f4bc1f2c Michael Hanselmann
    raise SysconfigError("the device file %s does not exist, but the block"
315 f4bc1f2c Michael Hanselmann
                         " device exists in the /sys/block tree" % path)
316 a8083063 Iustin Pop
  rdev = os.stat(path).st_rdev
317 a8083063 Iustin Pop
  if devnum != rdev:
318 f4bc1f2c Michael Hanselmann
    raise SysconfigError("For device %s, the major:minor in /dev is %04x"
319 f4bc1f2c Michael Hanselmann
                         " while the major:minor in sysfs is %s" %
320 a8083063 Iustin Pop
                         (path, rdev, devnum))
321 a8083063 Iustin Pop
322 a8083063 Iustin Pop
323 a8083063 Iustin Pop
def ReadDev(syspath):
324 a8083063 Iustin Pop
  """Reads the device number from a sysfs path.
325 a8083063 Iustin Pop
326 a8083063 Iustin Pop
  The device number is given in sysfs under a block device directory
327 a8083063 Iustin Pop
  in a file named 'dev' which contains major:minor (in ASCII). This
328 a8083063 Iustin Pop
  function reads that file and converts the major:minor pair to a dev
329 a8083063 Iustin Pop
  number.
330 a8083063 Iustin Pop
331 454723b5 Iustin Pop
  @type syspath: string
332 454723b5 Iustin Pop
  @param syspath: the path to a block device dir in sysfs,
333 454723b5 Iustin Pop
      e.g. C{/sys/block/sda}
334 a8083063 Iustin Pop
335 454723b5 Iustin Pop
  @return: the device number
336 a8083063 Iustin Pop
337 454723b5 Iustin Pop
  """
338 a8083063 Iustin Pop
  if not os.path.exists("%s/dev" % syspath):
339 a8083063 Iustin Pop
    raise ProgrammingError("Invalid path passed to ReadDev: %s" % syspath)
340 a8083063 Iustin Pop
  f = open("%s/dev" % syspath)
341 a8083063 Iustin Pop
  data = f.read().strip()
342 a8083063 Iustin Pop
  f.close()
343 a8083063 Iustin Pop
  major, minor = data.split(":", 1)
344 a8083063 Iustin Pop
  major = int(major)
345 a8083063 Iustin Pop
  minor = int(minor)
346 a8083063 Iustin Pop
  dev = os.makedev(major, minor)
347 a8083063 Iustin Pop
  return dev
348 a8083063 Iustin Pop
349 a8083063 Iustin Pop
350 a8083063 Iustin Pop
def ReadSize(syspath):
351 a8083063 Iustin Pop
  """Reads the size from a sysfs path.
352 a8083063 Iustin Pop
353 a8083063 Iustin Pop
  The size is given in sysfs under a block device directory in a file
354 a8083063 Iustin Pop
  named 'size' which contains the number of sectors (in ASCII). This
355 a8083063 Iustin Pop
  function reads that file and converts the number in sectors to the
356 a8083063 Iustin Pop
  size in bytes.
357 a8083063 Iustin Pop
358 454723b5 Iustin Pop
  @type syspath: string
359 454723b5 Iustin Pop
  @param syspath: the path to a block device dir in sysfs,
360 454723b5 Iustin Pop
      e.g. C{/sys/block/sda}
361 454723b5 Iustin Pop
362 454723b5 Iustin Pop
  @rtype: int
363 454723b5 Iustin Pop
  @return: the device size in bytes
364 a8083063 Iustin Pop
365 a8083063 Iustin Pop
  """
366 a8083063 Iustin Pop
367 a8083063 Iustin Pop
  if not os.path.exists("%s/size" % syspath):
368 a8083063 Iustin Pop
    raise ProgrammingError("Invalid path passed to ReadSize: %s" % syspath)
369 a8083063 Iustin Pop
  f = open("%s/size" % syspath)
370 a8083063 Iustin Pop
  data = f.read().strip()
371 a8083063 Iustin Pop
  f.close()
372 a8083063 Iustin Pop
  size = 512L * int(data)
373 a8083063 Iustin Pop
  return size
374 a8083063 Iustin Pop
375 a8083063 Iustin Pop
376 a8083063 Iustin Pop
def ReadPV(name):
377 a8083063 Iustin Pop
  """Reads physical volume information.
378 a8083063 Iustin Pop
379 a8083063 Iustin Pop
  This function tries to see if a block device is a physical volume.
380 a8083063 Iustin Pop
381 454723b5 Iustin Pop
  @type name: string
382 454723b5 Iustin Pop
  @param name: the device name (e.g. sda)
383 454723b5 Iustin Pop
384 454723b5 Iustin Pop
  @return: the name of the volume group to which this PV belongs, or
385 454723b5 Iustin Pop
      "" if this PV is not in use, or None if this is not a PV
386 a8083063 Iustin Pop
387 454723b5 Iustin Pop
  """
388 a8083063 Iustin Pop
  result = ExecCommand("pvdisplay -c /dev/%s" % name)
389 a8083063 Iustin Pop
  if result.failed:
390 a8083063 Iustin Pop
    return None
391 a8083063 Iustin Pop
  vgname = result.stdout.strip().split(":")[1]
392 a8083063 Iustin Pop
  return vgname
393 a8083063 Iustin Pop
394 a8083063 Iustin Pop
395 d1687c6f Iustin Pop
def GetDiskList(opts):
396 a8083063 Iustin Pop
  """Computes the block device list for this system.
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
  This function examines the /sys/block tree and using information
399 a8083063 Iustin Pop
  therein, computes the status of the block device.
400 a8083063 Iustin Pop
401 454723b5 Iustin Pop
  @return: a list like [(name, size, dev, partitions, inuse), ...], where:
402 454723b5 Iustin Pop
      - name is the block device name (e.g. sda)
403 454723b5 Iustin Pop
      - size the size in bytes
404 454723b5 Iustin Pop
      - dev is the device number (e.g. 8704 for hdg)
405 454723b5 Iustin Pop
      - partitions is [(name, size, dev), ...] mirroring the disk list
406 454723b5 Iustin Pop
        data inuse is a boolean showing the in-use status of the disk,
407 454723b5 Iustin Pop
        computed as the possibility of re-reading the partition table
408 454723b5 Iustin Pop
        (the meaning of the operation varies with the kernel version,
409 454723b5 Iustin Pop
        but is usually accurate; a mounted disk/partition or swap-area
410 454723b5 Iustin Pop
        or PV with active LVs on it is busy)
411 a8083063 Iustin Pop
412 454723b5 Iustin Pop
  """
413 a8083063 Iustin Pop
  dlist = []
414 a8083063 Iustin Pop
  for name in os.listdir("/sys/block"):
415 577d45d4 Iustin Pop
    if not compat.any([name.startswith(pfx) for pfx in SUPPORTED_TYPES]):
416 a8083063 Iustin Pop
      continue
417 a8083063 Iustin Pop
418 a8083063 Iustin Pop
    size = ReadSize("/sys/block/%s" % name)
419 a8083063 Iustin Pop
420 a8083063 Iustin Pop
    f = open("/sys/block/%s/removable" % name)
421 a8083063 Iustin Pop
    removable = int(f.read().strip())
422 a8083063 Iustin Pop
    f.close()
423 a8083063 Iustin Pop
424 d1687c6f Iustin Pop
    if removable and not opts.removable_ok:
425 a8083063 Iustin Pop
      continue
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
    dev = ReadDev("/sys/block/%s" % name)
428 a8083063 Iustin Pop
    CheckSysDev(name, dev)
429 b98bb41e Iustin Pop
    inuse = InUse(name)
430 a8083063 Iustin Pop
    # Enumerate partitions of the block device
431 a8083063 Iustin Pop
    partitions = []
432 a8083063 Iustin Pop
    for partname in os.listdir("/sys/block/%s" % name):
433 a8083063 Iustin Pop
      if not partname.startswith(name):
434 a8083063 Iustin Pop
        continue
435 a8083063 Iustin Pop
      partdev = ReadDev("/sys/block/%s/%s" % (name, partname))
436 a8083063 Iustin Pop
      partsize = ReadSize("/sys/block/%s/%s" % (name, partname))
437 a8083063 Iustin Pop
      CheckSysDev(partname, partdev)
438 a8083063 Iustin Pop
      partitions.append((partname, partsize, partdev))
439 a8083063 Iustin Pop
    partitions.sort()
440 a8083063 Iustin Pop
    dlist.append((name, size, dev, partitions, inuse))
441 a8083063 Iustin Pop
  dlist.sort()
442 a8083063 Iustin Pop
  return dlist
443 a8083063 Iustin Pop
444 a8083063 Iustin Pop
445 a8083063 Iustin Pop
def GetMountInfo():
446 a8083063 Iustin Pop
  """Reads /proc/mounts and computes the mountpoint-devnum mapping.
447 a8083063 Iustin Pop
448 a8083063 Iustin Pop
  This function reads /proc/mounts, finds the mounted filesystems
449 a8083063 Iustin Pop
  (excepting a hard-coded blacklist of network and virtual
450 a8083063 Iustin Pop
  filesystems) and does a stat on these mountpoints. The st_dev number
451 a8083063 Iustin Pop
  of the results is memorised for later matching against the
452 a8083063 Iustin Pop
  /sys/block devices.
453 a8083063 Iustin Pop
454 454723b5 Iustin Pop
  @rtype: dict
455 454723b5 Iustin Pop
  @return: a {mountpoint: device number} dictionary
456 a8083063 Iustin Pop
457 454723b5 Iustin Pop
  """
458 3374afa9 Guido Trotter
  mountlines = ReadFile("/proc/mounts").splitlines()
459 a8083063 Iustin Pop
  mounts = {}
460 a8083063 Iustin Pop
  for line in mountlines:
461 f4ad2ef0 Iustin Pop
    _, mountpoint, fstype, _ = line.split(None, 3)
462 a8083063 Iustin Pop
    # fs type blacklist
463 a8083063 Iustin Pop
    if fstype in ["nfs", "nfs4", "autofs", "tmpfs", "proc", "sysfs"]:
464 a8083063 Iustin Pop
      continue
465 a8083063 Iustin Pop
    try:
466 a8083063 Iustin Pop
      dev = os.stat(mountpoint).st_dev
467 a8083063 Iustin Pop
    except OSError, err:
468 a8083063 Iustin Pop
      # this should be a fairly rare error, since we are blacklisting
469 a8083063 Iustin Pop
      # network filesystems; with this in mind, we'll ignore it,
470 a8083063 Iustin Pop
      # since the rereadpt check catches in-use filesystems,
471 a8083063 Iustin Pop
      # and this is used for disk information only
472 a8083063 Iustin Pop
      print >> sys.stderr, ("Can't stat mountpoint '%s': %s" %
473 a8083063 Iustin Pop
                            (mountpoint, err))
474 a8083063 Iustin Pop
      print >> sys.stderr, "Ignoring."
475 a8083063 Iustin Pop
      continue
476 a8083063 Iustin Pop
    mounts[dev] = mountpoint
477 a8083063 Iustin Pop
  return mounts
478 a8083063 Iustin Pop
479 a8083063 Iustin Pop
480 a8083063 Iustin Pop
def DevInfo(name, dev, mountinfo):
481 5bbd3f7f Michael Hanselmann
  """Computes miscellaneous information about a block device.
482 a8083063 Iustin Pop
483 454723b5 Iustin Pop
  @type name: string
484 454723b5 Iustin Pop
  @param name: the device name, e.g. sda
485 a8083063 Iustin Pop
486 454723b5 Iustin Pop
  @return: a tuple (mpath, whatvg, fileinfo), where:
487 454723b5 Iustin Pop
      - mpath is the mount path where this device is mounted or None
488 454723b5 Iustin Pop
      - whatvg is the result of the ReadPV function
489 454723b5 Iustin Pop
      - fileinfo is the output of file -bs on the device
490 a8083063 Iustin Pop
491 454723b5 Iustin Pop
  """
492 a8083063 Iustin Pop
  if dev in mountinfo:
493 a8083063 Iustin Pop
    mpath = mountinfo[dev]
494 a8083063 Iustin Pop
  else:
495 a8083063 Iustin Pop
    mpath = None
496 a8083063 Iustin Pop
497 a8083063 Iustin Pop
  whatvg = ReadPV(name)
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
  result = ExecCommand("file -bs /dev/%s" % name)
500 a8083063 Iustin Pop
  if result.failed:
501 a8083063 Iustin Pop
    fileinfo = "<error: %s>" % result.stderr
502 a8083063 Iustin Pop
  fileinfo = result.stdout[:45]
503 a8083063 Iustin Pop
  return mpath, whatvg, fileinfo
504 a8083063 Iustin Pop
505 a8083063 Iustin Pop
506 d1687c6f Iustin Pop
def ShowDiskInfo(opts):
507 a8083063 Iustin Pop
  """Shows a nicely formatted block device list for this system.
508 a8083063 Iustin Pop
509 5bbd3f7f Michael Hanselmann
  This function shows the user a table with the information gathered
510 a8083063 Iustin Pop
  by the other functions defined, in order to help the user make a
511 a8083063 Iustin Pop
  choice about which disks should be allocated to our volume group.
512 a8083063 Iustin Pop
513 a8083063 Iustin Pop
  """
514 a8083063 Iustin Pop
  mounts = GetMountInfo()
515 d1687c6f Iustin Pop
  dlist = GetDiskList(opts)
516 a8083063 Iustin Pop
517 a8083063 Iustin Pop
  print "------- Disk information -------"
518 e194129a Stephen Shirley
  headers = {
519 e194129a Stephen Shirley
      "name": "Name",
520 e194129a Stephen Shirley
      "size": "Size[M]",
521 e194129a Stephen Shirley
      "used": "Used",
522 e194129a Stephen Shirley
      "mount": "Mount",
523 e194129a Stephen Shirley
      "lvm": "LVM?",
524 e194129a Stephen Shirley
      "info": "Info"
525 e194129a Stephen Shirley
      }
526 e194129a Stephen Shirley
  fields = ["name", "size", "used", "mount", "lvm", "info"]
527 a8083063 Iustin Pop
528 a8083063 Iustin Pop
  flatlist = []
529 a8083063 Iustin Pop
  # Flatten the [(disk, [partition,...]), ...] list
530 a8083063 Iustin Pop
  for name, size, dev, parts, inuse in dlist:
531 a8083063 Iustin Pop
    if inuse:
532 a8083063 Iustin Pop
      str_inuse = "yes"
533 a8083063 Iustin Pop
    else:
534 a8083063 Iustin Pop
      str_inuse = "no"
535 a8083063 Iustin Pop
    flatlist.append((name, size, dev, str_inuse))
536 a8083063 Iustin Pop
    for partname, partsize, partdev in parts:
537 a8083063 Iustin Pop
      flatlist.append((partname, partsize, partdev, ""))
538 a8083063 Iustin Pop
539 e194129a Stephen Shirley
  strlist = []
540 a8083063 Iustin Pop
  for name, size, dev, in_use in flatlist:
541 a8083063 Iustin Pop
    mp, vgname, fileinfo = DevInfo(name, dev, mounts)
542 a8083063 Iustin Pop
    if mp is None:
543 a8083063 Iustin Pop
      mp = "-"
544 a8083063 Iustin Pop
    if vgname is None:
545 a8083063 Iustin Pop
      lvminfo = "-"
546 a8083063 Iustin Pop
    elif vgname == "":
547 a8083063 Iustin Pop
      lvminfo = "yes,free"
548 a8083063 Iustin Pop
    else:
549 a8083063 Iustin Pop
      lvminfo = "in %s" % vgname
550 a8083063 Iustin Pop
551 a8083063 Iustin Pop
    if len(name) > 3:
552 a8083063 Iustin Pop
      # Indent partitions
553 a8083063 Iustin Pop
      name = " %s" % name
554 e194129a Stephen Shirley
555 e194129a Stephen Shirley
    strlist.append([name, "%.2f" % (float(size) / 1024 / 1024),
556 e194129a Stephen Shirley
                    in_use, mp, lvminfo, fileinfo])
557 e194129a Stephen Shirley
558 e194129a Stephen Shirley
  data = cli.GenerateTable(headers, fields, None,
559 e194129a Stephen Shirley
                           strlist, numfields=["size"])
560 e194129a Stephen Shirley
561 e194129a Stephen Shirley
  for line in data:
562 e194129a Stephen Shirley
    print line
563 a8083063 Iustin Pop
564 a8083063 Iustin Pop
565 b98bb41e Iustin Pop
def CheckSysfsHolders(name):
566 b98bb41e Iustin Pop
  """Check to see if a device is 'hold' at sysfs level.
567 b98bb41e Iustin Pop
568 b98bb41e Iustin Pop
  This is usually the case for Physical Volumes under LVM.
569 b98bb41e Iustin Pop
570 b98bb41e Iustin Pop
  @rtype: boolean
571 b98bb41e Iustin Pop
  @return: true if the device is available according to sysfs
572 b98bb41e Iustin Pop
573 b98bb41e Iustin Pop
  """
574 b98bb41e Iustin Pop
  try:
575 b98bb41e Iustin Pop
    contents = os.listdir("/sys/block/%s/holders/" % name)
576 b98bb41e Iustin Pop
  except OSError, err:
577 b98bb41e Iustin Pop
    if err.errno == errno.ENOENT:
578 b98bb41e Iustin Pop
      contents = []
579 b98bb41e Iustin Pop
    else:
580 b98bb41e Iustin Pop
      raise
581 b98bb41e Iustin Pop
  return not bool(contents)
582 b98bb41e Iustin Pop
583 b98bb41e Iustin Pop
584 a8083063 Iustin Pop
def CheckReread(name):
585 a8083063 Iustin Pop
  """Check to see if a block device is in use.
586 a8083063 Iustin Pop
587 577d45d4 Iustin Pop
  Uses blockdev to reread the partition table of a block device (or
588 577d45d4 Iustin Pop
  fuser if the device is not partitionable), and thus compute the
589 577d45d4 Iustin Pop
  in-use status.  See the discussion in GetDiskList about the meaning
590 577d45d4 Iustin Pop
  of 'in use'.
591 a8083063 Iustin Pop
592 454723b5 Iustin Pop
  @rtype: boolean
593 454723b5 Iustin Pop
  @return: the in-use status of the device
594 a8083063 Iustin Pop
595 454723b5 Iustin Pop
  """
596 577d45d4 Iustin Pop
  use_blockdev = IsPartitioned(name)
597 577d45d4 Iustin Pop
  if use_blockdev:
598 577d45d4 Iustin Pop
    cmd = "blockdev --rereadpt /dev/%s" % name
599 577d45d4 Iustin Pop
  else:
600 577d45d4 Iustin Pop
    cmd = "fuser -vam /dev/%s" % name
601 577d45d4 Iustin Pop
602 f4ad2ef0 Iustin Pop
  for _ in range(3):
603 577d45d4 Iustin Pop
    result = ExecCommand(cmd)
604 577d45d4 Iustin Pop
    if not use_blockdev and result.failed:
605 577d45d4 Iustin Pop
      break
606 577d45d4 Iustin Pop
    elif not result.failed:
607 a8083063 Iustin Pop
      break
608 a8083063 Iustin Pop
    time.sleep(2)
609 a8083063 Iustin Pop
610 577d45d4 Iustin Pop
  if use_blockdev:
611 577d45d4 Iustin Pop
    return not result.failed
612 577d45d4 Iustin Pop
  else:
613 577d45d4 Iustin Pop
    return result.failed
614 a8083063 Iustin Pop
615 a8083063 Iustin Pop
616 b98bb41e Iustin Pop
def InUse(name):
617 b98bb41e Iustin Pop
  """Returns if a disk is in use or not.
618 b98bb41e Iustin Pop
619 b98bb41e Iustin Pop
  """
620 b98bb41e Iustin Pop
  return not (CheckSysfsHolders(name) and CheckReread(name))
621 b98bb41e Iustin Pop
622 b98bb41e Iustin Pop
623 a8083063 Iustin Pop
def WipeDisk(name):
624 a8083063 Iustin Pop
  """Wipes a block device.
625 a8083063 Iustin Pop
626 a8083063 Iustin Pop
  This function wipes a block device, by clearing and re-reading the
627 a8083063 Iustin Pop
  partition table. If not successful, it writes back the old partition
628 a8083063 Iustin Pop
  data, and leaves the cleanup to the user.
629 a8083063 Iustin Pop
630 454723b5 Iustin Pop
  @param name: the device name (e.g. sda)
631 454723b5 Iustin Pop
632 a8083063 Iustin Pop
  """
633 a8083063 Iustin Pop
634 b98bb41e Iustin Pop
  if InUse(name):
635 f4bc1f2c Michael Hanselmann
    raise OperationalError("CRITICAL: disk %s you selected seems to be in"
636 f4bc1f2c Michael Hanselmann
                           " use. ABORTING!" % name)
637 a8083063 Iustin Pop
638 a8083063 Iustin Pop
  fd = os.open("/dev/%s" % name, os.O_RDWR | os.O_SYNC)
639 a8083063 Iustin Pop
  olddata = os.read(fd, 512)
640 a8083063 Iustin Pop
  if len(olddata) != 512:
641 f4bc1f2c Michael Hanselmann
    raise OperationalError("CRITICAL: Can't read partition table information"
642 f4bc1f2c Michael Hanselmann
                           " from /dev/%s (needed 512 bytes, got %d" %
643 a8083063 Iustin Pop
                           (name, len(olddata)))
644 a8083063 Iustin Pop
  newdata = "\0" * 512
645 a8083063 Iustin Pop
  os.lseek(fd, 0, 0)
646 a8083063 Iustin Pop
  bytes_written = os.write(fd, newdata)
647 a8083063 Iustin Pop
  os.close(fd)
648 a8083063 Iustin Pop
  if bytes_written != 512:
649 a8083063 Iustin Pop
    raise OperationalError("CRITICAL: Can't write partition table information"
650 f4bc1f2c Michael Hanselmann
                           " to /dev/%s (tried to write 512 bytes, written"
651 f4bc1f2c Michael Hanselmann
                           " %d. I don't know how to cleanup. Sorry." %
652 a8083063 Iustin Pop
                           (name, bytes_written))
653 a8083063 Iustin Pop
654 b98bb41e Iustin Pop
  if InUse(name):
655 b98bb41e Iustin Pop
    # try to restore the data
656 a8083063 Iustin Pop
    fd = os.open("/dev/%s" % name, os.O_RDWR | os.O_SYNC)
657 a8083063 Iustin Pop
    os.write(fd, olddata)
658 a8083063 Iustin Pop
    os.close(fd)
659 f4bc1f2c Michael Hanselmann
    raise OperationalError("CRITICAL: disk %s which I have just wiped cannot"
660 f4bc1f2c Michael Hanselmann
                           " reread partition table. Most likely, it is"
661 f4bc1f2c Michael Hanselmann
                           " in use. You have to clean after this yourself."
662 f4bc1f2c Michael Hanselmann
                           " I tried to restore the old partition table,"
663 f4bc1f2c Michael Hanselmann
                           " but I cannot guarantee nothing has broken." %
664 a8083063 Iustin Pop
                           name)
665 a8083063 Iustin Pop
666 a8083063 Iustin Pop
667 a8083063 Iustin Pop
def PartitionDisk(name):
668 a8083063 Iustin Pop
  """Partitions a disk.
669 a8083063 Iustin Pop
670 a8083063 Iustin Pop
  This function creates a single partition spanning the entire disk,
671 a8083063 Iustin Pop
  by means of fdisk.
672 a8083063 Iustin Pop
673 454723b5 Iustin Pop
  @param name: the device name, e.g. sda
674 454723b5 Iustin Pop
675 a8083063 Iustin Pop
  """
676 a8083063 Iustin Pop
  result = ExecCommand(
677 a8083063 Iustin Pop
    'echo ,,8e, | sfdisk /dev/%s' % name)
678 a8083063 Iustin Pop
  if result.failed:
679 f4bc1f2c Michael Hanselmann
    raise OperationalError("CRITICAL: disk %s which I have just partitioned"
680 f4bc1f2c Michael Hanselmann
                           " cannot reread its partition table, or there"
681 f4bc1f2c Michael Hanselmann
                           " is some other sfdisk error. Likely, it is in"
682 f4bc1f2c Michael Hanselmann
                           " use. You have to clean this yourself. Error"
683 f4bc1f2c Michael Hanselmann
                           " message from sfdisk: %s" %
684 a8083063 Iustin Pop
                           (name, result.output))
685 a8083063 Iustin Pop
686 a8083063 Iustin Pop
687 a8083063 Iustin Pop
def CreatePVOnDisk(name):
688 a8083063 Iustin Pop
  """Creates a physical volume on a block device.
689 a8083063 Iustin Pop
690 a8083063 Iustin Pop
  This function creates a physical volume on a block device, overriding
691 a8083063 Iustin Pop
  all warnings. So it can wipe existing PVs and PVs which are in a VG.
692 a8083063 Iustin Pop
693 454723b5 Iustin Pop
  @param name: the device name, e.g. sda
694 a8083063 Iustin Pop
695 a8083063 Iustin Pop
  """
696 577d45d4 Iustin Pop
  device = DeviceName(name)
697 577d45d4 Iustin Pop
  result = ExecCommand("pvcreate -yff %s" % device)
698 a8083063 Iustin Pop
  if result.failed:
699 f4bc1f2c Michael Hanselmann
    raise OperationalError("I cannot create a physical volume on"
700 577d45d4 Iustin Pop
                           " %s. Error message: %s."
701 f4bc1f2c Michael Hanselmann
                           " Please clean up yourself." %
702 577d45d4 Iustin Pop
                           (device, result.output))
703 a8083063 Iustin Pop
704 a8083063 Iustin Pop
705 a8083063 Iustin Pop
def CreateVG(vgname, disks):
706 a8083063 Iustin Pop
  """Creates the volume group.
707 a8083063 Iustin Pop
708 a8083063 Iustin Pop
  This function creates a volume group named `vgname` on the disks
709 a8083063 Iustin Pop
  given as parameters. The physical extent size is set to 64MB.
710 a8083063 Iustin Pop
711 454723b5 Iustin Pop
  @param disks: a list of disk names, e.g. ['sda','sdb']
712 a8083063 Iustin Pop
713 a8083063 Iustin Pop
  """
714 577d45d4 Iustin Pop
  pnames = [DeviceName(d) for d in disks]
715 a8083063 Iustin Pop
  result = ExecCommand("vgcreate -s 64MB '%s' %s" % (vgname, " ".join(pnames)))
716 a8083063 Iustin Pop
  if result.failed:
717 f4bc1f2c Michael Hanselmann
    raise OperationalError("I cannot create the volume group %s from"
718 f4bc1f2c Michael Hanselmann
                           " disks %s. Error message: %s. Please clean up"
719 f4bc1f2c Michael Hanselmann
                           " yourself." %
720 a8083063 Iustin Pop
                           (vgname, " ".join(disks), result.output))
721 a8083063 Iustin Pop
722 a8083063 Iustin Pop
723 a8083063 Iustin Pop
def ValidateDiskList(options):
724 a8083063 Iustin Pop
  """Validates or computes the disk list for create.
725 a8083063 Iustin Pop
726 a8083063 Iustin Pop
  This function either computes the available disk list (if the user
727 a8083063 Iustin Pop
  gave --alldisks option), or validates the user-given disk list (by
728 a8083063 Iustin Pop
  using the --disks option) such that all given disks are present and
729 a8083063 Iustin Pop
  not in use.
730 a8083063 Iustin Pop
731 454723b5 Iustin Pop
  @param options: the options returned from OptParser.parse_options
732 a8083063 Iustin Pop
733 454723b5 Iustin Pop
  @return: a list of disk names, e.g. ['sda', 'sdb']
734 a8083063 Iustin Pop
735 454723b5 Iustin Pop
  """
736 d1687c6f Iustin Pop
  sysdisks = GetDiskList(options)
737 a8083063 Iustin Pop
  if not sysdisks:
738 f4bc1f2c Michael Hanselmann
    raise PrereqError("no disks found (I looked for"
739 f4bc1f2c Michael Hanselmann
                      " non-removable block devices).")
740 a8083063 Iustin Pop
  sysd_free = []
741 a8083063 Iustin Pop
  sysd_used = []
742 f4ad2ef0 Iustin Pop
  for name, _, _, _, used in sysdisks:
743 a8083063 Iustin Pop
    if used:
744 a8083063 Iustin Pop
      sysd_used.append(name)
745 a8083063 Iustin Pop
    else:
746 a8083063 Iustin Pop
      sysd_free.append(name)
747 a8083063 Iustin Pop
748 a8083063 Iustin Pop
  if not sysd_free:
749 a8083063 Iustin Pop
    raise PrereqError("no free disks found! (%d in-use disks)" %
750 a8083063 Iustin Pop
                      len(sysd_used))
751 a8083063 Iustin Pop
  if options.alldisks:
752 a8083063 Iustin Pop
    disklist = sysd_free
753 a8083063 Iustin Pop
  elif options.disks:
754 a8083063 Iustin Pop
    disklist = options.disks.split(",")
755 a8083063 Iustin Pop
    for name in disklist:
756 a8083063 Iustin Pop
      if name in sysd_used:
757 a8083063 Iustin Pop
        raise ParameterError("disk %s is in use, cannot wipe!" % name)
758 a8083063 Iustin Pop
      if name not in sysd_free:
759 a8083063 Iustin Pop
        raise ParameterError("cannot find disk %s!" % name)
760 a8083063 Iustin Pop
  else:
761 a8083063 Iustin Pop
    raise ParameterError("Please use either --alldisks or --disks!")
762 a8083063 Iustin Pop
763 a8083063 Iustin Pop
  return disklist
764 a8083063 Iustin Pop
765 f4bc1f2c Michael Hanselmann
766 a8083063 Iustin Pop
def BootStrap():
767 454723b5 Iustin Pop
  """Actual main routine.
768 a8083063 Iustin Pop
769 454723b5 Iustin Pop
  """
770 a8083063 Iustin Pop
  CheckPrereq()
771 a8083063 Iustin Pop
772 a8083063 Iustin Pop
  options, args = ParseOptions()
773 a8083063 Iustin Pop
  vgname = options.vgname
774 a8083063 Iustin Pop
  command = args.pop(0)
775 a8083063 Iustin Pop
  if command == "diskinfo":
776 d1687c6f Iustin Pop
    ShowDiskInfo(options)
777 a8083063 Iustin Pop
    return
778 a8083063 Iustin Pop
  if command != "create":
779 a8083063 Iustin Pop
    Usage()
780 a8083063 Iustin Pop
781 a8083063 Iustin Pop
  exists, lv_count, vg_size, vg_free = CheckVGExists(vgname)
782 a8083063 Iustin Pop
  if exists:
783 a8083063 Iustin Pop
    raise PrereqError("It seems volume group '%s' already exists:\n"
784 a8083063 Iustin Pop
                      "  LV count: %s, size: %s, free: %s." %
785 a8083063 Iustin Pop
                      (vgname, lv_count, vg_size, vg_free))
786 a8083063 Iustin Pop
787 a8083063 Iustin Pop
788 a8083063 Iustin Pop
  disklist = ValidateDiskList(options)
789 a8083063 Iustin Pop
790 a8083063 Iustin Pop
  for disk in disklist:
791 a8083063 Iustin Pop
    WipeDisk(disk)
792 577d45d4 Iustin Pop
    if IsPartitioned(disk):
793 577d45d4 Iustin Pop
      PartitionDisk(disk)
794 a8083063 Iustin Pop
  for disk in disklist:
795 a8083063 Iustin Pop
    CreatePVOnDisk(disk)
796 a8083063 Iustin Pop
  CreateVG(vgname, disklist)
797 a8083063 Iustin Pop
798 f4ad2ef0 Iustin Pop
  status, lv_count, size, _ = CheckVGExists(vgname)
799 a8083063 Iustin Pop
  if status:
800 a8083063 Iustin Pop
    print "Done! %s: size %s GiB, disks: %s" % (vgname, size,
801 f4bc1f2c Michael Hanselmann
                                              ",".join(disklist))
802 a8083063 Iustin Pop
  else:
803 f4bc1f2c Michael Hanselmann
    raise OperationalError("Although everything seemed ok, the volume"
804 f4bc1f2c Michael Hanselmann
                           " group did not get created.")
805 a8083063 Iustin Pop
806 a8083063 Iustin Pop
807 a8083063 Iustin Pop
def main():
808 454723b5 Iustin Pop
  """Application entry point.
809 a8083063 Iustin Pop
810 a8083063 Iustin Pop
  This is just a wrapper over BootStrap, to handle our own exceptions.
811 a8083063 Iustin Pop
812 454723b5 Iustin Pop
  """
813 a8083063 Iustin Pop
  try:
814 a8083063 Iustin Pop
    BootStrap()
815 a8083063 Iustin Pop
  except PrereqError, err:
816 a8083063 Iustin Pop
    print >> sys.stderr, "The prerequisites for running this tool are not met."
817 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("Please make sure you followed all the steps in"
818 f4bc1f2c Michael Hanselmann
                          " the build document.")
819 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
820 a8083063 Iustin Pop
    sys.exit(1)
821 a8083063 Iustin Pop
  except SysconfigError, err:
822 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("This system's configuration seems wrong, at"
823 f4bc1f2c Michael Hanselmann
                          " least is not what I expect.")
824 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("Please check that the installation didn't fail"
825 f4bc1f2c Michael Hanselmann
                          " at some step.")
826 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
827 a8083063 Iustin Pop
    sys.exit(1)
828 a8083063 Iustin Pop
  except ParameterError, err:
829 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("Some parameters you gave to the program or the"
830 f4bc1f2c Michael Hanselmann
                          " invocation is wrong. ")
831 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
832 a8083063 Iustin Pop
    Usage()
833 a8083063 Iustin Pop
  except OperationalError, err:
834 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("A serious error has happened while modifying"
835 f4bc1f2c Michael Hanselmann
                          " the system's configuration.")
836 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("Please review the error message below and make"
837 f4bc1f2c Michael Hanselmann
                          " sure you clean up yourself.")
838 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("It is most likely that the system configuration"
839 f4bc1f2c Michael Hanselmann
                          " has been partially altered.")
840 a8083063 Iustin Pop
    print >> sys.stderr, str(err)
841 a8083063 Iustin Pop
    sys.exit(1)
842 a8083063 Iustin Pop
  except ProgrammingError, err:
843 f4bc1f2c Michael Hanselmann
    print >> sys.stderr, ("Internal application error. Please signal this"
844 f4bc1f2c Michael Hanselmann
                          " to xencluster-team.")
845 a8083063 Iustin Pop
    print >> sys.stderr, "Error description: %s" % str(err)
846 a8083063 Iustin Pop
    sys.exit(1)
847 a8083063 Iustin Pop
  except Error, err:
848 a8083063 Iustin Pop
    print >> sys.stderr, "Unhandled application error: %s" % err
849 a8083063 Iustin Pop
    sys.exit(1)
850 a8083063 Iustin Pop
  except (IOError, OSError), err:
851 a8083063 Iustin Pop
    print >> sys.stderr, "I/O error detected, please report."
852 a8083063 Iustin Pop
    print >> sys.stderr, "Description: %s" % str(err)
853 a8083063 Iustin Pop
    sys.exit(1)
854 a8083063 Iustin Pop
855 a8083063 Iustin Pop
856 a8083063 Iustin Pop
if __name__ == "__main__":
857 a8083063 Iustin Pop
  main()