Statistics
| Branch: | Tag: | Revision:

root / tools / lvmstrap @ 54bd7d76

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