lvmstrap: add support for non-partitioned md disks
authorIustin Pop <iustin@google.com>
Wed, 5 Jan 2011 12:56:00 +0000 (13:56 +0100)
committerIustin Pop <iustin@google.com>
Thu, 6 Jan 2011 10:33:52 +0000 (11:33 +0100)
This patch, originally written by Marc Schmitt <mschmitt@google.com>,
adds support for MD devices (used in a non-partitioned mode). I
abstracted all the original startswith('md') checks into separate
functions, and also moved the supported disk types to a list.

Proper "in-use" detection also needs another check, which will come in
a subsequent patch.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>

tools/lvmstrap

index e6856c5..2452837 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 
-# Copyright (C) 2006, 2007 Google Inc.
+# Copyright (C) 2006, 2007, 2011 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -48,6 +48,7 @@ import time
 from ganeti.utils import RunCmd, ReadFile
 from ganeti import constants
 from ganeti import cli
+from ganeti import compat
 
 USAGE = ("\tlvmstrap diskinfo\n"
          "\tlvmstrap [--vgname=NAME] [--allow-removable]"
@@ -56,6 +57,14 @@ USAGE = ("\tlvmstrap diskinfo\n"
 
 verbose_flag = False
 
+#: Supported disk types (as prefixes)
+SUPPORTED_TYPES = [
+  "hd",
+  "sd",
+  "md",
+  "ubd",
+  ]
+
 
 class Error(Exception):
   """Generic exception"""
@@ -169,6 +178,29 @@ def ParseOptions():
   return options, args
 
 
+def IsPartitioned(disk):
+  """Returns whether a given disk should be used partitioned or as-is.
+
+  Currently only md devices are used as is.
+
+  """
+  return not disk.startswith('md')
+
+
+def DeviceName(disk):
+  """Returns the appropriate device name for a disk.
+
+  For non-partitioned devices, it returns the name as is, otherwise it
+  returns the first partition.
+
+  """
+  if IsPartitioned(disk):
+    device = '/dev/%s1' % disk
+  else:
+    device = '/dev/%s' % disk
+  return device
+
+
 def ExecCommand(command):
   """Executes a command.
 
@@ -379,9 +411,7 @@ def GetDiskList(opts):
   """
   dlist = []
   for name in os.listdir("/sys/block"):
-    if (not name.startswith("hd") and
-        not name.startswith("sd") and
-        not name.startswith("ubd")):
+    if not compat.any([name.startswith(pfx) for pfx in SUPPORTED_TYPES]):
       continue
 
     size = ReadSize("/sys/block/%s" % name)
@@ -534,21 +564,33 @@ def ShowDiskInfo(opts):
 def CheckReread(name):
   """Check to see if a block device is in use.
 
-  Uses blockdev to reread the partition table of a block device, and
-  thus compute the in-use status. See the discussion in GetDiskList
-  about the meaning of 'in use'.
+  Uses blockdev to reread the partition table of a block device (or
+  fuser if the device is not partitionable), and thus compute the
+  in-use status.  See the discussion in GetDiskList about the meaning
+  of 'in use'.
 
   @rtype: boolean
   @return: the in-use status of the device
 
   """
+  use_blockdev = IsPartitioned(name)
+  if use_blockdev:
+    cmd = "blockdev --rereadpt /dev/%s" % name
+  else:
+    cmd = "fuser -vam /dev/%s" % name
+
   for _ in range(3):
-    result = ExecCommand("blockdev --rereadpt /dev/%s" % name)
-    if not result.failed:
+    result = ExecCommand(cmd)
+    if not use_blockdev and result.failed:
+      break
+    elif not result.failed:
       break
     time.sleep(2)
 
-  return not result.failed
+  if use_blockdev:
+    return not result.failed
+  else:
+    return result.failed
 
 
 def WipeDisk(name):
@@ -623,12 +665,13 @@ def CreatePVOnDisk(name):
   @param name: the device name, e.g. sda
 
   """
-  result = ExecCommand("pvcreate -yff /dev/%s1 " % name)
+  device = DeviceName(name)
+  result = ExecCommand("pvcreate -yff %s" % device)
   if result.failed:
     raise OperationalError("I cannot create a physical volume on"
-                           " partition /dev/%s1. Error message: %s."
+                           " %s. Error message: %s."
                            " Please clean up yourself." %
-                           (name, result.output))
+                           (device, result.output))
 
 
 def CreateVG(vgname, disks):
@@ -640,7 +683,7 @@ def CreateVG(vgname, disks):
   @param disks: a list of disk names, e.g. ['sda','sdb']
 
   """
-  pnames = ["'/dev/%s1'" % disk for disk in disks]
+  pnames = [DeviceName(d) for d in disks]
   result = ExecCommand("vgcreate -s 64MB '%s' %s" % (vgname, " ".join(pnames)))
   if result.failed:
     raise OperationalError("I cannot create the volume group %s from"
@@ -718,7 +761,8 @@ def BootStrap():
 
   for disk in disklist:
     WipeDisk(disk)
-    PartitionDisk(disk)
+    if IsPartitioned(disk):
+      PartitionDisk(disk)
   for disk in disklist:
     CreatePVOnDisk(disk)
   CreateVG(vgname, disklist)