diff --git a/.gitignore b/.gitignore index 849e799..ba01e7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/targetcli-fb-2.1.fb46.tar.gz +SOURCES/targetcli-fb-2.1.fb49.tar.gz diff --git a/.targetcli.metadata b/.targetcli.metadata index 8fae95d..52a4911 100644 --- a/.targetcli.metadata +++ b/.targetcli.metadata @@ -1 +1 @@ -cbfc05ef7baac08165fdb17efe26081eb9850363 SOURCES/targetcli-fb-2.1.fb46.tar.gz +f55bb874f9644991a042ee83f25c14d44a86d2db SOURCES/targetcli-fb-2.1.fb49.tar.gz diff --git a/SOURCES/0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch b/SOURCES/0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch deleted file mode 100644 index ecefe7e..0000000 --- a/SOURCES/0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 8011ea6a741d494c145b4906f7a7865c8b74c6a7 Mon Sep 17 00:00:00 2001 -From: Christian Seiler -Date: Thu, 23 Mar 2017 19:36:18 +0100 -Subject: [PATCH] Properly detect errors when writing backup files. (Closes: - #80) (#81) - -* Properly detect errors when writing backup files. (Closes: #80) - -If the backup directory does not exist, properly detect that and show a -warning message to the user, so that they don't think that their -configuration was backed up, when it fact wasn't. - -Additionally, try to automatically create the backup directory if it -does not exist. - -Signed-off-by: Christian Seiler - -* Don't automatically create backup directory if it doesn't exist. - -After discussion on the issue tracker, it was decided to not -auto-create the backup-directory if it doesn't exist yet. - -If the directory doesn't exist, the user will now see the warning. - -Signed-off-by: Christian Seiler ---- - targetcli/ui_root.py | 28 ++++++++++++++++++---------- - 1 file changed, 18 insertions(+), 10 deletions(-) - -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index 2d8989c..c3a8483 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -75,17 +75,25 @@ class UIRoot(UINode): - backup_name = "saveconfig-" + \ - datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json" - backupfile = backup_dir + "/" + backup_name -- with ignored(IOError): -+ backup_error = None -+ try: - shutil.copy(savefile, backupfile) -- -- # Kill excess backups -- backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) -- files_to_unlink = list(reversed(backups))[kept_backups:] -- for f in files_to_unlink: -- os.unlink(f) -- -- self.shell.log.info("Last %d configs saved in %s." % \ -- (kept_backups, backup_dir)) -+ except IOError as ioe: -+ backup_error = ioe.strerror or "Unknown error" -+ -+ if backup_error == None: -+ # Kill excess backups -+ backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) -+ files_to_unlink = list(reversed(backups))[kept_backups:] -+ for f in files_to_unlink: -+ with ignored(IOError): -+ os.unlink(f) -+ -+ self.shell.log.info("Last %d configs saved in %s." % \ -+ (kept_backups, backup_dir)) -+ else: -+ self.shell.log.warning("Could not create backup file %s: %s." % \ -+ (backupfile, backup_error)) - - self.rtsroot.save_to_file(savefile) - --- -1.8.3.1 - diff --git a/SOURCES/0002-Read-number-of-backup-files-to-keep-from-file.patch b/SOURCES/0002-Read-number-of-backup-files-to-keep-from-file.patch deleted file mode 100644 index 6c591e3..0000000 --- a/SOURCES/0002-Read-number-of-backup-files-to-keep-from-file.patch +++ /dev/null @@ -1,52 +0,0 @@ -From bf0fb387cef89bb0dc51cf1740ab73abf549c38e Mon Sep 17 00:00:00 2001 -From: Taylor Jakobson -Date: Mon, 23 Oct 2017 14:26:03 -0500 -Subject: [PATCH] Read number of backup files to keep from file - -Use /etc/target/targetcli.conf file to store universal configurations -that are the same for all users. -Configuration file has format of: - key = value ---- - targetcli/ui_root.py | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index c3a8483..8bc8521 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -20,6 +20,7 @@ under the License. - from datetime import datetime - from glob import glob - import os -+import re - import shutil - import stat - -@@ -32,7 +33,8 @@ from .ui_node import UINode - from .ui_target import UIFabricModule - - default_save_file = "/etc/target/saveconfig.json" --kept_backups = 10 -+universal_prefs_file = "/etc/target/targetcli.conf" -+default_kept_backups = 10 - - class UIRoot(UINode): - ''' -@@ -83,6 +85,13 @@ class UIRoot(UINode): - - if backup_error == None: - # Kill excess backups -+ try: -+ with open(universal_prefs_file) as prefs: -+ backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)] -+ kept_backups = int(backups[0].split('=')[1].strip()) -+ except: -+ kept_backups = default_kept_backups -+ - backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) - files_to_unlink = list(reversed(backups))[kept_backups:] - for f in files_to_unlink: --- -1.8.3.1 - diff --git a/SOURCES/0003-config-defend-on-etc-target-backup-directory.patch b/SOURCES/0003-config-defend-on-etc-target-backup-directory.patch deleted file mode 100644 index 837f9af..0000000 --- a/SOURCES/0003-config-defend-on-etc-target-backup-directory.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 6349a75bd71f2f15c3acd89588321524c94676e8 Mon Sep 17 00:00:00 2001 -From: Prasanna Kumar Kalever -Date: Fri, 15 Dec 2017 15:16:28 +0530 -Subject: [PATCH] config: defend on '/etc/target/backup' directory - -Currently we do not create '/etc/target/backup/' while we expect the directory -to be presented by package (rpm). - -If for some reason '/etc/target/backup' is not available, say may be a -unintentional deletion or use of targetcli which is compiled from source, -we see below errors on up on saveconfig command, - -Case 1: No '/etc/target/backup/' dir - -$ targetcli / saveconfig -Could not create backup file /etc/target/backup/saveconfig-20171215-15:26:48.json: No such file or directory. -Configuration saved to /etc/target/saveconfig.json - -Case 2: No '/etc/target/' dir - -$ targetcli / saveconfig -Could not create backup file /etc/target/backup/saveconfig-20171215-15:27:42.json: No such file or directory. -[Errno 2] No such file or directory: '/etc/target/saveconfig.json.temp' - -This patch tries to create '/etc/target/backup' directory tree in case if it -is absent. - -Signed-off-by: Prasanna Kumar Kalever ---- - targetcli/ui_root.py | 50 +++++++++++++++++++++++++++++--------------------- - 1 file changed, 29 insertions(+), 21 deletions(-) - -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index 8bc8521..33bb948 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -78,30 +78,38 @@ class UIRoot(UINode): - datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json" - backupfile = backup_dir + "/" + backup_name - backup_error = None -- try: -- shutil.copy(savefile, backupfile) -- except IOError as ioe: -- backup_error = ioe.strerror or "Unknown error" - -- if backup_error == None: -- # Kill excess backups -+ if not os.path.exists(backup_dir): -+ try: -+ os.makedirs(backup_dir); -+ except OSError as exe: -+ raise ExecutionError("Cannot create backup directory [%s] %s." % (backup_dir, exc.strerror)) -+ -+ if os.path.exists(savefile): - try: -- with open(universal_prefs_file) as prefs: -- backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)] -- kept_backups = int(backups[0].split('=')[1].strip()) -- except: -- kept_backups = default_kept_backups -- -- backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) -- files_to_unlink = list(reversed(backups))[kept_backups:] -- for f in files_to_unlink: -- with ignored(IOError): -- os.unlink(f) -- -- self.shell.log.info("Last %d configs saved in %s." % \ -+ shutil.copy(savefile, backupfile) -+ except IOError as ioe: -+ backup_error = ioe.strerror or "Unknown error" -+ -+ if backup_error == None: -+ # Kill excess backups -+ try: -+ with open(universal_prefs_file) as prefs: -+ backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)] -+ kept_backups = int(backups[0].split('=')[1].strip()) -+ except: -+ kept_backups = default_kept_backups -+ -+ backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) -+ files_to_unlink = list(reversed(backups))[kept_backups:] -+ for f in files_to_unlink: -+ with ignored(IOError): -+ os.unlink(f) -+ -+ self.shell.log.info("Last %d configs saved in %s." % \ - (kept_backups, backup_dir)) -- else: -- self.shell.log.warning("Could not create backup file %s: %s." % \ -+ else: -+ self.shell.log.warning("Could not create backup file %s: %s." % \ - (backupfile, backup_error)) - - self.rtsroot.save_to_file(savefile) --- -1.8.3.1 - diff --git a/SOURCES/0004-config-backup-when-current-config-is-different-from-.patch b/SOURCES/0004-config-backup-when-current-config-is-different-from-.patch deleted file mode 100644 index 69ed6cc..0000000 --- a/SOURCES/0004-config-backup-when-current-config-is-different-from-.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 6efbd7e4c0217d1f6b46e22ec51a209439678f5a Mon Sep 17 00:00:00 2001 -From: Prasanna Kumar Kalever -Date: Mon, 18 Dec 2017 15:25:42 +0530 -Subject: [PATCH] config: backup when current config is different from recent - backup copy - -With this change, -when '/etc/target/saveconfig.json' is same as '/etc/target/backup/saveconfig-${latest-stamp}.json -we skip backing up saveconfig.json - -Signed-off-by: Prasanna Kumar Kalever ---- - targetcli/ui_root.py | 53 ++++++++++++++++++++++++++++------------------------ - 1 file changed, 29 insertions(+), 24 deletions(-) - -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index 33bb948..f398395 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -23,6 +23,7 @@ import os - import re - import shutil - import stat -+import filecmp - - from configshell_fb import ExecutionError - from rtslib_fb import RTSRoot -@@ -85,32 +86,36 @@ class UIRoot(UINode): - except OSError as exe: - raise ExecutionError("Cannot create backup directory [%s] %s." % (backup_dir, exc.strerror)) - -+ # Only save backups if savefile exits - if os.path.exists(savefile): -- try: -- shutil.copy(savefile, backupfile) -- except IOError as ioe: -- backup_error = ioe.strerror or "Unknown error" -- -- if backup_error == None: -- # Kill excess backups -+ backed_files_list = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) -+ # Save backup if 1. backup dir is empty, or 2. savefile is differnt from recent backup copy -+ if not backed_files_list or not filecmp.cmp(backed_files_list[-1], savefile): - try: -- with open(universal_prefs_file) as prefs: -- backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)] -- kept_backups = int(backups[0].split('=')[1].strip()) -- except: -- kept_backups = default_kept_backups -- -- backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) -- files_to_unlink = list(reversed(backups))[kept_backups:] -- for f in files_to_unlink: -- with ignored(IOError): -- os.unlink(f) -- -- self.shell.log.info("Last %d configs saved in %s." % \ -- (kept_backups, backup_dir)) -- else: -- self.shell.log.warning("Could not create backup file %s: %s." % \ -- (backupfile, backup_error)) -+ shutil.copy(savefile, backupfile) -+ -+ except IOError as ioe: -+ backup_error = ioe.strerror or "Unknown error" -+ -+ if backup_error == None: -+ # Kill excess backups -+ try: -+ with open(universal_prefs_file) as prefs: -+ backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)] -+ kept_backups = int(backups[0].split('=')[1].strip()) -+ except: -+ kept_backups = default_kept_backups -+ -+ files_to_unlink = list(reversed(backed_files_list))[kept_backups:] -+ for f in files_to_unlink: -+ with ignored(IOError): -+ os.unlink(f) -+ -+ self.shell.log.info("Last %d configs saved in %s." % \ -+ (kept_backups, backup_dir)) -+ else: -+ self.shell.log.warning("Could not create backup file %s: %s." % \ -+ (backupfile, backup_error)) - - self.rtsroot.save_to_file(savefile) - --- -1.8.3.1 - diff --git a/SOURCES/0005-config-rename-key-kept_backups-as-max_backup_files.patch b/SOURCES/0005-config-rename-key-kept_backups-as-max_backup_files.patch deleted file mode 100644 index 732b1c0..0000000 --- a/SOURCES/0005-config-rename-key-kept_backups-as-max_backup_files.patch +++ /dev/null @@ -1,48 +0,0 @@ -From bd3b2b50d741848a748830d9a1a7ee642e8d40d3 Mon Sep 17 00:00:00 2001 -From: Prasanna Kumar Kalever -Date: Tue, 19 Dec 2017 14:32:41 +0530 -Subject: [PATCH] config: rename key 'kept_backups' as 'max_backup_files' - -$ cat /etc/target/targetcli.conf -max_backup_files = 25 - -$ targetcli / saveconfig -Last 25 configs saved in /etc/target/backup. -Configuration saved to /etc/target/saveconfig.json - -Signed-off-by: Prasanna Kumar Kalever ---- - targetcli/ui_root.py | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index f398395..f84d33d 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -101,18 +101,18 @@ class UIRoot(UINode): - # Kill excess backups - try: - with open(universal_prefs_file) as prefs: -- backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)] -- kept_backups = int(backups[0].split('=')[1].strip()) -+ backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)] -+ max_backup_files = int(backups[0].split('=')[1].strip()) - except: -- kept_backups = default_kept_backups -+ max_backup_files = default_kept_backups - -- files_to_unlink = list(reversed(backed_files_list))[kept_backups:] -+ files_to_unlink = list(reversed(backed_files_list))[max_backup_files:] - for f in files_to_unlink: - with ignored(IOError): - os.unlink(f) - - self.shell.log.info("Last %d configs saved in %s." % \ -- (kept_backups, backup_dir)) -+ (max_backup_files, backup_dir)) - else: - self.shell.log.warning("Could not create backup file %s: %s." % \ - (backupfile, backup_error)) --- -1.8.3.1 - diff --git a/SOURCES/0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch b/SOURCES/0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch deleted file mode 100644 index 3493991..0000000 --- a/SOURCES/0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch +++ /dev/null @@ -1,78 +0,0 @@ -From bf75323d7d678f01c21d0c9825bd55553727e934 Mon Sep 17 00:00:00 2001 -From: Prasanna Kumar Kalever -Date: Fri, 15 Dec 2017 17:23:25 +0530 -Subject: [PATCH] backup: global option to tune max no. of backup conf files - -Eg: -/> set global max_backup_files=1000 -Parameter max_backup_files is now '1000'. - -If 'max_backup_files' is set in /etc/target/targetcli.conf, then max value -between conf file setting and global option settings is considered. - -Signed-off-by: Prasanna Kumar Kalever ---- - scripts/targetcli | 1 + - targetcli/ui_node.py | 3 +++ - targetcli/ui_root.py | 8 +++++--- - 3 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/scripts/targetcli b/scripts/targetcli -index 5404fcd..371edbe 100755 ---- a/scripts/targetcli -+++ b/scripts/targetcli -@@ -49,6 +49,7 @@ class TargetCLI(ConfigShell): - 'auto_add_mapped_luns': True, - 'auto_cd_after_create': False, - 'auto_save_on_exit': True, -+ 'max_backup_files': '10', - 'auto_add_default_portal': True, - } - -diff --git a/targetcli/ui_node.py b/targetcli/ui_node.py -index c91dae2..a6982f1 100644 ---- a/targetcli/ui_node.py -+++ b/targetcli/ui_node.py -@@ -46,6 +46,9 @@ class UINode(ConfigNode): - self.define_config_group_param( - 'global', 'auto_add_default_portal', 'bool', - 'If true, adds a portal listening on all IPs to new targets.') -+ self.define_config_group_param( -+ 'global', 'max_backup_files', 'string', -+ 'Max no. of configurations to be backed up in /etc/target/backup/ directory.') - - def assert_root(self): - ''' -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index f84d33d..a54845f 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -35,7 +35,6 @@ from .ui_target import UIFabricModule - - default_save_file = "/etc/target/saveconfig.json" - universal_prefs_file = "/etc/target/targetcli.conf" --default_kept_backups = 10 - - class UIRoot(UINode): - ''' -@@ -99,12 +98,15 @@ class UIRoot(UINode): - - if backup_error == None: - # Kill excess backups -+ max_backup_files = int(self.shell.prefs['max_backup_files']) -+ - try: - with open(universal_prefs_file) as prefs: - backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)] -- max_backup_files = int(backups[0].split('=')[1].strip()) -+ if max_backup_files < int(backups[0].split('=')[1].strip()): -+ max_backup_files = int(backups[0].split('=')[1].strip()) - except: -- max_backup_files = default_kept_backups -+ self.shell.log.debug("No universal prefs file '%s'." % universal_prefs_file) - - files_to_unlink = list(reversed(backed_files_list))[max_backup_files:] - for f in files_to_unlink: --- -1.8.3.1 - diff --git a/SOURCES/0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch b/SOURCES/0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch deleted file mode 100644 index aa9a488..0000000 --- a/SOURCES/0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch +++ /dev/null @@ -1,26 +0,0 @@ -From cac1f18c54c87839b4eaa812cd438dc4593c7975 Mon Sep 17 00:00:00 2001 -From: tangwenji -Date: Thu, 15 Mar 2018 14:52:20 +0800 -Subject: [PATCH] Fix default max_backup_files in ui_command_saveconfig - -Signed-off-by: tangwenji ---- - targetcli/ui_root.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index a54845f..54d38e3 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -98,7 +98,7 @@ class UIRoot(UINode): - - if backup_error == None: - # Kill excess backups -- max_backup_files = int(self.shell.prefs['max_backup_files']) -+ max_backup_files = int(self.shell.default_prefs['max_backup_files']) - - try: - with open(universal_prefs_file) as prefs: --- -1.8.3.1 - diff --git a/SOURCES/0008-config-add-saveconfig-command-to-StorageObject-level.patch b/SOURCES/0008-config-add-saveconfig-command-to-StorageObject-level.patch deleted file mode 100644 index b018d94..0000000 --- a/SOURCES/0008-config-add-saveconfig-command-to-StorageObject-level.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 9dc85912f6ff2ba77fa8b136478ae3d2776c2b5e Mon Sep 17 00:00:00 2001 -From: Prasanna Kumar Kalever -Date: Sat, 24 Feb 2018 08:38:35 +0530 -Subject: [PATCH] config: add saveconfig command to StorageObject level - -$ 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 ---- - targetcli/ui_backstore.py | 22 ++++++++++ - targetcli/ui_root.py | 110 ++++++++++++++++++++++++++-------------------- - 2 files changed, 85 insertions(+), 47 deletions(-) - -diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py -index 5af448f..efa532f 100644 ---- a/targetcli/ui_backstore.py -+++ b/targetcli/ui_backstore.py -@@ -36,6 +36,8 @@ from rtslib_fb.utils import get_block_type - - from .ui_node import UINode, UIRTSLibNode - -+default_save_file = "/etc/target/saveconfig.json" -+ - alua_rw_params = ['alua_access_state', 'alua_access_status', - 'alua_write_metadata', 'alua_access_type', 'preferred', - 'nonop_delay_msecs', 'trans_delay_msecs', -@@ -702,6 +704,26 @@ class UIStorageObject(UIRTSLibNode): - self.shell.con.display("Backstore plugin %s %s" - % (self.rtsnode.plugin, self.rtsnode.version)) - -+ def ui_command_saveconfig(self, savefile=None): -+ ''' -+ Save configuration of this StorageObject. -+ ''' -+ so = self.rtsnode -+ rn = self.get_root() -+ -+ if not savefile: -+ savefile = default_save_file -+ -+ savefile = os.path.expanduser(savefile) -+ -+ rn._save_backups(savefile) -+ -+ rn.rtsroot.save_to_file(savefile, -+ '/backstores/' + so.plugin + '/' + so.name) -+ -+ self.shell.log.info("Storage Object '%s:%s' config saved to %s." -+ % (so.plugin, so.name, savefile)) -+ - - class UIPSCSIStorageObject(UIStorageObject): - def summary(self): -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index 54d38e3..09f3f1b 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -62,6 +62,65 @@ class UIRoot(UINode): - if fm.wwns == None or any(fm.wwns): - UIFabricModule(fm, self) - -+ def _save_backups(self, savefile): -+ ''' -+ Take backup of config-file if needed. -+ ''' -+ # Only save backups if saving to default location -+ if savefile != default_save_file: -+ return -+ -+ backup_dir = os.path.dirname(savefile) + "/backup/" -+ backup_name = "saveconfig-" + \ -+ datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json" -+ backupfile = backup_dir + backup_name -+ backup_error = None -+ -+ if not os.path.exists(backup_dir): -+ try: -+ os.makedirs(backup_dir); -+ except OSError as exe: -+ raise ExecutionError("Cannot create backup directory [%s] %s." -+ % (backup_dir, exc.strerror)) -+ -+ # Only save backups if savefile exits -+ if not os.path.exists(savefile): -+ return -+ -+ backed_files_list = sorted(glob(os.path.dirname(savefile) + \ -+ "/backup/*.json")) -+ -+ # Save backup if backup dir is empty, or savefile is differnt from recent backup copy -+ if not backed_files_list or not filecmp.cmp(backed_files_list[-1], savefile): -+ try: -+ shutil.copy(savefile, backupfile) -+ -+ except IOError as ioe: -+ backup_error = ioe.strerror or "Unknown error" -+ -+ if backup_error == None: -+ # remove excess backups -+ max_backup_files = int(self.shell.prefs['max_backup_files']) -+ -+ try: -+ with open(universal_prefs_file) as prefs: -+ backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)] -+ if max_backup_files < int(backups[0].split('=')[1].strip()): -+ max_backup_files = int(backups[0].split('=')[1].strip()) -+ except: -+ self.shell.log.debug("No universal prefs file '%s'." % universal_prefs_file) -+ -+ files_to_unlink = list(reversed(backed_files_list))[max_backup_files:] -+ for f in files_to_unlink: -+ with ignored(IOError): -+ os.unlink(f) -+ -+ self.shell.log.info("Last %d configs saved in %s." -+ % (max_backup_files, backup_dir)) -+ else: -+ self.shell.log.warning("Could not create backup file %s: %s." -+ % (backupfile, backup_error)) -+ - def ui_command_saveconfig(self, savefile=default_save_file): - ''' - Saves the current configuration to a file so that it can be restored -@@ -69,55 +128,12 @@ class UIRoot(UINode): - ''' - self.assert_root() - -+ if not savefile: -+ savefile = default_save_file -+ - savefile = os.path.expanduser(savefile) - -- # Only save backups if saving to default location -- if savefile == default_save_file: -- backup_dir = os.path.dirname(savefile) + "/backup" -- backup_name = "saveconfig-" + \ -- datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json" -- backupfile = backup_dir + "/" + backup_name -- backup_error = None -- -- if not os.path.exists(backup_dir): -- try: -- os.makedirs(backup_dir); -- except OSError as exe: -- raise ExecutionError("Cannot create backup directory [%s] %s." % (backup_dir, exc.strerror)) -- -- # Only save backups if savefile exits -- if os.path.exists(savefile): -- backed_files_list = sorted(glob(os.path.dirname(savefile) + "/backup/*.json")) -- # Save backup if 1. backup dir is empty, or 2. savefile is differnt from recent backup copy -- if not backed_files_list or not filecmp.cmp(backed_files_list[-1], savefile): -- try: -- shutil.copy(savefile, backupfile) -- -- except IOError as ioe: -- backup_error = ioe.strerror or "Unknown error" -- -- if backup_error == None: -- # Kill excess backups -- max_backup_files = int(self.shell.default_prefs['max_backup_files']) -- -- try: -- with open(universal_prefs_file) as prefs: -- backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)] -- if max_backup_files < int(backups[0].split('=')[1].strip()): -- max_backup_files = int(backups[0].split('=')[1].strip()) -- except: -- self.shell.log.debug("No universal prefs file '%s'." % universal_prefs_file) -- -- files_to_unlink = list(reversed(backed_files_list))[max_backup_files:] -- for f in files_to_unlink: -- with ignored(IOError): -- os.unlink(f) -- -- self.shell.log.info("Last %d configs saved in %s." % \ -- (max_backup_files, backup_dir)) -- else: -- self.shell.log.warning("Could not create backup file %s: %s." % \ -- (backupfile, backup_error)) -+ self._save_backups(savefile) - - self.rtsroot.save_to_file(savefile) - --- -1.8.3.1 - diff --git a/SOURCES/0009-Support-tcmu-hw-max-sectors.patch b/SOURCES/0009-Support-tcmu-hw-max-sectors.patch deleted file mode 100644 index 4137170..0000000 --- a/SOURCES/0009-Support-tcmu-hw-max-sectors.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 2f3183bf56295a764e743d0601275c7aa5a815db Mon Sep 17 00:00:00 2001 -From: Mike Christie -Date: Wed, 29 Mar 2017 15:01:05 -0500 -Subject: [PATCH] Support tcmu hw max sectors - -Support hw_max_sectors setting for tcmu added in this patch: - -commit 3abaa2bfdb1e6bb33d38a2e82cf3bb82ec0197bf -Author: Mike Christie -Date: Wed Mar 1 23:14:39 2017 -0600 - - tcmu: allow hw_max_sectors greater than 128 ---- - targetcli/ui_backstore.py | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py -index 4c577a4..88240bb 100644 ---- a/targetcli/ui_backstore.py -+++ b/targetcli/ui_backstore.py -@@ -574,7 +574,8 @@ class UIUserBackedBackstore(UIBackstore): - print(x.get("ConfigDesc", "No description.")) - print() - -- def ui_command_create(self, name, size, cfgstring, wwn=None): -+ def ui_command_create(self, name, size, cfgstring, wwn=None, -+ hw_max_sectors=None): - ''' - Creates a User-backed storage object. - -@@ -598,7 +599,8 @@ class UIUserBackedBackstore(UIBackstore): - if not ok: - raise ExecutionError("cfgstring invalid: %s" % errmsg) - -- so = UserBackedStorageObject(name, size=size, config=config, wwn=wwn) -+ so = UserBackedStorageObject(name, size=size, config=config, wwn=wwn, -+ hw_max_sectors=hw_max_sectors) - ui_so = UIUserBackedStorageObject(so, self) - self.shell.log.info("Created user-backed storage object %s size %d." - % (name, size)) --- -1.8.3.1 - diff --git a/SOURCES/0010-create-add-a-way-to-set-control-string.patch b/SOURCES/0010-create-add-a-way-to-set-control-string.patch deleted file mode 100644 index 55bae36..0000000 --- a/SOURCES/0010-create-add-a-way-to-set-control-string.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py -index 3838d02..b60eba5 100644 ---- a/targetcli/ui_backstore.py -+++ b/targetcli/ui_backstore.py -@@ -577,7 +577,7 @@ class UIUserBackedBackstore(UIBackstore): - print() - - def ui_command_create(self, name, size, cfgstring, wwn=None, -- hw_max_sectors=None): -+ hw_max_sectors=None, control=None): - ''' - Creates a User-backed storage object. - -@@ -602,7 +602,7 @@ class UIUserBackedBackstore(UIBackstore): - raise ExecutionError("cfgstring invalid: %s" % errmsg) - - so = UserBackedStorageObject(name, size=size, config=config, wwn=wwn, -- hw_max_sectors=hw_max_sectors) -+ hw_max_sectors=hw_max_sectors, control=control) - ui_so = UIUserBackedStorageObject(so, self) - self.shell.log.info("Created user-backed storage object %s size %d." - % (name, size)) -@@ -633,6 +633,7 @@ class UIStorageObject(UIRTSLibNode): - 'fabric_max_sectors': ('number', 'Maximum number of sectors the fabric can transfer at once.'), - 'hw_block_size': ('number', 'Hardware block size in bytes.'), - 'hw_max_sectors': ('number', 'Maximum number of sectors the hardware can transfer at once.'), -+ 'control': ('string', 'Comma separated string of control=value tuples that will be passed to kernel control file.'), - 'hw_pi_prot_type': ('number', 'If non-zero, DIF protection is enabled on the underlying hardware.'), - 'hw_queue_depth': ('number', 'Hardware queue depth.'), - 'is_nonrot': ('number', 'If set to 1, the backstore is a non rotational device.'), diff --git a/SOURCES/0011-saveconfig-way-for-block-level-save-with-delete-comm.patch b/SOURCES/0011-saveconfig-way-for-block-level-save-with-delete-comm.patch deleted file mode 100644 index 76817d0..0000000 --- a/SOURCES/0011-saveconfig-way-for-block-level-save-with-delete-comm.patch +++ /dev/null @@ -1,46 +0,0 @@ -From bca03ea400a691e4218113b6d10adb61ce0cd511 Mon Sep 17 00:00:00 2001 -From: Prasanna Kumar Kalever -Date: Fri, 1 Jun 2018 16:15:22 +0530 -Subject: [PATCH] saveconfig: way for block-level save with delete command - -currently, we can use block-level save feature for create command and -reconfig of different attributes, but there is no way to use block-level -feature for delete command. - -This patch introduces 'save' flag (False on default), which can trigger -saveconfig internally as part of delete command. - -$ targetcli /backstores/user:glfs delete test save=True -Deleted storage object test. - -Signed-off-by: Prasanna Kumar Kalever ---- - targetcli/ui_backstore.py | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py -index 0af29f0..02695ba 100644 ---- a/targetcli/ui_backstore.py -+++ b/targetcli/ui_backstore.py -@@ -284,7 +284,7 @@ class UIBackstore(UINode): - def summary(self): - return ("Storage Objects: %d" % len(self._children), None) - -- def ui_command_delete(self, name): -+ def ui_command_delete(self, name, save=None): - ''' - Recursively deletes the storage object having the specified I{name}. If - there are LUNs using this storage object, they will be deleted too. -@@ -301,7 +301,8 @@ class UIBackstore(UINode): - except ValueError: - raise ExecutionError("No storage object named %s." % name) - -- child.rtsnode.delete() -+ save = self.ui_eval_param(save, 'bool', False) -+ child.rtsnode.delete(save=save) - self.remove_child(child) - self.shell.log.info("Deleted storage object %s." % name) - --- -1.8.3.1 - diff --git a/SOURCES/0012-saveconfig-handle-backups-with-block-level-delete.patch b/SOURCES/0012-saveconfig-handle-backups-with-block-level-delete.patch deleted file mode 100644 index f45c669..0000000 --- a/SOURCES/0012-saveconfig-handle-backups-with-block-level-delete.patch +++ /dev/null @@ -1,28 +0,0 @@ -From a7254dfc15830eb64ae8d47639889cb6a23bd7f4 Mon Sep 17 00:00:00 2001 -From: Prasanna Kumar Kalever -Date: Tue, 12 Jun 2018 15:36:42 +0530 -Subject: [PATCH] saveconfig: handle backups with block-level delete - -Signed-off-by: Prasanna Kumar Kalever ---- - targetcli/ui_backstore.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py -index 02695ba..7af2568 100644 ---- a/targetcli/ui_backstore.py -+++ b/targetcli/ui_backstore.py -@@ -302,6 +302,10 @@ class UIBackstore(UINode): - raise ExecutionError("No storage object named %s." % name) - - save = self.ui_eval_param(save, 'bool', False) -+ if save: -+ rn = self.get_root() -+ rn._save_backups(default_save_file) -+ - child.rtsnode.delete(save=save) - self.remove_child(child) - self.shell.log.info("Deleted storage object %s." % name) --- -1.8.3.1 - diff --git a/SPECS/targetcli.spec b/SPECS/targetcli.spec index de5c36c..932dcb2 100644 --- a/SPECS/targetcli.spec +++ b/SPECS/targetcli.spec @@ -4,22 +4,10 @@ Name: targetcli License: ASL 2.0 Group: System Environment/Libraries Summary: An administration shell for storage targets -Version: 2.1.fb46 -Release: 7%{?dist} +Version: 2.1.fb49 +Release: 1%{?dist} URL: https://fedorahosted.org/targetcli-fb/ Source: https://fedorahosted.org/released/targetcli-fb/%{oname}-%{version}.tar.gz -Patch0: 0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch -Patch1: 0002-Read-number-of-backup-files-to-keep-from-file.patch -Patch2: 0003-config-defend-on-etc-target-backup-directory.patch -Patch3: 0004-config-backup-when-current-config-is-different-from-.patch -Patch4: 0005-config-rename-key-kept_backups-as-max_backup_files.patch -Patch5: 0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch -Patch6: 0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch -Patch7: 0008-config-add-saveconfig-command-to-StorageObject-level.patch -Patch8: 0009-Support-tcmu-hw-max-sectors.patch -Patch9: 0010-create-add-a-way-to-set-control-string.patch -Patch10: 0011-saveconfig-way-for-block-level-save-with-delete-comm.patch -Patch11: 0012-saveconfig-handle-backups-with-block-level-delete.patch BuildArch: noarch BuildRequires: python-devel python-setuptools Requires: python-rtslib >= 2.1.fb41, python-configshell, python-ethtool @@ -33,18 +21,6 @@ users will also need to install and use fcoe-utils. %prep %setup -q -n %{oname}-%{version} -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 %build %{__python} setup.py build @@ -65,6 +41,9 @@ install -m 644 targetcli.8.gz %{buildroot}%{_mandir}/man8/ %{_mandir}/man8/targetcli.8.gz %changelog +* Tue Jan 29 2019 Maurizio Lombardi - 2.1.fb49-1 +- Rebase to latest upstream version + * Wed Aug 08 2018 Maurizio Lombardi - 2.1.fb46-7 - Respin a new release of targetcli to avoid problems with TPS tests.