diff options
author | Andy Grover <agrover@redhat.com> | 2012-06-12 07:46:48 -0700 |
---|---|---|
committer | Andy Grover <agrover@redhat.com> | 2012-06-12 07:46:48 -0700 |
commit | 37b7be38b68855c613548105385d191bc35973bf (patch) | |
tree | 4f44960ea6be9cf1b8044cb317755c67788a7ca6 | |
parent | de8a7566aba0a76b683b1989df0e216b03e2b0ad (diff) | |
download | rtslib-fb-broken-worktree.tar.gz |
-rw-r--r-- | rtslib/__init__.py | 2 | ||||
-rw-r--r-- | rtslib/root.py | 29 | ||||
-rw-r--r-- | rtslib/tcm.py | 377 |
3 files changed, 178 insertions, 230 deletions
diff --git a/rtslib/__init__.py b/rtslib/__init__.py index 18ad7bb..7d9cfd0 100644 --- a/rtslib/__init__.py +++ b/rtslib/__init__.py @@ -23,9 +23,7 @@ from utils import RTSLibError, RTSLibBrokenLink, RTSLibNotInCFS from target import LUN, MappedLUN from target import NodeACL, NetworkPortal, TPG, Target, FabricModule -from tcm import FileIOBackstore, BlockBackstore from tcm import FileIOStorageObject, BlockStorageObject -from tcm import PSCSIBackstore, RDMCPBackstore from tcm import PSCSIStorageObject, RDMCPStorageObject __version__ = 'GIT_VERSION' diff --git a/rtslib/root.py b/rtslib/root.py index 5f18279..fa5311a 100644 --- a/rtslib/root.py +++ b/rtslib/root.py @@ -22,15 +22,17 @@ import os from node import CFSNode from target import Target, FabricModule -from tcm import Backstore, FileIOBackstore, BlockBackstore -from tcm import PSCSIBackstore, RDMCPBackstore +from tcm import Backstore +from tcm import (FileIOStorageObject, BlockStorageObject, + PSCSIStorageObject, RDMCPStorageObject) from utils import RTSLibError, RTSLibBrokenLink, modprobe +from utils import dict_remove, set_attributes -backstores = dict( - fileio=FileIOBackstore, - block=BlockBackstore, - pscsi=PSCSIBackstore, - ramdisk=RDMCPBackstore, +storageobjects = dict( + fileio=FileIOStorageObject, + block=BlockStorageObject, + pscsi=PSCSIStorageObject, + ramdisk=RDMCPStorageObject, ) class RTSRoot(CFSNode): @@ -182,13 +184,18 @@ class RTSRoot(CFSNode): errors = 0 - for index, so in enumerate(config.get('storage_objects', [])): - # We need to create a Backstore object for each StorageObject + for so in config.get('storage_objects', []): if 'plugin' not in so: errors += 1 continue - bs_obj = backstores[so['plugin']](index) - errors += bs_obj._storage_object_class.setup(bs_obj, **so) + so_cls = storageobjects[so['plugin']] + kwargs = so.copy() + dict_remove(kwargs, ('exists', 'attributes', 'plugin')) + try: + so_obj = so_cls(**kwargs) + set_attributes(so_obj, so.get('attributes', {})) + except (RTSLibError, TypeError): + errors += 1 # config was broken, but keep going # Don't need to create fabric modules for fm_obj in self.fabric_modules: diff --git a/rtslib/tcm.py b/rtslib/tcm.py index f4c5154..2e51f97 100644 --- a/rtslib/tcm.py +++ b/rtslib/tcm.py @@ -27,174 +27,6 @@ from utils import fread, fwrite, RTSLibError, list_scsi_hbas, generate_wwn from utils import convert_scsi_path_to_hctl, convert_scsi_hctl_to_path from utils import is_dev_in_use, get_block_type from utils import is_disk_partition, get_disk_size -from utils import dict_remove, set_attributes - -class Backstore(CFSNode): - - # Backstore private stuff - - def __init__(self, plugin, storage_class, mode, index=None, alt_dirprefix=None): - super(Backstore, self).__init__() - if issubclass(storage_class, StorageObject): - self._storage_object_class = storage_class - self._plugin = plugin - else: - raise RTSLibError("StorageClass must derive from StorageObject.") - - if index == None: - self._index = self._next_hba_index(self.configfs_dir) - else: - try: - self._index = int(index) - except ValueError: - raise RTSLibError("Invalid backstore index: %s" % index) - - if alt_dirprefix: - dirp = alt_dirprefix - else: - dirp = plugin - self._path = "%s/core/%s_%d" % (self.configfs_dir, - dirp, - self._index) - self._create_in_cfs_ine(mode) - - @classmethod - def all(cls, path): - mapping = dict( - fileio=FileIOBackstore, - pscsi=PSCSIBackstore, - iblock=BlockBackstore, - rd_mcp=RDMCPBackstore, - ) - for name, index in cls._hbas(path): - yield mapping[name](int(index), 'lookup') - - @classmethod - def _next_hba_index(cls, path): - indexes = [int(y) for x, y in cls._hbas(path)] - for index in xrange(1048576): - if index not in indexes: - return index - else: - raise ExecutionError("Cannot find an available backstore index.") - - @classmethod - def _hbas(cls, path): - if os.path.isdir("%s/core" % path): - backstore_dirs = glob.glob("%s/core/*_*" % path) - for backstore_dir in [os.path.basename(path) - for path in backstore_dirs]: - regex = re.search("([a-z]+[_]*[a-z]+)(_)([0-9]+)", - backstore_dir) - if regex: - yield(regex.group(1), regex.group(3)) - - def _get_index(self): - return self._index - - def _list_storage_objects(self): - self._check_self() - storage_object_names = [os.path.basename(s) - for s in os.listdir(self.path) - if s not in set(["hba_info", "hba_mode"])] - - for storage_object_name in storage_object_names: - yield self._storage_object_class(self, storage_object_name) - - def _create_in_cfs_ine(self, mode): - try: - super(Backstore, self)._create_in_cfs_ine(mode) - except OSError, msg: - raise RTSLibError("Cannot create backstore: %s" % msg) - - def _parse_info(self, key): - self._check_self() - info = fread("%s/hba_info" % self.path) - return re.search(".*%s: ([^: ]+).*" \ - % key, ' '.join(info.split())).group(1).lower() - - def _get_version(self): - self._check_self() - return self._parse_info("version") - - def _get_plugin(self): - self._check_self() - return self._plugin - - def _get_name(self): - self._check_self() - return "%s%d" % (self.plugin, self.index) - - # Backstore public stuff - - def delete(self): - ''' - Recursively deletes a Backstore object. - This will delete all attached StorageObject objects, and then the - Backstore itself. The underlying file and block storages will not be - touched, but all ramdisk data will be lost. - ''' - self._check_self() - for storage in self.storage_objects: - storage.delete() - super(Backstore, self).delete() - - plugin = property(_get_plugin, - doc="Get the backstore plugin name.") - index = property(_get_index, - doc="Get the backstore index as an int.") - storage_objects = property(_list_storage_objects, - doc="Get the list of StorageObjects attached to the backstore.") - version = property(_get_version, - doc="Get the Backstore plugin version string.") - name = property(_get_name, - doc="Get the backstore name.") - - def dump(self): - d = super(Backstore, self).dump() - d['storage_objects'] = [so.dump() for so in self.storage_objects] - d['plugin'] = self.plugin - d['name'] = self.name - return d - - -class PSCSIBackstore(Backstore): - ''' - This is an interface to pscsi backstore plugin objects in configFS. - A PSCSIBackstore object is identified by its backstore index. - ''' - - # PSCSIBackstore private stuff - - def __init__(self, index=None, mode='any'): - ''' - @param index: The backstore index matching a physical SCSI HBA. - @type index: int - @param mode: An optional string containing the object creation mode: - - I{'any'} the configFS object will be either lookuped or created. - - I{'lookup'} the object MUST already exist configFS. - - I{'create'} the object must NOT already exist in configFS. - @type mode:string - @return: A PSCSIBackstore object. - ''' - super(PSCSIBackstore, self).__init__("pscsi", - PSCSIStorageObject, - mode, index) - -class RDMCPBackstore(Backstore): - def __init__(self, index=None, mode='any'): - super(RDMCPBackstore, self).__init__("ramdisk", RDMCPStorageObject, - mode, index, alt_dirprefix="rd_mcp") - -class FileIOBackstore(Backstore): - def __init__(self, index=None, mode='any'): - super(FileIOBackstore, self).__init__("fileio", FileIOStorageObject, - mode, index) - -class BlockBackstore(Backstore): - def __init__(self, index=None, mode='any'): - super(BlockBackstore, self).__init__("block", BlockStorageObject, - mode, index, alt_dirprefix="iblock") class StorageObject(CFSNode): @@ -204,14 +36,14 @@ class StorageObject(CFSNode): ''' # StorageObject private stuff - def __init__(self, backstore_class, name, mode): + def __init__(self, name, mode): super(StorageObject, self).__init__() - self._backstore = backstore_class() if "/" in name or " " in name or "\t" in name or "\n" in name: raise RTSLibError("A storage object's name cannot contain " " /, newline or spaces/tabs.") else: self._name = name + self._backstore = Backstore(self, mode) self._path = "%s/%s" % (self.backstore.path, self.name) self._create_in_cfs_ine(mode) @@ -364,23 +196,6 @@ class StorageObject(CFSNode): attached_luns = property(_list_attached_luns, doc="Get the list of all LUN objects attached.") - @classmethod - def setup(cls, bs_obj, **so): - ''' - Set up storage objects based upon so dict, from saved config. - Guard against missing or bad dict items, but keep going. - Returns how many recoverable errors happened. - ''' - errors = 0 - kwargs = so.copy() - dict_remove(kwargs, ('exists', 'attributes', 'plugin')) - try: - so_obj = bs_obj._storage_object_class(bs_obj, **kwargs) - set_attributes(so_obj, so.get('attributes', {})) - except (RTSLibError, TypeError): - errors += 1 # config was broken, but keep going - return errors - def dump(self): d = super(StorageObject, self).dump() d['name'] = self.name @@ -400,11 +215,11 @@ class PSCSIStorageObject(StorageObject): A PSCSIStorageObject can be instanciated in two ways: - B{Creation mode}: If I{dev} is specified, the underlying configFS object will be created with that parameter. No PSCSIStorageObject - with the same I{name} can pre-exist in the parent PSCSIBackstore + with the same I{name} can pre-exist in the parent Backstore in that mode, or instanciation will fail. - B{Lookup mode}: If I{dev} is not set, then the PSCSIStorageObject will be bound to the existing configFS object in the parent - PSCSIBackstore having the specified I{name}. The underlying + Backstore having the specified I{name}. The underlying configFS object must already exist in that mode, or instanciation will fail. @@ -417,16 +232,14 @@ class PSCSIStorageObject(StorageObject): @return: A PSCSIStorageObject object. ''' if dev is not None: - super(PSCSIStorageObject, self).__init__(PSCSIBackstore, - name, 'create') + super(PSCSIStorageObject, self).__init__(name, 'create') try: self._configure(dev) except: self.delete() raise else: - super(PSCSIStorageObject, self).__init__(PSCSIBackstore, - name, 'lookup') + super(PSCSIStorageObject, self).__init__(name, 'lookup') def _configure(self, dev): self._check_self() @@ -538,10 +351,10 @@ class RDMCPStorageObject(StorageObject): - B{Creation mode}: If I{size} is specified, the underlying configFS object will be created with that parameter. No RDMCPStorageObject with the same I{name} can pre-exist in the - parent RDMCPBackstore in that mode, or instanciation will fail. + parent Backstore in that mode, or instanciation will fail. - B{Lookup mode}: If I{size} is not set, then the RDMCPStorageObject will be bound to the existing configFS object - in the parent RDMCPBackstore having the specified I{name}. + in the parent Backstore having the specified I{name}. The underlying configFS object must already exist in that mode, or instanciation will fail. @@ -568,18 +381,14 @@ class RDMCPStorageObject(StorageObject): ''' if size is not None: - super(RDMCPStorageObject, self).__init__(RDMCPBackstore, - name, - 'create') + super(RDMCPStorageObject, self).__init__(name, 'create') try: self._configure(size, wwn) except: self.delete() raise else: - super(RDMCPStorageObject, self).__init__(RDMCPBackstore, - name, - 'lookup') + super(RDMCPStorageObject, self).__init__(name, 'lookup') def _configure(self, size, wwn): self._check_self() @@ -636,10 +445,10 @@ class FileIOStorageObject(StorageObject): - B{Creation mode}: If I{dev} and I{size} are specified, the underlying configFS object will be created with those parameters. No FileIOStorageObject with the same I{name} can pre-exist in the - parent FileIOBackstore in that mode, or instanciation will fail. + parent Backstore in that mode, or instanciation will fail. - B{Lookup mode}: If I{dev} and I{size} are not set, then the FileIOStorageObject will be bound to the existing configFS object - in the parent FileIOBackstore having the specified I{name}. + in the parent Backstore having the specified I{name}. The underlying configFS object must already exist in that mode, or instanciation will fail. @@ -674,18 +483,14 @@ class FileIOStorageObject(StorageObject): ''' if dev is not None: - super(FileIOStorageObject, self).__init__(FileIOBackstore, - name, - 'create') + super(FileIOStorageObject, self).__init__(name, 'create') try: self._configure(dev, size, wwn, buffered_mode) except: self.delete() raise else: - super(FileIOStorageObject, self).__init__(FileIOBackstore, - name, - 'lookup') + super(FileIOStorageObject, self).__init__(name, 'lookup') def _configure(self, dev, size, wwn, buffered_mode): self._check_self() @@ -789,10 +594,10 @@ class BlockStorageObject(StorageObject): - B{Creation mode}: If I{dev} is specified, the underlying configFS object will be created with that parameter. No BlockIOStorageObject with the same I{name} can pre-exist in - the parent BlockIOBackstore in that mode. + the parent Backstore in that mode. - B{Lookup mode}: If I{dev} is not set, then the BlockIOStorageObject will be bound to the existing configFS - object in the parent BlockIOBackstore having the specified + object in the parent Backstore having the specified I{name}. The underlying configFS object must already exist in that mode, or instanciation will fail. @@ -809,18 +614,14 @@ class BlockStorageObject(StorageObject): ''' if dev is not None: - super(BlockStorageObject, self).__init__(BlockBackstore, - name, - 'create') + super(BlockStorageObject, self).__init__(name, 'create') try: self._configure(dev, wwn) except: self.delete() raise else: - super(BlockStorageObject, self).__init__(BlockBackstore, - name, - 'lookup') + super(BlockStorageObject, self).__init__(name, 'lookup') def _configure(self, dev, wwn): self._check_self() @@ -866,6 +667,148 @@ class BlockStorageObject(StorageObject): return d +bs_params = { + PSCSIStorageObject: dict(name='pscsi'), + RDMCPStorageObject: dict(name='ramdisk', alt_dirprefix='rd_mcp'), + FileIOStorageObject: dict(name='fileio'), + BlockStorageObject: dict(name='block', alt_dirprefix='iblock'), + } + + +class Backstore(CFSNode): + """ + Needed as a level in the configfs hierarchy, but otherwise useless. + 1:1 so:backstore. + Created by so ctor before storageobject configfs entry. + """ + + def __init__(self, storage_object, mode): + super(Backstore, self).__init__() + self._so_cls = type(storage_object) + self._plugin = bs_params[self._so_cls]['name'] + self._index = None + + if mode == 'lookup': + backstore_dirs = glob.glob("%s/core/%s_*" % (self.path, self._plugin)) + for backstore_dir in [os.path.basename(path) + for path in backstore_dirs]: + regex = re.search("([a-z]+[_]*[a-z]+)(_)([0-9]+)", + backstore_dir) + if regex: + print "woot!", regex.group(3) + if os.path.isdir("%s/core/%s_%s/%s" % + (self.configfs_path, self._plugin, regex.group(3), storage_object.name)): + self._index = int(regex.group(3)) + + if self._index == None: + self._index = self._next_hba_index(self.configfs_dir) + + dirp = bs_params[self._so_cls].get("alt_dirprefix", self._plugin) + self._path = "%s/core/%s_%d" % (self.configfs_dir, + dirp, + self._index) + self._create_in_cfs_ine(mode) + + @classmethod + def all(cls, path): + mapping = dict( + fileio=FileIOStorageObject, + pscsi=PSCSIStorageObject, + iblock=BlockStorageObject, + rd_mcp=RDMCPStorageObject, + ) + for name, index in cls._hbas(path): + yield Backstore(mapping[name], 'lookup') + + @classmethod + def _next_hba_index(cls, path): + indexes = [int(y) for x, y in cls._hbas(path)] + for index in xrange(1048576): + if index not in indexes: + return index + else: + raise ExecutionError("Cannot find an available backstore index.") + + @classmethod + def _hbas(cls, path): + if os.path.isdir("%s/core" % path): + backstore_dirs = glob.glob("%s/core/*_*" % path) + for backstore_dir in [os.path.basename(path) + for path in backstore_dirs]: + regex = re.search("([a-z]+[_]*[a-z]+)(_)([0-9]+)", + backstore_dir) + if regex: + yield(regex.group(1), regex.group(3)) + + def _get_index(self): + return self._index + + def _list_storage_objects(self): + self._check_self() + storage_object_names = [os.path.basename(s) + for s in os.listdir(self.path) + if s not in set(["hba_info", "hba_mode"])] + + for storage_object_name in storage_object_names: + yield self._so_cls(storage_object_name) + + def _create_in_cfs_ine(self, mode): + try: + super(Backstore, self)._create_in_cfs_ine(mode) + except OSError, msg: + raise RTSLibError("Cannot create backstore: %s" % msg) + + def _parse_info(self, key): + self._check_self() + info = fread("%s/hba_info" % self.path) + return re.search(".*%s: ([^: ]+).*" \ + % key, ' '.join(info.split())).group(1).lower() + + def _get_version(self): + self._check_self() + return self._parse_info("version") + + def _get_plugin(self): + self._check_self() + return self._plugin + + def _get_name(self): + self._check_self() + return "%s%d" % (self.plugin, self.index) + + # Backstore public stuff + + def delete(self): + ''' + Recursively deletes a Backstore object. + This will delete all attached StorageObject objects, and then the + Backstore itself. The underlying file and block storages will not be + touched, but all ramdisk data will be lost. + ''' + self._check_self() + for storage in self.storage_objects: + storage.delete() + super(Backstore, self).delete() + + plugin = property(_get_plugin, + doc="Get the backstore plugin name.") + index = property(_get_index, + doc="Get the backstore index as an int.") + storage_objects = property(_list_storage_objects, + doc="Get the list of StorageObjects attached to the backstore.") + version = property(_get_version, + doc="Get the Backstore plugin version string.") + name = property(_get_name, + doc="Get the backstore name.") + + def dump(self): + d = super(Backstore, self).dump() + d['storage_objects'] = [so.dump() for so in self.storage_objects] + d['plugin'] = self.plugin + d['name'] = self.name + return d + + def _test(): import doctest doctest.testmod() |