예제 #1
0
파일: bdev.py 프로젝트: oleeander/ganeti
  def Attach(self):
    """Attach to an existing rbd device.

    This method maps the rbd volume that matches our name with
    an rbd device and then attaches to this device.

    """
    self.attached = False

    # Map the rbd volume to a block device under /dev
    self.dev_path = self._MapVolumeToBlockdev(self.unique_id)

    try:
      st = os.stat(self.dev_path)
    except OSError as err:
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
      return False

    if not stat.S_ISBLK(st.st_mode):
      logging.error("%s is not a block device", self.dev_path)
      return False

    self.major = os.major(st.st_rdev)
    self.minor = utils.osminor(st.st_rdev)
    self.attached = True

    return True
예제 #2
0
파일: bdev.py 프로젝트: ganeti/ganeti
  def Attach(self):
    """Attach to an existing rbd device.

    This method maps the rbd volume that matches our name with
    an rbd device and then attaches to this device.

    """
    self.attached = False

    # Map the rbd volume to a block device under /dev
    self.dev_path = self._MapVolumeToBlockdev(self.unique_id)

    try:
      st = os.stat(self.dev_path)
    except OSError as err:
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
      return False

    if not stat.S_ISBLK(st.st_mode):
      logging.error("%s is not a block device", self.dev_path)
      return False

    self.major = os.major(st.st_rdev)
    self.minor = utils.osminor(st.st_rdev)
    self.attached = True

    return True
예제 #3
0
  def Attach(self, **kwargs):
    """Attach to an existing extstorage device.

    This method maps the extstorage volume that matches our name with
    a corresponding block device and then attaches to this device.

    """
    self.attached = False

    # Call the External Storage's attach script,
    # to attach an existing Volume to a block device under /dev
    result = _ExtStorageAction(constants.ES_ACTION_ATTACH,
                               self.unique_id, self.ext_params,
                               name=self.name, uuid=self.uuid)

    # Attach script returns the block device path and optionally
    # the URIs to be used for userspace access (one URI for
    # each hypervisor supported).
    # If the provider doesn't support userspace access, then
    # the 'uris' variable will be an empty list.
    result = result.split("\n")
    self.dev_path = result[0]
    self.uris = result[1:]

    if not self.dev_path:
      logging.info("A local block device is not available")
      self.dev_path = None
      if not self.uris:
        logging.error("Neither a block device nor a userspace URI is available")
        return False

      self.attached = True
      return True

    # Verify that dev_path exists and is a block device
    try:
      st = os.stat(self.dev_path)
    except OSError as err:
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
      return False

    if not stat.S_ISBLK(st.st_mode):
      logging.error("%s is not a block device", self.dev_path)
      return False

    self.major = os.major(st.st_rdev)
    self.minor = utils.osminor(st.st_rdev)
    self.attached = True

    return True
예제 #4
0
파일: bdev.py 프로젝트: oleeander/ganeti
  def Attach(self):
    """Attach to an existing block device.

    """
    self.attached = False
    try:
      st = os.stat(self.dev_path)
    except OSError as err:
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
      return False

    if not stat.S_ISBLK(st.st_mode):
      logging.error("%s is not a block device", self.dev_path)
      return False

    self.major = os.major(st.st_rdev)
    self.minor = utils.osminor(st.st_rdev)
    self.attached = True

    return True
예제 #5
0
파일: bdev.py 프로젝트: ganeti/ganeti
  def Attach(self):
    """Attach to an existing block device.

    """
    self.attached = False
    try:
      st = os.stat(self.dev_path)
    except OSError as err:
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
      return False

    if not stat.S_ISBLK(st.st_mode):
      logging.error("%s is not a block device", self.dev_path)
      return False

    self.major = os.major(st.st_rdev)
    self.minor = utils.osminor(st.st_rdev)
    self.attached = True

    return True
예제 #6
0
class RADOSBlockDevice(base.BlockDev):
  """A RADOS Block Device (rbd).

  This class implements the RADOS Block Device for the backend. You need
  the rbd kernel driver, the RADOS Tools and a working RADOS cluster for
  this to be functional.

  """
  def __init__(self, unique_id, children, size, params, dyn_params, *args):
    """Attaches to an rbd device.

    """
    super(RADOSBlockDevice, self).__init__(unique_id, children, size, params,
                                           dyn_params, *args)
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
      raise ValueError("Invalid configuration data %s" % str(unique_id))

    self.driver, self.rbd_name = unique_id
    self.rbd_pool = params[constants.LDP_POOL]

    self.major = self.minor = None
    self.Attach()

  @classmethod
  def Create(cls, unique_id, children, size, spindles, params, excl_stor,
             dyn_params, *args):
    """Create a new rbd device.

    Provision a new rbd volume inside a RADOS pool.

    """
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
      raise errors.ProgrammerError("Invalid configuration data %s" %
                                   str(unique_id))
    if excl_stor:
      raise errors.ProgrammerError("RBD device requested with"
                                   " exclusive_storage")
    rbd_pool = params[constants.LDP_POOL]
    rbd_name = unique_id[1]

    # Provision a new rbd volume (Image) inside the RADOS cluster.
    cmd = [constants.RBD_CMD, "create", "-p", rbd_pool,
           rbd_name, "--size", "%s" % size]
    result = utils.RunCmd(cmd)
    if result.failed:
      base.ThrowError("rbd creation failed (%s): %s",
                      result.fail_reason, result.output)

    return RADOSBlockDevice(unique_id, children, size, params, dyn_params,
                            *args)

  def Remove(self):
    """Remove the rbd device.

    """
    rbd_pool = self.params[constants.LDP_POOL]
    rbd_name = self.unique_id[1]

    if not self.minor and not self.Attach():
      # The rbd device doesn't exist.
      return

    # First shutdown the device (remove mappings).
    self.Shutdown()

    # Remove the actual Volume (Image) from the RADOS cluster.
    cmd = [constants.RBD_CMD, "rm", "-p", rbd_pool, rbd_name]
    result = utils.RunCmd(cmd)
    if result.failed:
      base.ThrowError("Can't remove Volume from cluster with rbd rm: %s - %s",
                      result.fail_reason, result.output)

  def Rename(self, new_id):
    """Rename this device.

    """
    pass

  def Attach(self):
    """Attach to an existing rbd device.

    This method maps the rbd volume that matches our name with
    an rbd device and then attaches to this device.

    """
    self.attached = False

    # Map the rbd volume to a block device under /dev
    self.dev_path = self._MapVolumeToBlockdev(self.unique_id)

    try:
      st = os.stat(self.dev_path)
    except OSError, err:
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
      return False

    if not stat.S_ISBLK(st.st_mode):
      logging.error("%s is not a block device", self.dev_path)
      return False

    self.major = os.major(st.st_rdev)
    self.minor = utils.osminor(st.st_rdev)
    self.attached = True

    return True
예제 #7
0
class PersistentBlockDevice(base.BlockDev):
  """A block device with persistent node

  May be either directly attached, or exposed through DM (e.g. dm-multipath).
  udev helpers are probably required to give persistent, human-friendly
  names.

  For the time being, pathnames are required to lie under /dev.

  """
  def __init__(self, unique_id, children, size, params, dyn_params, *args):
    """Attaches to a static block device.

    The unique_id is a path under /dev.

    """
    super(PersistentBlockDevice, self).__init__(unique_id, children, size,
                                                params, dyn_params, *args)
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
      raise ValueError("Invalid configuration data %s" % str(unique_id))
    self.dev_path = unique_id[1]
    if not os.path.realpath(self.dev_path).startswith("/dev/"):
      raise ValueError("Full path '%s' lies outside /dev" %
                              os.path.realpath(self.dev_path))
    # TODO: this is just a safety guard checking that we only deal with devices
    # we know how to handle. In the future this will be integrated with
    # external storage backends and possible values will probably be collected
    # from the cluster configuration.
    if unique_id[0] != constants.BLOCKDEV_DRIVER_MANUAL:
      raise ValueError("Got persistent block device of invalid type: %s" %
                       unique_id[0])

    self.major = self.minor = None
    self.Attach()

  @classmethod
  def Create(cls, unique_id, children, size, spindles, params, excl_stor,
             dyn_params, *args):
    """Create a new device

    This is a noop, we only return a PersistentBlockDevice instance

    """
    if excl_stor:
      raise errors.ProgrammerError("Persistent block device requested with"
                                   " exclusive_storage")
    return PersistentBlockDevice(unique_id, children, 0, params, dyn_params,
                                 *args)

  def Remove(self):
    """Remove a device

    This is a noop

    """
    pass

  def Rename(self, new_id):
    """Rename this device.

    """
    base.ThrowError("Rename is not supported for PersistentBlockDev storage")

  def Attach(self):
    """Attach to an existing block device.


    """
    self.attached = False
    try:
      st = os.stat(self.dev_path)
    except OSError, err:
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
      return False

    if not stat.S_ISBLK(st.st_mode):
      logging.error("%s is not a block device", self.dev_path)
      return False

    self.major = os.major(st.st_rdev)
    self.minor = utils.osminor(st.st_rdev)
    self.attached = True

    return True
예제 #8
0
class ExtStorageDevice(base.BlockDev):
    """A block device provided by an ExtStorage Provider.

  This class implements the External Storage Interface, which means
  handling of the externally provided block devices.

  """
    def __init__(self, unique_id, children, size, params, dyn_params, *args):
        """Attaches to an extstorage block device.

    """
        super(ExtStorageDevice, self).__init__(unique_id, children, size,
                                               params, dyn_params, *args)
        (self.name, self.uuid) = args

        if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
            raise ValueError("Invalid configuration data %s" % str(unique_id))

        self.driver, self.vol_name = unique_id
        self.ext_params = params

        self.major = self.minor = None
        self.uris = []
        self.Attach()

    @classmethod
    def Create(cls, unique_id, children, size, spindles, params, excl_stor,
               dyn_params, *args):
        """Create a new extstorage device.

    Provision a new volume using an extstorage provider, which will
    then be mapped to a block device.

    """
        (name, uuid) = args

        if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
            raise errors.ProgrammerError("Invalid configuration data %s" %
                                         str(unique_id))
        if excl_stor:
            raise errors.ProgrammerError("extstorage device requested with"
                                         " exclusive_storage")

        # Call the External Storage's create script,
        # to provision a new Volume inside the External Storage
        _ExtStorageAction(constants.ES_ACTION_CREATE,
                          unique_id,
                          params,
                          size=size,
                          name=name,
                          uuid=uuid)

        return ExtStorageDevice(unique_id, children, size, params, dyn_params,
                                *args)

    def Remove(self):
        """Remove the extstorage device.

    """
        if not self.minor and not self.Attach():
            # The extstorage device doesn't exist.
            return

        # First shutdown the device (remove mappings).
        self.Shutdown()

        # Call the External Storage's remove script,
        # to remove the Volume from the External Storage
        _ExtStorageAction(constants.ES_ACTION_REMOVE,
                          self.unique_id,
                          self.ext_params,
                          name=self.name,
                          uuid=self.uuid)

    def Rename(self, new_id):
        """Rename this device.

    """
        pass

    def Attach(self):
        """Attach to an existing extstorage device.

    This method maps the extstorage volume that matches our name with
    a corresponding block device and then attaches to this device.

    """
        self.attached = False

        # Call the External Storage's attach script,
        # to attach an existing Volume to a block device under /dev
        result = _ExtStorageAction(constants.ES_ACTION_ATTACH,
                                   self.unique_id,
                                   self.ext_params,
                                   name=self.name,
                                   uuid=self.uuid)

        # Attach script returns the block device path and optionally
        # the URIs to be used for userspace access (one URI for
        # each hypervisor supported).
        # If the provider doesn't support userspace access, then
        # the 'uris' variable will be an empty list.
        result = result.split("\n")
        self.dev_path = result[0]
        self.uris = result[1:]

        # Verify that dev_path exists and is a block device
        try:
            st = os.stat(self.dev_path)
        except OSError, err:
            logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
            return False

        if not stat.S_ISBLK(st.st_mode):
            logging.error("%s is not a block device", self.dev_path)
            return False

        self.major = os.major(st.st_rdev)
        self.minor = utils.osminor(st.st_rdev)
        self.attached = True

        return True