Commit 71877c4f authored by Ritesh Sarraf's avatar Ritesh Sarraf

Update upstream source from tag 'upstream/2.1.fb49'

Update to upstream version '2.1.fb49'
with Debian dir 9cc7d18b957ff6467e82de81afefb08d8f01ad48
parents 192f04b5 c2b22ff8
......@@ -20,7 +20,7 @@ under the License.
from __future__ import print_function
from os import getuid
from os import getuid, getenv
from targetcli import UIRoot
from rtslib_fb import RTSLibError
from configshell_fb import ConfigShell, ExecutionError
......@@ -75,7 +75,7 @@ def main():
else:
is_root = False
shell = TargetCLI('~/.targetcli')
shell = TargetCLI(getenv("TARGETCLI_HOME", '~/.targetcli'))
try:
root_node = UIRoot(shell, as_root=is_root)
......
......@@ -456,6 +456,9 @@ the userid and password for full-feature phase for this ACL.
.B /etc/target/saveconfig.json
.br
.B /etc/target/backup/*
.SH ENVIRONMENT
.SS TARGETCLI_HOME
If set, this variable points to a directory that should be used instead of ~/.targetctl
.SH SEE ALSO
.BR targetctl (8),
.BR tcmu-runner (8)
......
......@@ -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',
......@@ -131,7 +133,7 @@ class UIALUATargetPortGroup(UIRTSLibNode):
self.define_config_group_param("alua", param, 'string')
for param in alua_ro_params:
self.define_config_group_param("alua", param, 'string', False)
self.define_config_group_param("alua", param, 'string', writable=False)
def ui_getgroup_alua(self, alua_attr):
return getattr(self.rtsnode, alua_attr)
......@@ -282,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.
......@@ -299,7 +301,12 @@ class UIBackstore(UINode):
except ValueError:
raise ExecutionError("No storage object named %s." % name)
child.rtsnode.delete()
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)
......@@ -536,7 +543,7 @@ class UIBlockBackstore(UIBackstore):
except (OSError, IOError):
raise ExecutionError("Could not open %s" % dev)
# ioctl returns an int. Provision a buffer for it
buf = array.array('c', [chr(0)] * 4)
buf = array.array('b', [0] * 4)
try:
fcntl.ioctl(f, BLKROGET, buf)
except (OSError, IOError):
......@@ -613,7 +620,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.
......@@ -639,7 +646,8 @@ class UIUserBackedBackstore(UIBackstore):
try:
so = UserBackedStorageObject(name, size=size, config=config,
wwn=wwn, hw_max_sectors=hw_max_sectors)
wwn=wwn, hw_max_sectors=hw_max_sectors,
control=control)
except:
raise ExecutionError("UserBackedStorageObject creation failed.")
......@@ -648,6 +656,19 @@ class UIUserBackedBackstore(UIBackstore):
% (name, size))
return self.new_node(ui_so)
def ui_command_changemedium(self, name, size, cfgstring):
size = human_to_bytes(size)
config = self.handler + "/" + cfgstring
try:
rc, errmsg = self.iface.ChangeMedium('(sts)', name, size, config)
except Exception as e:
raise ExecutionError("ChangeMedium failed: %s" % e)
else:
if rc == 0:
self.shell.log.info("Medium Changed.")
else:
raise ExecutionError("ChangeMedium failed: %s" % errmsg)
class UIStorageObject(UIRTSLibNode):
'''
......@@ -673,6 +694,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.'),
......@@ -702,6 +724,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):
......
......@@ -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 - 1:]
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.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)
......
......@@ -1141,7 +1141,7 @@ class UILUNs(UINode):
existing_mluns = [mlun.mapped_lun for mlun in acl.mapped_luns]
if mapped_lun in existing_mluns:
mapped_lun = None
for possible_mlun in six.moves.range(LUN.MAX_LUN):
for possible_mlun in six.moves.range(MappedLUN.MAX_LUN):
if possible_mlun not in existing_mluns:
mapped_lun = possible_mlun
break
......
......@@ -15,4 +15,4 @@ License for the specific language governing permissions and limitations
under the License.
'''
__version__ = '2.1.fb48'
__version__ = '2.1.fb49'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment