From 7cc8531b03f5391f8c2fa1208c4f6b6e7b030b66 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi 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 Signed-off-by: Maurizio Lombardi --- 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