Blob Blame History Raw
From 7cc8531b03f5391f8c2fa1208c4f6b6e7b030b66 Mon Sep 17 00:00:00 2001
From: Maurizio Lombardi <mlombard@redhat.com>
Date: Tue, 10 Apr 2018 15:18:37 +0200
Subject: [PATCH] save_to_file: support saveconfig at storage object level

Added an option to update configuration for single storage object at a time.
As of today changes done for one storage object needs the whole configuration
update. This option will enable us to save changes done to a give storage object.

$ targetcli /backstores/user:glfs/block1 help
[...]
AVAILABLE COMMANDS
[...]
    - saveconfig [savefile]
    - set [group] [parameter=value...]
    - status
    - version

$ targetcli /backstores/user:glfs/block1 saveconfig
Storage Object 'user:block1' config saved to /etc/target/saveconfig.json

Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
---
 rtslib/root.py | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 84 insertions(+), 2 deletions(-)

diff --git a/rtslib/root.py b/rtslib/root.py
index 99a25b7..c6697cf 100644
--- a/rtslib/root.py
+++ b/rtslib/root.py
@@ -148,6 +148,83 @@ class RTSRoot(CFSNode):
     def __str__(self):
         return "rtslib"
 
+    def _get_saveconf(self, so_path, save_file):
+        '''
+        Fetch the configuration of all the blocks and return conf with
+        updated storageObject info and its related target configuraion of
+        given storage object path
+        '''
+        current = self.dump()
+
+        with open(save_file, "r") as f:
+            saveconf = json.loads(f.read())
+            f.close()
+
+        fetch_cur_so = False
+        fetch_cur_tg = False
+        # Get the given block current storageObj configuration
+        for sidx, sobj in enumerate(current.get('storage_objects', [])):
+            if '/backstores/' + sobj['plugin'] + '/' + sobj['name'] == so_path:
+                current_so = current['storage_objects'][sidx]
+                fetch_cur_so = True
+                break
+
+        # Get the given block current target configuration
+        if fetch_cur_so:
+            for tidx, tobj in enumerate(current.get('targets', [])):
+                if fetch_cur_tg:
+                    break
+                for luns in tobj.get('tpgs', []):
+                    if fetch_cur_tg:
+                        break
+                    for lun in luns.get('luns', []):
+                        if lun['storage_object'] == so_path:
+                            current_tg = current['targets'][tidx]
+                            fetch_cur_tg = True
+                            break
+
+        fetch_sav_so = False
+        fetch_sav_tg = False
+        # Get the given block storageObj from saved configuration
+        for sidx, sobj in enumerate(saveconf.get('storage_objects', [])):
+            if '/backstores/' + sobj['plugin'] + '/' + sobj['name'] == so_path:
+                # Merge StorageObj
+                if fetch_cur_so:
+                    saveconf['storage_objects'][sidx] = current_so;
+                # Remove StorageObj
+                else:
+                    saveconf['storage_objects'].remove(saveconf['storage_objects'][sidx])
+                fetch_sav_so = True
+                break
+
+        # Get the given block target from saved configuration
+        if fetch_sav_so:
+            for tidx, tobj in enumerate(saveconf.get('targets', [])):
+                if fetch_sav_tg:
+                    break
+                for luns in tobj.get('tpgs', []):
+                    if fetch_sav_tg:
+                        break
+                    for lun in luns.get('luns', []):
+                        if lun['storage_object'] == so_path:
+                            # Merge target
+                            if fetch_cur_tg:
+                                saveconf['targets'][tidx] = current_tg;
+                            # Remove target
+                            else:
+                                saveconf['targets'].remove(saveconf['targets'][tidx])
+                            fetch_sav_tg = True
+                            break
+
+        # Insert storageObj
+        if fetch_cur_so and not fetch_sav_so:
+            saveconf['storage_objects'].append(current_so)
+        # Insert target
+        if fetch_cur_tg and not fetch_sav_tg:
+            saveconf['targets'].append(current_tg)
+
+        return saveconf
+
     # RTSRoot public stuff
 
     def dump(self):
@@ -257,7 +334,7 @@ class RTSRoot(CFSNode):
 
         return errors
 
-    def save_to_file(self, save_file=None):
+    def save_to_file(self, save_file=None, so_path=None):
         '''
         Write the configuration in json format to a file.
         Save file defaults to '/etc/targets/saveconfig.json'.
@@ -265,9 +342,14 @@ class RTSRoot(CFSNode):
         if not save_file:
             save_file = default_save_file
 
+        if so_path:
+            saveconf = self._get_saveconf(so_path, save_file)
+        else:
+            saveconf = self.dump()
+
         with open(save_file+".temp", "w+") as f:
             os.fchmod(f.fileno(), stat.S_IRUSR | stat.S_IWUSR)
-            f.write(json.dumps(self.dump(), sort_keys=True, indent=2))
+            f.write(json.dumps(saveconf, sort_keys=True, indent=2))
             f.write("\n")
             f.flush()
             os.fsync(f.fileno())
-- 
1.8.3.1