Ethers hook, compatibility with old lockfile
[ganeti-local] / tools / lvmstrap
index 4d514cd..a10296e 100755 (executable)
@@ -46,9 +46,11 @@ import time
 
 from ganeti.utils import RunCmd
 from ganeti import constants
+from ganeti import cli
 
-USAGE = ("\tlvmstrap.py diskinfo\n"
-         "\tlvmstrap.py [--vgname=NAME] { --alldisks | --disks DISKLIST }"
+USAGE = ("\tlvmstrap diskinfo\n"
+         "\tlvmstrap [--vgname=NAME] [--allow-removable]"
+         " { --alldisks | --disks DISKLIST }"
          " create")
 
 verbose_flag = False
@@ -110,6 +112,7 @@ class ParameterError(Error):
   """
   pass
 
+
 def Usage():
   """Shows program usage information and exits the program."""
 
@@ -142,6 +145,9 @@ def ParseOptions():
   parser.add_option("-v", "--verbose",
                     action="store_true", dest="verbose", default=False,
                     help="print command execution messages to stdout")
+  parser.add_option("-r", "--allow-removable",
+                    action="store_true", dest="removable_ok", default=False,
+                    help="allow and use removable devices too")
   parser.add_option("-g", "--vg-name", type="string",
                     dest="vgname", default="xenvg", metavar="NAME",
                     help="the volume group to be created [default: xenvg]")
@@ -190,24 +196,24 @@ def CheckPrereq():
 
   osname, nodename, release, version, arch = os.uname()
   if osname != 'Linux':
-    raise PrereqError("This tool only runs on Linux "
-                      "(detected OS: %s)." % osname)
+    raise PrereqError("This tool only runs on Linux"
+                      " (detected OS: %s)." % osname)
 
   if not release.startswith("2.6."):
-    raise PrereqError("Wrong major kernel version (detected %s, needs "
-                      "2.6.*)" % release)
+    raise PrereqError("Wrong major kernel version (detected %s, needs"
+                      " 2.6.*)" % release)
 
   if not os.path.ismount("/sys"):
-    raise PrereqError("Can't find a filesystem mounted at /sys. "
-                      "Please mount /sys.")
+    raise PrereqError("Can't find a filesystem mounted at /sys."
+                      " Please mount /sys.")
 
   if not os.path.isdir("/sys/block"):
-    raise SysconfigError("Can't find /sys/block directory. Has the "
-                         "layout of /sys changed?")
+    raise SysconfigError("Can't find /sys/block directory. Has the"
+                         " layout of /sys changed?")
 
   if not os.path.ismount("/proc"):
-    raise PrereqError("Can't find a filesystem mounted at /proc. "
-                      "Please mount /proc.")
+    raise PrereqError("Can't find a filesystem mounted at /proc."
+                      " Please mount /proc.")
 
   if not os.path.exists("/proc/mounts"):
     raise SysconfigError("Can't find /proc/mounts")
@@ -228,9 +234,9 @@ def CheckVGExists(vgname):
       vg_free: The available space in the volume group
   """
 
-  result = ExecCommand("vgs --nohead -o lv_count,vg_size,"
-                       "vg_free --nosuffix --units g "
-                       "--ignorelockingfailure %s" % vgname)
+  result = ExecCommand("vgs --nohead -o lv_count,vg_size,vg_free"
+                       " --nosuffix --units g"
+                       " --ignorelockingfailure %s" % vgname)
   if not result.failed:
     try:
       lv_count, vg_size, vg_free = result.stdout.strip().split()
@@ -262,7 +268,7 @@ def CheckSysDev(name, devnum):
    devnum: the device number, e.g. 0x803 (2051 in decimal) for sda3
 
   Returns:
-    None; failure of the check is signalled by raising a
+    None; failure of the check is signaled by raising a
       SysconfigError exception
   """
 
@@ -272,12 +278,12 @@ def CheckSysDev(name, devnum):
       break
     time.sleep(0.250)
   else:
-    raise SysconfigError("the device file %s does not exist, but the block "
-                         "device exists in the /sys/block tree" % path)
+    raise SysconfigError("the device file %s does not exist, but the block"
+                         " device exists in the /sys/block tree" % path)
   rdev = os.stat(path).st_rdev
   if devnum != rdev:
-    raise SysconfigError("For device %s, the major:minor in /dev is %04x "
-                         "while the major:minor in sysfs is %s" %
+    raise SysconfigError("For device %s, the major:minor in /dev is %04x"
+                         " while the major:minor in sysfs is %s" %
                          (path, rdev, devnum))
 
 
@@ -352,7 +358,7 @@ def ReadPV(name):
   return vgname
 
 
-def GetDiskList():
+def GetDiskList(opts):
   """Computes the block device list for this system.
 
   This function examines the /sys/block tree and using information
@@ -385,7 +391,7 @@ def GetDiskList():
     removable = int(f.read().strip())
     f.close()
 
-    if removable:
+    if removable and not opts.removable_ok:
       continue
 
     dev = ReadDev("/sys/block/%s" % name)
@@ -444,7 +450,7 @@ def GetMountInfo():
 
 
 def DevInfo(name, dev, mountinfo):
-  """Computes miscellaneous informations about a block device.
+  """Computes miscellaneous information about a block device.
 
   Args:
     name: the device name, e.g. sda
@@ -470,20 +476,27 @@ def DevInfo(name, dev, mountinfo):
   return mpath, whatvg, fileinfo
 
 
-def ShowDiskInfo():
+def ShowDiskInfo(opts):
   """Shows a nicely formatted block device list for this system.
 
-  This function shows the user a table with the informations gathered
+  This function shows the user a table with the information gathered
   by the other functions defined, in order to help the user make a
   choice about which disks should be allocated to our volume group.
 
   """
   mounts = GetMountInfo()
-  dlist = GetDiskList()
+  dlist = GetDiskList(opts)
 
   print "------- Disk information -------"
-  print ("%5s %7s %4s %5s %-10s %s" %
-         ("Name", "Size[M]", "Used", "Mount", "LVM?", "Info"))
+  headers = {
+      "name": "Name",
+      "size": "Size[M]",
+      "used": "Used",
+      "mount": "Mount",
+      "lvm": "LVM?",
+      "info": "Info"
+      }
+  fields = ["name", "size", "used", "mount", "lvm", "info"]
 
   flatlist = []
   # Flatten the [(disk, [partition,...]), ...] list
@@ -496,6 +509,7 @@ def ShowDiskInfo():
     for partname, partsize, partdev in parts:
       flatlist.append((partname, partsize, partdev, ""))
 
+  strlist = []
   for name, size, dev, in_use in flatlist:
     mp, vgname, fileinfo = DevInfo(name, dev, mounts)
     if mp is None:
@@ -510,8 +524,15 @@ def ShowDiskInfo():
     if len(name) > 3:
       # Indent partitions
       name = " %s" % name
-    print ("%-5s %7.2f %-4s %-5s %-10s %s" %
-           (name, float(size) / 1024 / 1024, in_use, mp, lvminfo, fileinfo))
+
+    strlist.append([name, "%.2f" % (float(size) / 1024 / 1024),
+                    in_use, mp, lvminfo, fileinfo])
+
+  data = cli.GenerateTable(headers, fields, None,
+                           strlist, numfields=["size"])
+
+  for line in data:
+    print line
 
 
 def CheckReread(name):
@@ -546,14 +567,14 @@ def WipeDisk(name):
   """
 
   if not CheckReread(name):
-    raise OperationalError("CRITICAL: disk %s you selected seems to be in "
-                           "use. ABORTING!" % name)
+    raise OperationalError("CRITICAL: disk %s you selected seems to be in"
+                           " use. ABORTING!" % name)
 
   fd = os.open("/dev/%s" % name, os.O_RDWR | os.O_SYNC)
   olddata = os.read(fd, 512)
   if len(olddata) != 512:
-    raise OperationalError("CRITICAL: Can't read partition table information "
-                           "from /dev/%s (needed 512 bytes, got %d" %
+    raise OperationalError("CRITICAL: Can't read partition table information"
+                           " from /dev/%s (needed 512 bytes, got %d" %
                            (name, len(olddata)))
   newdata = "\0" * 512
   os.lseek(fd, 0, 0)
@@ -561,19 +582,19 @@ def WipeDisk(name):
   os.close(fd)
   if bytes_written != 512:
     raise OperationalError("CRITICAL: Can't write partition table information"
-                           " to /dev/%s (tried to write 512 bytes, written "
-                           "%d. I don't know how to cleanup. Sorry." %
+                           " to /dev/%s (tried to write 512 bytes, written"
+                           " %d. I don't know how to cleanup. Sorry." %
                            (name, bytes_written))
 
   if not CheckReread(name):
     fd = os.open("/dev/%s" % name, os.O_RDWR | os.O_SYNC)
     os.write(fd, olddata)
     os.close(fd)
-    raise OperationalError("CRITICAL: disk %s which I have just wiped cannot "
-                           "reread partition table. Most likely, it is "
-                           "in use. You have to clean after this yourself. "
-                           "I tried to restore the old partition table, "
-                           "but I cannot guarantee nothing has broken." %
+    raise OperationalError("CRITICAL: disk %s which I have just wiped cannot"
+                           " reread partition table. Most likely, it is"
+                           " in use. You have to clean after this yourself."
+                           " I tried to restore the old partition table,"
+                           " but I cannot guarantee nothing has broken." %
                            name)
 
 
@@ -589,11 +610,11 @@ def PartitionDisk(name):
   result = ExecCommand(
     'echo ,,8e, | sfdisk /dev/%s' % name)
   if result.failed:
-    raise OperationalError("CRITICAL: disk %s which I have just partitioned "
-                           "cannot reread its partition table, or there "
-                           "is some other sfdisk error. Likely, it is in "
-                           "use. You have to clean this yourself. Error "
-                           "message from sfdisk: %s" %
+    raise OperationalError("CRITICAL: disk %s which I have just partitioned"
+                           " cannot reread its partition table, or there"
+                           " is some other sfdisk error. Likely, it is in"
+                           " use. You have to clean this yourself. Error"
+                           " message from sfdisk: %s" %
                            (name, result.output))
 
 
@@ -609,9 +630,9 @@ def CreatePVOnDisk(name):
   """
   result = ExecCommand("pvcreate -yff /dev/%s1 " % name)
   if result.failed:
-    raise OperationalError("I cannot create a physical volume on "
-                           "partition /dev/%s1. Error message: %s. "
-                           "Please clean up yourself." %
+    raise OperationalError("I cannot create a physical volume on"
+                           " partition /dev/%s1. Error message: %s."
+                           " Please clean up yourself." %
                            (name, result.output))
 
 
@@ -628,9 +649,9 @@ def CreateVG(vgname, disks):
   pnames = ["'/dev/%s1'" % disk for disk 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 "
-                           "disks %s. Error message: %s. Please clean up "
-                           "yourself." %
+    raise OperationalError("I cannot create the volume group %s from"
+                           " disks %s. Error message: %s. Please clean up"
+                           " yourself." %
                            (vgname, " ".join(disks), result.output))
 
 
@@ -649,10 +670,10 @@ def ValidateDiskList(options):
     a list of disk names, e.g. ['sda', 'sdb']
   """
 
-  sysdisks = GetDiskList()
+  sysdisks = GetDiskList(options)
   if not sysdisks:
-    raise PrereqError("no disks found (I looked for "
-                      "non-removable block devices).")
+    raise PrereqError("no disks found (I looked for"
+                      " non-removable block devices).")
   sysd_free = []
   sysd_used = []
   for name, size, dev, part, used in sysdisks:
@@ -678,6 +699,7 @@ def ValidateDiskList(options):
 
   return disklist
 
+
 def BootStrap():
   """Actual main routine."""
 
@@ -687,7 +709,7 @@ def BootStrap():
   vgname = options.vgname
   command = args.pop(0)
   if command == "diskinfo":
-    ShowDiskInfo()
+    ShowDiskInfo(options)
     return
   if command != "create":
     Usage()
@@ -711,10 +733,10 @@ def BootStrap():
   status, lv_count, size, free = CheckVGExists(vgname)
   if status:
     print "Done! %s: size %s GiB, disks: %s" % (vgname, size,
-                                                ",".join(disklist))
+                                              ",".join(disklist))
   else:
-    raise OperationalError("Although everything seemed ok, the volume "
-                           "group did not get created.")
+    raise OperationalError("Although everything seemed ok, the volume"
+                           " group did not get created.")
 
 
 def main():
@@ -727,34 +749,34 @@ def main():
     BootStrap()
   except PrereqError, err:
     print >> sys.stderr, "The prerequisites for running this tool are not met."
-    print >> sys.stderr, ("Please make sure you followed all the steps in "
-                          "the build document.")
+    print >> sys.stderr, ("Please make sure you followed all the steps in"
+                          " the build document.")
     print >> sys.stderr, "Description: %s" % str(err)
     sys.exit(1)
   except SysconfigError, err:
-    print >> sys.stderr, ("This system's configuration seems wrong, at "
-                          "least is not what I expect.")
-    print >> sys.stderr, ("Please check that the installation didn't fail "
-                          "at some step.")
+    print >> sys.stderr, ("This system's configuration seems wrong, at"
+                          " least is not what I expect.")
+    print >> sys.stderr, ("Please check that the installation didn't fail"
+                          " at some step.")
     print >> sys.stderr, "Description: %s" % str(err)
     sys.exit(1)
   except ParameterError, err:
-    print >> sys.stderr, ("Some parameters you gave to the program or the "
-                          "invocation is wrong. ")
+    print >> sys.stderr, ("Some parameters you gave to the program or the"
+                          " invocation is wrong. ")
     print >> sys.stderr, "Description: %s" % str(err)
     Usage()
   except OperationalError, err:
-    print >> sys.stderr, ("A serious error has happened while modifying "
-                          "the system's configuration.")
-    print >> sys.stderr, ("Please review the error message below and make "
-                          "sure you clean up yourself.")
-    print >> sys.stderr, ("It is most likely that the system configuration "
-                          "has been partially altered.")
+    print >> sys.stderr, ("A serious error has happened while modifying"
+                          " the system's configuration.")
+    print >> sys.stderr, ("Please review the error message below and make"
+                          " sure you clean up yourself.")
+    print >> sys.stderr, ("It is most likely that the system configuration"
+                          " has been partially altered.")
     print >> sys.stderr, str(err)
     sys.exit(1)
   except ProgrammingError, err:
-    print >> sys.stderr, ("Internal application error. Please signal this "
-                          "to xencluster-team.")
+    print >> sys.stderr, ("Internal application error. Please signal this"
+                          " to xencluster-team.")
     print >> sys.stderr, "Error description: %s" % str(err)
     sys.exit(1)
   except Error, err: