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
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
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
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
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
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