Statistics
| Branch: | Tag: | Revision:

root / tools / lvmstrap @ 1817dca9

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