[PATCH 22/24] Improve configfile error handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Handle valid json configfiles that are broken in other ways. Do not
abort loading the config if possible, but skip the bad section and
continue.

Move utility functions to utils.

Push code to parse dicts out of root.py into target/tcm.py, in setup()
methods.

Signed-off-by: Andy Grover <agrover@xxxxxxxxxx>
---
 rtslib/root.py   |   85 ++++++++++++++++-------------------------------------
 rtslib/target.py |   66 ++++++++++++++++++++++++++++++++++++++++++
 rtslib/tcm.py    |   18 +++++++++++
 rtslib/utils.py  |   14 +++++++++
 4 files changed, 124 insertions(+), 59 deletions(-)

diff --git a/rtslib/root.py b/rtslib/root.py
index 2e3a10d..f02dc3a 100644
--- a/rtslib/root.py
+++ b/rtslib/root.py
@@ -22,7 +22,7 @@ import os
 import glob
 
 from node import CFSNode
-from target import Target, FabricModule, TPG, MappedLUN, LUN, NetworkPortal, NodeACL
+from target import Target, FabricModule
 from tcm import FileIOBackstore, BlockBackstore
 from tcm import PSCSIBackstore, RDMCPBackstore
 from utils import RTSLibError, RTSLibBrokenLink, modprobe
@@ -187,77 +187,44 @@ class RTSRoot(CFSNode):
     def restore(self, config, clear_existing=False):
         '''
         Takes a dict generated by dump() and reconfigures the target to match.
+        Returns int reflecting how many non-fatal errors were encountered.
         '''
         if clear_existing:
             self.clear_existing(confirm=True)
-
-        if not clear_existing and (list(self.storage_objects) or list(self.targets)):
+        elif list(self.storage_objects) or list(self.targets):
             raise RTSLibError("backstores or targets present, not restoring." +
                               " Set clear_existing=True?")
 
-        def del_if_there(d, items):
-            for item in items:
-                if item in d:
-                    del d[item]
-
-        def set_attributes(obj, attr_dict):
-            for name, value in attr_dict.iteritems():
-                try:
-                    obj.set_attribute(name, value)
-                except RTSLibError:
-                    # Setting some attributes may return an error, before kernel 3.3
-                    pass
+        errors = 0
 
-        for index, so in enumerate(config['storage_objects']):
+        for index, so in enumerate(config.get('storage_objects', [])):
             # We need to create a Backstore object for each StorageObject
+            if 'plugin' not in so:
+                errors += 1
+                continue
             bs_obj = backstores[so['plugin']](index)
+            errors += bs_obj._storage_object_class.setup(bs_obj, **so)
+
+        # Don't need to create fabric modules
+        for fm_obj in self.fabric_modules:
+            for fm in config.get('fabric_modules', []):
+                if fm['name'] == fm_obj.name:
+                    errors += fm_obj.setup(fm)
+
+        for t in config.get('targets', []):
+            if 'fabric' not in t:
+                errors += 1
+                continue
+            if t['fabric'] not in (f.name for f in self.fabric_modules):
+                errors += 1
+                continue
 
-            # Instantiate storageobject
-            kwargs = so.copy()
-            del_if_there(kwargs, ('exists', 'attributes', 'plugin'))
-            so_obj = bs_obj._storage_object_class(bs_obj, **kwargs)
-            set_attributes(so_obj, so['attributes'])
-
-        for fm in config['fabric_modules']:
-            # will not have config for FMs that don't support discovery_auth
-            fm_obj = FabricModule(fm['name'])
-            del fm['name']
-            for name, value in fm.iteritems():
-                setattr(fm_obj, name, value)
-
-        for t in config['targets']:
             fm_obj = FabricModule(t['fabric'])
 
             # Instantiate target
-            t_obj = Target(fm_obj, t.get('wwn'))
-
-            for tpg in t['tpgs']:
-                tpg_obj = TPG(t_obj)
-                set_attributes(tpg_obj, tpg['attributes'])
-
-                for lun in tpg['luns']:
-                    bs_name, so_name = lun['storage_object'].split('/')[2:]
-                    match_so = [x for x in self.storage_objects if so_name == x.name]
-                    match_so = [x for x in match_so if bs_name == x.backstore.plugin]
-                    if len(match_so) != 1:
-                        raise RTSLibError("Can't find storage object %s" %
-                                          lun['storage_object'])
-                    lun_obj = LUN(tpg_obj, lun.get('index'), storage_object=match_so[0])
-
-                for p in tpg['portals']:
-                    NetworkPortal(tpg_obj, p['ip_address'], p['port'])
-
-                for acl in tpg['node_acls']:
-                    acl_obj = NodeACL(tpg_obj, acl['node_wwn'])
-                    set_attributes(tpg_obj, tpg['attributes'])
-                    for mlun in acl['mapped_luns']:
-                        mlun_obj = MappedLUN(acl_obj, mlun['index'],
-                                             mlun['index'], mlun.get('write_protect'))
-
-                    del_if_there(acl, ('attributes', 'mapped_luns', 'node_wwn'))
-                    for name, value in acl.iteritems():
-                        if value:
-                            setattr(acl_obj, name, value)
+            errors += Target.setup(fm_obj, self.storage_objects, t)
+
+        return errors
 
     backstores = property(_list_backstores,
             doc="Get the list of Backstore objects.")
diff --git a/rtslib/target.py b/rtslib/target.py
index 61d3fa7..f6e3d27 100644
--- a/rtslib/target.py
+++ b/rtslib/target.py
@@ -30,6 +30,7 @@ from configobj import ConfigObj
 from utils import RTSLibError, RTSLibBrokenLink, modprobe
 from utils import is_ipv6_address, is_ipv4_address
 from utils import fread, fwrite, generate_wwn, is_valid_wwn, exec_argv
+from utils import dict_remove, set_attributes
 
 class FabricModule(CFSNode):
     '''
@@ -359,6 +360,11 @@ class FabricModule(CFSNode):
     version = property(_get_version,
                        doc="Get the fabric module version string.")
 
+    def setup(self, **fm):
+            del fm['name']
+            for name, value in fm.iteritems():
+                setattr(fm_obj, name, value)
+
     def dump(self):
         d = super(FabricModule, self).dump()
         d['name'] = self.name
@@ -1357,6 +1363,66 @@ class Target(CFSNode):
 
     tpgs = property(_list_tpgs, doc="Get the list of TPG for the Target.")
 
+    @classmethod
+    def setup(cls, fm_obj, storage_objects, t):
+        '''
+        Set up target objects based upon t dict, from saved config.
+        Guard against missing or bad dict items, but keep going.
+        Returns how many recoverable errors happened.
+        '''
+
+        try:
+            t_obj = Target(fm_obj, t.get('wwn'))
+        except RTSLibError:
+            return 1
+
+        errors = 0
+
+        for tpg in t.get('tpgs', []):
+            tpg_obj = TPG(t_obj)
+            set_attributes(tpg_obj, tpg.get('attributes', {}))
+
+            for lun in tpg.get('luns', []):
+                try:
+                    bs_name, so_name = lun['storage_object'].split('/')[2:]
+                except:
+                    errors += 1
+                    continue
+
+                match_so = [x for x in storage_objects
+                            if so_name == x.name
+                            if bs_name == x.backstore.plugin]
+                try:
+                    LUN(tpg_obj, lun.get('index'), storage_object=match_so[0])
+                except RTSLibError:
+                    errors += 1
+
+                for p in tpg.get('portals', []):
+                    try:
+                        NetworkPortal(tpg_obj, p['ip_address'], p['port'])
+                    except RTSLibError:
+                        errors += 1
+
+                for acl in tpg.get('node_acls', []):
+                    try:
+                        acl_obj = NodeACL(tpg_obj, acl['node_wwn'])
+                        set_attributes(tpg_obj, tpg.get('attributes', {}))
+                        for mlun in acl.get('mapped_luns', []):
+                            try:
+                                mlun_obj = MappedLUN(acl_obj, mlun['index'],
+                                                     mlun['index'], mlun.get('write_protect'))
+                            except RTSLibError:
+                                errors += 1
+
+                        dict_remove(acl, ('attributes', 'mapped_luns', 'node_wwn'))
+                        for name, value in acl.iteritems():
+                            if value:
+                                setattr(acl_obj, name, value)
+                    except RTSLibError:
+                        errors += 1
+
+        return errors
+
     def dump(self):
         d = super(Target, self).dump()
         d['wwn'] = self.wwn
diff --git a/rtslib/tcm.py b/rtslib/tcm.py
index d4c08ed..e4955a7 100644
--- a/rtslib/tcm.py
+++ b/rtslib/tcm.py
@@ -26,6 +26,7 @@ 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 human_to_bytes, 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):
 
@@ -450,6 +451,23 @@ 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
diff --git a/rtslib/utils.py b/rtslib/utils.py
index d1be95b..1532539 100644
--- a/rtslib/utils.py
+++ b/rtslib/utils.py
@@ -650,6 +650,20 @@ def exec_argv(argv, strip=True, shell=False):
     else:
         return stdoutdata
 
+def dict_remove(d, items):
+    for item in items:
+        if item in d:
+            del d[item]
+
+def set_attributes(obj, attr_dict):
+    for name, value in attr_dict.iteritems():
+        try:
+            obj.set_attribute(name, value)
+        except RTSLibError:
+            # Setting some attributes may return an error, before kernel 3.3
+            pass
+
+
 def list_eth_ips(ifnames=None):
     '''
     List the IPv4 and IPv6 non-loopback, non link-local addresses (in the
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux