Split DRBD8Dev into DRBD8 and DRBD8Dev
authorThomas Thrainer <thomasth@google.com>
Thu, 25 Apr 2013 07:21:52 +0000 (09:21 +0200)
committerThomas Thrainer <thomasth@google.com>
Mon, 6 May 2013 08:47:43 +0000 (10:47 +0200)
All functionality specific to a single DRBD8 devide is now in DRBD8Dev,
whereas functionality which is valid for the whole DRBD "installation"
on a device is collected in DRBD8.

This makes it possible to remove a couple of FIXME's and clarifies the
code in some areas.

Signed-off-by: Thomas Thrainer <thomasth@google.com>
Reviewed-by: Helga Velroyen <helgav@google.com>

lib/backend.py
lib/block/base.py
lib/block/drbd.py
lib/bootstrap.py
lib/watcher/nodemaint.py
test/py/ganeti.block.drbd_unittest.py

index 147f35c..dc13b02 100644 (file)
@@ -66,7 +66,7 @@ from ganeti import pathutils
 from ganeti import vcluster
 from ganeti import ht
 from ganeti.block.base import BlockDev
-from ganeti.block.drbd_info import DRBD8Info
+from ganeti.block.drbd import DRBD8
 from ganeti import hooksmaster
 
 
@@ -833,7 +833,7 @@ def VerifyNode(what, cluster_name):
 
   if constants.NV_DRBDVERSION in what and vm_capable:
     try:
-      drbd_version = DRBD8Info.CreateFromFile().GetVersionString()
+      drbd_version = DRBD8.GetProcInfo().GetVersionString()
     except errors.BlockDeviceError, err:
       logging.warning("Can't get DRBD version", exc_info=True)
       drbd_version = str(err)
@@ -841,7 +841,7 @@ def VerifyNode(what, cluster_name):
 
   if constants.NV_DRBDLIST in what and vm_capable:
     try:
-      used_minors = drbd.DRBD8Dev.GetUsedDevs()
+      used_minors = drbd.DRBD8.GetUsedDevs()
     except errors.BlockDeviceError, err:
       logging.warning("Can't get used minors list", exc_info=True)
       used_minors = str(err)
@@ -850,7 +850,7 @@ def VerifyNode(what, cluster_name):
   if constants.NV_DRBDHELPER in what and vm_capable:
     status = True
     try:
-      payload = drbd.DRBD8Dev.GetUsermodeHelper()
+      payload = drbd.DRBD8.GetUsermodeHelper()
     except errors.BlockDeviceError, err:
       logging.error("Can't get DRBD usermode helper: %s", str(err))
       status = False
@@ -3692,7 +3692,7 @@ def GetDrbdUsermodeHelper():
 
   """
   try:
-    return drbd.DRBD8Dev.GetUsermodeHelper()
+    return drbd.DRBD8.GetUsermodeHelper()
   except errors.BlockDeviceError, err:
     _Fail(str(err))
 
index 7e6449e..d07705d 100644 (file)
@@ -149,6 +149,8 @@ class BlockDev(object):
     The force parameter signifies that if the device has any kind of
     --force thing, it should be used, we know what we are doing.
 
+    @type force: boolean
+
     """
     raise NotImplementedError
 
@@ -185,6 +187,7 @@ class BlockDev(object):
 
     In case this is not a mirroring device, this is no-op.
 
+    @type pause: boolean
     @param pause: Whether to pause or resume
 
     """
index 3912f3d..65274f3 100644 (file)
@@ -32,8 +32,7 @@ from ganeti import netutils
 from ganeti import objects
 from ganeti.block import base
 from ganeti.block.drbd_info import DRBD8Info
-from ganeti.block.drbd_info import DRBD83ShowInfo
-from ganeti.block.drbd_info import DRBD84ShowInfo
+from ganeti.block import drbd_info
 from ganeti.block import drbd_cmdgen
 
 
@@ -42,6 +41,121 @@ from ganeti.block import drbd_cmdgen
 _DEVICE_READ_SIZE = 128 * 1024
 
 
+class DRBD8(object):
+  """Various methods to deals with the DRBD system as a whole.
+
+  This class provides a set of methods to deal with the DRBD installation on
+  the node or with uninitialized devices as opposed to a DRBD device.
+
+  """
+  _USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper"
+
+  _MAX_MINORS = 255
+
+  @staticmethod
+  def GetUsermodeHelper(filename=_USERMODE_HELPER_FILE):
+    """Returns DRBD usermode_helper currently set.
+
+    @type filename: string
+    @param filename: the filename to read the usermode helper from
+    @rtype: string
+    @return: the currently configured DRBD usermode helper
+
+    """
+    try:
+      helper = utils.ReadFile(filename).splitlines()[0]
+    except EnvironmentError, err:
+      if err.errno == errno.ENOENT:
+        base.ThrowError("The file %s cannot be opened, check if the module"
+                        " is loaded (%s)", filename, str(err))
+      else:
+        base.ThrowError("Can't read DRBD helper file %s: %s",
+                        filename, str(err))
+    if not helper:
+      base.ThrowError("Can't read any data from %s", filename)
+    return helper
+
+  @staticmethod
+  def GetProcInfo():
+    """Reads and parses information from /proc/drbd.
+
+    @rtype: DRBD8Info
+    @return: a L{DRBD8Info} instance containing the current /proc/drbd info
+
+    """
+    return DRBD8Info.CreateFromFile()
+
+  @staticmethod
+  def GetUsedDevs():
+    """Compute the list of used DRBD minors.
+
+    @rtype: list of ints
+
+    """
+    info = DRBD8.GetProcInfo()
+    return filter(lambda m: not info.GetMinorStatus(m).is_unconfigured,
+                  info.GetMinors())
+
+  @staticmethod
+  def FindUnusedMinor():
+    """Find an unused DRBD device.
+
+    This is specific to 8.x as the minors are allocated dynamically,
+    so non-existing numbers up to a max minor count are actually free.
+
+    @rtype: int
+
+    """
+    highest = None
+    info = DRBD8.GetProcInfo()
+    for minor in info.GetMinors():
+      status = info.GetMinorStatus(minor)
+      if not status.is_in_use:
+        return minor
+      highest = max(highest, minor)
+
+    if highest is None: # there are no minors in use at all
+      return 0
+    if highest >= DRBD8._MAX_MINORS:
+      logging.error("Error: no free drbd minors!")
+      raise errors.BlockDeviceError("Can't find a free DRBD minor")
+
+    return highest + 1
+
+  @staticmethod
+  def GetCmdGenerator(info):
+    """Creates a suitable L{BaseDRBDCmdGenerator} based on the given info.
+
+    @type info: DRBD8Info
+    @rtype: BaseDRBDCmdGenerator
+
+    """
+    version = info.GetVersion()
+    if version["k_minor"] <= 3:
+      return drbd_cmdgen.DRBD83CmdGenerator(version)
+    else:
+      return drbd_cmdgen.DRBD84CmdGenerator(version)
+
+  @staticmethod
+  def ShutdownAll(minor):
+    """Deactivate the device.
+
+    This will, of course, fail if the device is in use.
+
+    @type minor: int
+    @param minor: the minor to shut down
+
+    """
+    info = DRBD8.GetProcInfo()
+    cmd_gen = DRBD8.GetCmdGenerator(info)
+
+    cmd = cmd_gen.GenDownCmd(minor)
+    result = utils.RunCmd(cmd)
+    if result.failed:
+      base.ThrowError("drbd%d: can't shutdown drbd device: %s",
+                      minor, result.output)
+
+
 class DRBD8Dev(base.BlockDev):
   """DRBD v8.x block device.
 
@@ -57,10 +171,6 @@ class DRBD8Dev(base.BlockDev):
   """
   _DRBD_MAJOR = 147
 
-  _USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper"
-
-  _MAX_MINORS = 255
-
   # timeout constants
   _NET_RECONFIG_TIMEOUT = 60
 
@@ -81,19 +191,19 @@ class DRBD8Dev(base.BlockDev):
     super(DRBD8Dev, self).__init__(unique_id, children, size, params)
     self.major = self._DRBD_MAJOR
 
-    drbd_info = DRBD8Info.CreateFromFile()
-    version = drbd_info.GetVersion()
+    info = DRBD8.GetProcInfo()
+    version = info.GetVersion()
     if version["k_major"] != 8:
       base.ThrowError("Mismatch in DRBD kernel version and requested ganeti"
                       " usage: kernel is %s.%s, ganeti wants 8.x",
                       version["k_major"], version["k_minor"])
 
     if version["k_minor"] <= 3:
-      self._show_info_cls = DRBD83ShowInfo
+      self._show_info_cls = drbd_info.DRBD83ShowInfo
     else:
-      self._show_info_cls = DRBD84ShowInfo
+      self._show_info_cls = drbd_info.DRBD84ShowInfo
 
-    self._cmd_gen = self._GetCmdGenerator(drbd_info)
+    self._cmd_gen = DRBD8.GetCmdGenerator(info)
 
     if (self._lhost is not None and self._lhost == self._rhost and
             self._lport == self._rport):
@@ -101,53 +211,23 @@ class DRBD8Dev(base.BlockDev):
                        (unique_id,))
     self.Attach()
 
-  @classmethod
-  def _GetCmdGenerator(cls, drbd_info):
-    version = drbd_info.GetVersion()
-    if version["k_minor"] <= 3:
-      return drbd_cmdgen.DRBD83CmdGenerator(version)
-    else:
-      return drbd_cmdgen.DRBD84CmdGenerator(version)
-
-  @staticmethod
-  def GetUsermodeHelper(filename=_USERMODE_HELPER_FILE):
-    """Returns DRBD usermode_helper currently set.
-
-    """
-    try:
-      helper = utils.ReadFile(filename).splitlines()[0]
-    except EnvironmentError, err:
-      if err.errno == errno.ENOENT:
-        base.ThrowError("The file %s cannot be opened, check if the module"
-                        " is loaded (%s)", filename, str(err))
-      else:
-        base.ThrowError("Can't read DRBD helper file %s: %s",
-                        filename, str(err))
-    if not helper:
-      base.ThrowError("Can't read any data from %s", filename)
-    return helper
-
   @staticmethod
   def _DevPath(minor):
     """Return the path to a drbd device for a given minor.
 
-    """
-    return "/dev/drbd%d" % minor
-
-  @classmethod
-  def GetUsedDevs(cls):
-    """Compute the list of used DRBD devices.
+    @type minor: int
+    @rtype: string
 
     """
-    drbd_info = DRBD8Info.CreateFromFile()
-    return filter(lambda m: not drbd_info.GetMinorStatus(m).is_unconfigured,
-                  drbd_info.GetMinors())
+    return "/dev/drbd%d" % minor
 
   def _SetFromMinor(self, minor):
     """Set our parameters based on the given minor.
 
     This sets our minor variable and our dev_path.
 
+    @type minor: int
+
     """
     if minor is None:
       self.minor = self.dev_path = None
@@ -164,6 +244,9 @@ class DRBD8Dev(base.BlockDev):
     This currently only checks the size, which must be around
     128MiB.
 
+    @type meta_device: string
+    @param meta_device: the path to the device to check
+
     """
     result = utils.RunCmd(["blockdev", "--getsize", meta_device])
     if result.failed:
@@ -187,58 +270,12 @@ class DRBD8Dev(base.BlockDev):
       base.ThrowError("Meta device too big (%.2fMiB)",
                       (num_bytes / 1024 / 1024))
 
-  @classmethod
-  def _InitMeta(cls, minor, dev_path):
-    """Initialize a meta device.
-
-    This will not work if the given minor is in use.
-
-    """
-    # Zero the metadata first, in order to make sure drbdmeta doesn't
-    # try to auto-detect existing filesystems or similar (see
-    # http://code.google.com/p/ganeti/issues/detail?id=182); we only
-    # care about the first 128MB of data in the device, even though it
-    # can be bigger
-    result = utils.RunCmd([constants.DD_CMD,
-                           "if=/dev/zero", "of=%s" % dev_path,
-                           "bs=1048576", "count=128", "oflag=direct"])
-    if result.failed:
-      base.ThrowError("Can't wipe the meta device: %s", result.output)
-
-    drbd_info = DRBD8Info.CreateFromFile()
-    cmd_gen = cls._GetCmdGenerator(drbd_info)
-    cmd = cmd_gen.GenInitMetaCmd(minor, dev_path)
-
-    result = utils.RunCmd(cmd)
-    if result.failed:
-      base.ThrowError("Can't initialize meta device: %s", result.output)
-
-  def _FindUnusedMinor(self):
-    """Find an unused DRBD device.
-
-    This is specific to 8.x as the minors are allocated dynamically,
-    so non-existing numbers up to a max minor count are actually free.
-
-    """
-
-    highest = None
-    drbd_info = DRBD8Info.CreateFromFile()
-    for minor in drbd_info.GetMinors():
-      status = drbd_info.GetMinorStatus(minor)
-      if not status.is_in_use:
-        return minor
-      highest = max(highest, minor)
-
-    if highest is None: # there are no minors in use at all
-      return 0
-    if highest >= self._MAX_MINORS:
-      logging.error("Error: no free drbd minors!")
-      raise errors.BlockDeviceError("Can't find a free DRBD minor")
-
-    return highest + 1
-
   def _GetShowData(self, minor):
-    """Return the `drbdsetup show` data for a minor.
+    """Return the `drbdsetup show` data.
+
+    @type minor: int
+    @param minor: the minor to collect show output for
+    @rtype: string
 
     """
     result = utils.RunCmd(self._cmd_gen.GenShowCmd(minor))
@@ -249,16 +286,26 @@ class DRBD8Dev(base.BlockDev):
     return result.stdout
 
   def _GetShowInfo(self, minor):
+    """Return parsed information from `drbdsetup show`.
+
+    @type minor: int
+    @param minor: the minor to return information for
+    @rtype: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
+
+    """
     return self._show_info_cls.GetDevInfo(self._GetShowData(minor))
 
   def _MatchesLocal(self, info):
     """Test if our local config matches with an existing device.
 
-    The parameter should be as returned from `_GetDevInfo()`. This
+    The parameter should be as returned from `_GetShowInfo()`. This
     method tests if our local backing device is the same as the one in
     the info parameter, in effect testing if we look like the given
     device.
 
+    @type info: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
+    @rtype: boolean
+
     """
     if self._children:
       backend, meta = self._children
@@ -283,11 +330,14 @@ class DRBD8Dev(base.BlockDev):
   def _MatchesNet(self, info):
     """Test if our network config matches with an existing device.
 
-    The parameter should be as returned from `_GetDevInfo()`. This
+    The parameter should be as returned from `_GetShowInfo()`. This
     method tests if our network configuration is the same as the one
     in the info parameter, in effect testing if we look like the given
     device.
 
+    @type info: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
+    @rtype: boolean
+
     """
     if (((self._lhost is None and not ("local_addr" in info)) and
          (self._rhost is None and not ("remote_addr" in info)))):
@@ -308,6 +358,15 @@ class DRBD8Dev(base.BlockDev):
   def _AssembleLocal(self, minor, backend, meta, size):
     """Configure the local part of a DRBD device.
 
+    @type minor: int
+    @param minor: the minor to assemble locally
+    @type backend: string
+    @param backend: path to the data device to use
+    @type meta: string
+    @param meta: path to the meta device to use
+    @type size: int
+    @param size: size in MiB
+
     """
     cmds = self._cmd_gen.GenLocalInitCmds(minor, backend, meta,
                                           size, self.params)
@@ -322,6 +381,20 @@ class DRBD8Dev(base.BlockDev):
                    dual_pri=False, hmac=None, secret=None):
     """Configure the network part of the device.
 
+    @type minor: int
+    @param minor: the minor to assemble the network for
+    @type net_info: (string, int, string, int)
+    @param net_info: tuple containing the local address, local port, remote
+      address and remote port
+    @type protocol: string
+    @param protocol: either "ipv4" or "ipv6"
+    @type dual_pri: boolean
+    @param dual_pri: whether two primaries should be allowed or not
+    @type hmac: string
+    @param hmac: the HMAC algorithm to use
+    @type secret: string
+    @param secret: the shared secret to use
+
     """
     lhost, lport, rhost, rport = net_info
     if None in net_info:
@@ -384,6 +457,10 @@ class DRBD8Dev(base.BlockDev):
   def AddChildren(self, devices):
     """Add a disk to the DRBD device.
 
+    @type devices: list of L{BlockDev}
+    @param devices: a list of exactly two L{BlockDev} objects; the first
+      denotes the data device, the second the meta device for this DRBD device
+
     """
     if self.minor is None:
       base.ThrowError("drbd%d: can't attach to dbrd8 during AddChildren",
@@ -400,7 +477,7 @@ class DRBD8Dev(base.BlockDev):
     backend.Open()
     meta.Open()
     self._CheckMetaSize(meta.dev_path)
-    self._InitMeta(self._FindUnusedMinor(), meta.dev_path)
+    self._InitMeta(DRBD8.FindUnusedMinor(), meta.dev_path)
 
     self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path, self.size)
     self._children = devices
@@ -408,6 +485,10 @@ class DRBD8Dev(base.BlockDev):
   def RemoveChildren(self, devices):
     """Detach the drbd device from local storage.
 
+    @type devices: list of L{BlockDev}
+    @param devices: a list of exactly two L{BlockDev} objects; the first
+      denotes the data device, the second the meta device for this DRBD device
+
     """
     if self.minor is None:
       base.ThrowError("drbd%d: can't attach to drbd8 during RemoveChildren",
@@ -459,11 +540,7 @@ class DRBD8Dev(base.BlockDev):
   def SetSyncParams(self, params):
     """Set the synchronization parameters of the DRBD syncer.
 
-    @type params: dict
-    @param params: LD level disk parameters related to the synchronization
-    @rtype: list
-    @return: a list of error messages, emitted both by the current node and by
-    children. An empty list means no errors
+    See L{BlockDev.SetSyncParams} for parameter description.
 
     """
     if self.minor is None:
@@ -478,8 +555,7 @@ class DRBD8Dev(base.BlockDev):
   def PauseResumeSync(self, pause):
     """Pauses or resumes the sync of a DRBD device.
 
-    @param pause: Wether to pause or resume
-    @return: the success of the operation
+    See L{BlockDev.PauseResumeSync} for parameter description.
 
     """
     if self.minor is None:
@@ -500,26 +576,26 @@ class DRBD8Dev(base.BlockDev):
     return not result.failed and children_result
 
   def GetProcStatus(self):
-    """Return device data from /proc.
+    """Return the current status data from /proc/drbd for this device.
+
+    @rtype: DRBD8Status
 
     """
     if self.minor is None:
       base.ThrowError("drbd%d: GetStats() called while not attached",
                       self._aminor)
-    drbd_info = DRBD8Info.CreateFromFile()
-    if not drbd_info.HasMinorStatus(self.minor):
+    info = DRBD8.GetProcInfo()
+    if not info.HasMinorStatus(self.minor):
       base.ThrowError("drbd%d: can't find myself in /proc", self.minor)
-    return drbd_info.GetMinorStatus(self.minor)
+    return info.GetMinorStatus(self.minor)
 
   def GetSyncStatus(self):
     """Returns the sync status of the device.
 
-
     If sync_percent is None, it means all is ok
     If estimated_time is None, it means we can't estimate
     the time needed, otherwise it's the time left in seconds.
 
-
     We set the is_degraded parameter to True on two conditions:
     network not connected or local disk missing.
 
@@ -553,10 +629,10 @@ class DRBD8Dev(base.BlockDev):
   def Open(self, force=False):
     """Make the local state primary.
 
-    If the 'force' parameter is given, the '-o' option is passed to
-    drbdsetup. Since this is a potentially dangerous operation, the
-    force flag should be only given after creation, when it actually
-    is mandatory.
+    If the 'force' parameter is given, DRBD is instructed to switch the device
+    into primary mode. Since this is a potentially dangerous operation, the
+    force flag should be only given after creation, when it actually is
+    mandatory.
 
     """
     if self.minor is None and not self.Attach():
@@ -653,8 +729,8 @@ class DRBD8Dev(base.BlockDev):
     specified multi-master flag. The device needs to be 'Standalone'
     but have valid network configuration data.
 
-    Args:
-      - multimaster: init the network in dual-primary mode
+    @type multimaster: boolean
+    @param multimaster: init the network in dual-primary mode
 
     """
     if self.minor is None:
@@ -685,7 +761,7 @@ class DRBD8Dev(base.BlockDev):
     /proc).
 
     """
-    used_devs = self.GetUsedDevs()
+    used_devs = DRBD8.GetUsedDevs()
     if self._aminor in used_devs:
       minor = self._aminor
     else:
@@ -818,6 +894,9 @@ class DRBD8Dev(base.BlockDev):
     I/Os will continue to be served from the remote device. If we
     don't have a remote device, this operation will fail.
 
+    @type minor: int
+    @param minor: the device to detach from the local device
+
     """
     cmd = self._cmd_gen.GenDetachCmd(minor)
     result = utils.RunCmd(cmd)
@@ -830,6 +909,9 @@ class DRBD8Dev(base.BlockDev):
 
     This fails if we don't have a local device.
 
+    @type minor: boolean
+    @param minor: the device to disconnect from the remote peer
+
     """
     family = self._GetNetFamily(minor, self._lhost, self._rhost)
     cmd = self._cmd_gen.GenDisconnectCmd(minor, family,
@@ -840,25 +922,6 @@ class DRBD8Dev(base.BlockDev):
       base.ThrowError("drbd%d: can't shutdown network: %s",
                       minor, result.output)
 
-  @classmethod
-  def _ShutdownAll(cls, minor):
-    """Deactivate the device.
-
-    This will, of course, fail if the device is in use.
-
-    """
-    # FIXME: _ShutdownAll, despite being private, is used in nodemaint.py.
-    # That's why we can't make it an instance method, which in turn requires
-    # us to duplicate code here (from __init__). This should be properly fixed.
-    drbd_info = DRBD8Info.CreateFromFile()
-    cmd_gen = cls._GetCmdGenerator(drbd_info)
-
-    cmd = cmd_gen.GenDownCmd(minor)
-    result = utils.RunCmd(cmd)
-    if result.failed:
-      base.ThrowError("drbd%d: can't shutdown drbd device: %s",
-                      minor, result.output)
-
   def Shutdown(self):
     """Shutdown the DRBD device.
 
@@ -869,7 +932,7 @@ class DRBD8Dev(base.BlockDev):
     minor = self.minor
     self.minor = None
     self.dev_path = None
-    self._ShutdownAll(minor)
+    DRBD8.ShutdownAll(minor)
 
   def Remove(self):
     """Stub remove for DRBD devices.
@@ -885,6 +948,58 @@ class DRBD8Dev(base.BlockDev):
     """
     raise errors.ProgrammerError("Can't rename a drbd device")
 
+  def Grow(self, amount, dryrun, backingstore):
+    """Resize the DRBD device and its backing storage.
+
+    See L{BlockDev.Grow} for parameter description.
+
+    """
+    if self.minor is None:
+      base.ThrowError("drbd%d: Grow called while not attached", self._aminor)
+    if len(self._children) != 2 or None in self._children:
+      base.ThrowError("drbd%d: cannot grow diskless device", self.minor)
+    self._children[0].Grow(amount, dryrun, backingstore)
+    if dryrun or backingstore:
+      # DRBD does not support dry-run mode and is not backing storage,
+      # so we'll return here
+      return
+    cmd = self._cmd_gen.GenResizeCmd(self.minor, self.size + amount)
+    result = utils.RunCmd(cmd)
+    if result.failed:
+      base.ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
+
+  @classmethod
+  def _InitMeta(cls, minor, dev_path):
+    """Initialize a meta device.
+
+    This will not work if the given minor is in use.
+
+    @type minor: int
+    @param minor: the DRBD minor whose (future) meta device should be
+      initialized
+    @type dev_path: string
+    @param dev_path: path to the meta device to initialize
+
+    """
+    # Zero the metadata first, in order to make sure drbdmeta doesn't
+    # try to auto-detect existing filesystems or similar (see
+    # http://code.google.com/p/ganeti/issues/detail?id=182); we only
+    # care about the first 128MB of data in the device, even though it
+    # can be bigger
+    result = utils.RunCmd([constants.DD_CMD,
+                           "if=/dev/zero", "of=%s" % dev_path,
+                           "bs=1048576", "count=128", "oflag=direct"])
+    if result.failed:
+      base.ThrowError("Can't wipe the meta device: %s", result.output)
+
+    info = DRBD8.GetProcInfo()
+    cmd_gen = DRBD8.GetCmdGenerator(info)
+    cmd = cmd_gen.GenInitMetaCmd(minor, dev_path)
+
+    result = utils.RunCmd(cmd)
+    if result.failed:
+      base.ThrowError("Can't initialize meta device: %s", result.output)
+
   @classmethod
   def Create(cls, unique_id, children, size, params, excl_stor):
     """Create a new DRBD8 device.
@@ -901,9 +1016,9 @@ class DRBD8Dev(base.BlockDev):
     # check that the minor is unused
     aminor = unique_id[4]
 
-    drbd_info = DRBD8Info.CreateFromFile()
-    if drbd_info.HasMinorStatus(aminor):
-      status = drbd_info.GetMinorStatus(aminor)
+    info = DRBD8.GetProcInfo()
+    if info.HasMinorStatus(aminor):
+      status = info.GetMinorStatus(aminor)
       in_use = status.is_in_use
     else:
       in_use = False
@@ -919,30 +1034,14 @@ class DRBD8Dev(base.BlockDev):
     cls._InitMeta(aminor, meta.dev_path)
     return cls(unique_id, children, size, params)
 
-  def Grow(self, amount, dryrun, backingstore):
-    """Resize the DRBD device and its backing storage.
-
-    """
-    if self.minor is None:
-      base.ThrowError("drbd%d: Grow called while not attached", self._aminor)
-    if len(self._children) != 2 or None in self._children:
-      base.ThrowError("drbd%d: cannot grow diskless device", self.minor)
-    self._children[0].Grow(amount, dryrun, backingstore)
-    if dryrun or backingstore:
-      # DRBD does not support dry-run mode and is not backing storage,
-      # so we'll return here
-      return
-    cmd = self._cmd_gen.GenResizeCmd(self.minor, self.size + amount)
-    result = utils.RunCmd(cmd)
-    if result.failed:
-      base.ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
-
 
 def _CanReadDevice(path):
   """Check if we can read from the given device.
 
   This tries to read the first 128k of the device.
 
+  @type path: string
+
   """
   try:
     utils.ReadFile(path, size=_DEVICE_READ_SIZE)
index fba3315..d648c77 100644 (file)
@@ -470,7 +470,7 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913, R0914
 
   if drbd_helper is not None:
     try:
-      curr_helper = drbd.DRBD8Dev.GetUsermodeHelper()
+      curr_helper = drbd.DRBD8.GetUsermodeHelper()
     except errors.BlockDeviceError, err:
       raise errors.OpPrereqError("Error while checking drbd helper"
                                  " (specify --no-drbd-storage if you are not"
index ed4157e..c3b82c0 100644 (file)
@@ -80,7 +80,7 @@ class NodeMaintenance(object):
     """Get list of used DRBD minors.
 
     """
-    return drbd.DRBD8Dev.GetUsedDevs()
+    return drbd.DRBD8.GetUsedDevs()
 
   @classmethod
   def DoMaintenance(cls, role):
@@ -121,10 +121,7 @@ class NodeMaintenance(object):
       logging.info("Following DRBD minors should not be active,"
                    " shutting them down: %s", utils.CommaJoin(drbd_running))
       for minor in drbd_running:
-        # pylint: disable=W0212
-        # using the private method as is, pending enhancements to the DRBD
-        # interface
-        drbd.DRBD8Dev._ShutdownAll(minor)
+        drbd.DRBD8.ShutdownAll(minor)
 
   def Exec(self):
     """Check node status versus cluster desired state.
index ace363f..fcba8ee 100755 (executable)
@@ -295,7 +295,7 @@ class TestDRBD8Status(testutils.GanetiTestCase):
   def testHelper(self):
     """Test reading usermode_helper in /sys."""
     sys_drbd_helper = testutils.TestDataFilename("sys_drbd_usermode_helper.txt")
-    drbd_helper = drbd.DRBD8Dev.GetUsermodeHelper(filename=sys_drbd_helper)
+    drbd_helper = drbd.DRBD8.GetUsermodeHelper(filename=sys_drbd_helper)
     self.failUnlessEqual(drbd_helper, "/bin/true")
 
   def testHelperIOErrors(self):
@@ -303,7 +303,7 @@ class TestDRBD8Status(testutils.GanetiTestCase):
     temp_file = self._CreateTempFile()
     os.unlink(temp_file)
     self.failUnlessRaises(errors.BlockDeviceError,
-                          drbd.DRBD8Dev.GetUsermodeHelper, filename=temp_file)
+                          drbd.DRBD8.GetUsermodeHelper, filename=temp_file)
 
   def testMinorNotFound(self):
     """Test not-found-minor in /proc"""
@@ -401,7 +401,7 @@ class TestDRBD8Construction(testutils.GanetiTestCase):
 
     self.test_unique_id = ("hosta.com", 123, "host2.com", 123, 0, "secret")
 
-  @testutils.patch_object(drbd_info.DRBD8Info, "CreateFromFile")
+  @testutils.patch_object(drbd.DRBD8, "GetProcInfo")
   def testConstructionWith80Data(self, mock_create_from_file):
     mock_create_from_file.return_value = self.proc80_info
 
@@ -409,7 +409,7 @@ class TestDRBD8Construction(testutils.GanetiTestCase):
     self.assertEqual(inst._show_info_cls, drbd_info.DRBD83ShowInfo)
     self.assertTrue(isinstance(inst._cmd_gen, drbd_cmdgen.DRBD83CmdGenerator))
 
-  @testutils.patch_object(drbd_info.DRBD8Info, "CreateFromFile")
+  @testutils.patch_object(drbd.DRBD8, "GetProcInfo")
   def testConstructionWith83Data(self, mock_create_from_file):
     mock_create_from_file.return_value = self.proc83_info
 
@@ -417,7 +417,7 @@ class TestDRBD8Construction(testutils.GanetiTestCase):
     self.assertEqual(inst._show_info_cls, drbd_info.DRBD83ShowInfo)
     self.assertTrue(isinstance(inst._cmd_gen, drbd_cmdgen.DRBD83CmdGenerator))
 
-  @testutils.patch_object(drbd_info.DRBD8Info, "CreateFromFile")
+  @testutils.patch_object(drbd.DRBD8, "GetProcInfo")
   def testConstructionWith84Data(self, mock_create_from_file):
     mock_create_from_file.return_value = self.proc84_info