ssh: more details on failure
[ganeti-local] / lib / bdev.py
index 14f1e5c..834d7b3 100644 (file)
@@ -275,7 +275,8 @@ class LogicalVolume(BlockDev):
 
     """
     if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
-      raise ValueError("Invalid configuration data %s" % str(unique_id))
+      raise errors.ProgrammerError("Invalid configuration data %s" %
+                                   str(unique_id))
     vg_name, lv_name = unique_id
     pvs_info = cls.GetPVInfo(vg_name)
     if not pvs_info:
@@ -295,8 +296,8 @@ class LogicalVolume(BlockDev):
     result = utils.RunCmd(["lvcreate", "-L%dm" % size, "-n%s" % lv_name,
                            vg_name] + pvlist)
     if result.failed:
-      raise errors.BlockDeviceError("%s - %s" % (result.fail_reason,
-                                                result.output))
+      raise errors.BlockDeviceError("LV create failed (%s): %s" %
+                                    (result.fail_reason, result.output))
     return LogicalVolume(unique_id, children)
 
   @staticmethod
@@ -539,20 +540,28 @@ class DRBD8Status(object):
   Note that this doesn't support unconfigured devices (cs:Unconfigured).
 
   """
+  UNCONF_RE = re.compile(r"\s*[0-9]+:\s*cs:Unconfigured$")
   LINE_RE = re.compile(r"\s*[0-9]+:\s*cs:(\S+)\s+st:([^/]+)/(\S+)"
                        "\s+ds:([^/]+)/(\S+)\s+.*$")
   SYNC_RE = re.compile(r"^.*\ssync'ed:\s*([0-9.]+)%.*"
                        "\sfinish: ([0-9]+):([0-9]+):([0-9]+)\s.*$")
 
   def __init__(self, procline):
-    m = self.LINE_RE.match(procline)
-    if not m:
-      raise errors.BlockDeviceError("Can't parse input data '%s'" % procline)
-    self.cstatus = m.group(1)
-    self.lrole = m.group(2)
-    self.rrole = m.group(3)
-    self.ldisk = m.group(4)
-    self.rdisk = m.group(5)
+    u = self.UNCONF_RE.match(procline)
+    if u:
+      self.cstatus = "Unconfigured"
+      self.lrole = self.rrole = self.ldisk = self.rdisk = None
+    else:
+      m = self.LINE_RE.match(procline)
+      if not m:
+        raise errors.BlockDeviceError("Can't parse input data '%s'" % procline)
+      self.cstatus = m.group(1)
+      self.lrole = m.group(2)
+      self.rrole = m.group(3)
+      self.ldisk = m.group(4)
+      self.rdisk = m.group(5)
+
+    # end reading of data from the LINE_RE or UNCONF_RE
 
     self.is_standalone = self.cstatus == "StandAlone"
     self.is_wfconn = self.cstatus == "WFConnection"
@@ -567,6 +576,9 @@ class DRBD8Status(object):
     self.is_diskless = self.ldisk == "Diskless"
     self.is_disk_uptodate = self.ldisk == "UpToDate"
 
+    self.is_in_resync = self.cstatus in ("SyncSource", "SyncTarget")
+    self.is_in_use = self.cstatus != "Unconfigured"
+
     m = self.SYNC_RE.match(procline)
     if m:
       self.sync_percent = float(m.group(1))
@@ -680,7 +692,7 @@ class BaseDRBD(BlockDev):
     return "/dev/drbd%d" % minor
 
   @classmethod
-  def _GetUsedDevs(cls):
+  def GetUsedDevs(cls):
     """Compute the list of used DRBD devices.
 
     """
@@ -836,21 +848,6 @@ class DRBD8(BaseDRBD):
     return highest + 1
 
   @classmethod
-  def _IsValidMeta(cls, meta_device):
-    """Check if the given meta device looks like a valid one.
-
-    """
-    minor = cls._FindUnusedMinor()
-    minor_path = cls._DevPath(minor)
-    result = utils.RunCmd(["drbdmeta", minor_path,
-                           "v08", meta_device, "0",
-                           "dstate"])
-    if result.failed:
-      logging.error("Invalid meta device %s: %s", meta_device, result.output)
-      return False
-    return True
-
-  @classmethod
   def _GetShowParser(cls):
     """Return a parser for `drbd show` output.
 
@@ -1011,12 +1008,7 @@ class DRBD8(BaseDRBD):
   def _AssembleLocal(cls, minor, backend, meta):
     """Configure the local part of a DRBD device.
 
-    This is the first thing that must be done on an unconfigured DRBD
-    device. And it must be done only once.
-
     """
-    if not cls._IsValidMeta(meta):
-      return False
     args = ["drbdsetup", cls._DevPath(minor), "disk",
             backend, meta, "0", "-e", "detach", "--create-device"]
     result = utils.RunCmd(args)
@@ -1097,8 +1089,6 @@ class DRBD8(BaseDRBD):
     if not self._CheckMetaSize(meta.dev_path):
       raise errors.BlockDeviceError("Invalid meta device size")
     self._InitMeta(self._FindUnusedMinor(), meta.dev_path)
-    if not self._IsValidMeta(meta.dev_path):
-      raise errors.BlockDeviceError("Cannot initalize meta device")
 
     if not self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path):
       raise errors.BlockDeviceError("Can't attach to local storage")
@@ -1331,7 +1321,7 @@ class DRBD8(BaseDRBD):
     /proc).
 
     """
-    used_devs = self._GetUsedDevs()
+    used_devs = self.GetUsedDevs()
     if self._aminor in used_devs:
       minor = self._aminor
     else:
@@ -1522,15 +1512,24 @@ class DRBD8(BaseDRBD):
     """
     if len(children) != 2:
       raise errors.ProgrammerError("Invalid setup for the drbd device")
+    # check that the minor is unused
+    aminor = unique_id[4]
+    proc_info = cls._MassageProcData(cls._GetProcData())
+    if aminor in proc_info:
+      status = DRBD8Status(proc_info[aminor])
+      in_use = status.is_in_use
+    else:
+      in_use = False
+    if in_use:
+      raise errors.BlockDeviceError("DRBD minor %d already in use at"
+                                    " Create() time" % aminor)
     meta = children[1]
     meta.Assemble()
     if not meta.Attach():
       raise errors.BlockDeviceError("Can't attach to meta device")
     if not cls._CheckMetaSize(meta.dev_path):
       raise errors.BlockDeviceError("Invalid meta device size")
-    cls._InitMeta(cls._FindUnusedMinor(), meta.dev_path)
-    if not cls._IsValidMeta(meta.dev_path):
-      raise errors.BlockDeviceError("Cannot initalize meta device")
+    cls._InitMeta(aminor, meta.dev_path)
     return cls(unique_id, children)
 
   def Grow(self, amount):
@@ -1644,16 +1643,17 @@ class FileStorage(BlockDev):
     @return: an instance of FileStorage
 
     """
+    # TODO: decide whether we should check for existing files and
+    # abort or not
     if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
       raise ValueError("Invalid configuration data %s" % str(unique_id))
     dev_path = unique_id[1]
     try:
       f = open(dev_path, 'w')
-    except IOError, err:
-      raise errors.BlockDeviceError("Could not create '%'" % err)
-    else:
       f.truncate(size * 1024 * 1024)
       f.close()
+    except IOError, err:
+      raise errors.BlockDeviceError("Error in file creation: %" % str(err))
 
     return FileStorage(unique_id, children)