Hello community,

here is the log from the commit of package python-rtslib-fb for 
openSUSE:Factory checked in at 2018-10-22 11:23:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-rtslib-fb (Old)
 and      /work/SRC/openSUSE:Factory/.python-rtslib-fb.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-rtslib-fb"

Mon Oct 22 11:23:14 2018 rev:18 rq:643053 version:2.1.69

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-rtslib-fb/python-rtslib-fb.changes        
2018-04-19 15:29:24.199264772 +0200
+++ /work/SRC/openSUSE:Factory/.python-rtslib-fb.new/python-rtslib-fb.changes   
2018-10-22 11:23:17.947158503 +0200
@@ -1,0 +2,23 @@
+Thu Oct 18 23:27:42 UTC 2018 - [email protected]
+
+- Update to version 2.1.69:
+  * version 2.1.fb69
+  * fix compiler warning
+  * version 2.1.fb68
+  * Fix typo
+  * - remove underscore in hostname
+  * tcm: allow to enable asynchronous I/O for file backing stores
+  * saveconfig: way for block-level save with delete command
+  * saveconfig: fix missing import
+  * saveconfig: handle no attr exception in _parse_info()
+  * saveconfig: fix failure in absence of save file
+  * saveconfig: dump control string containing control=value tuples
+  * restoreconfig: fix alua tpg config setup
+  * tcmu: add control constructor arg
+  * save_to_file: support saveconfig at storage object level
+  * Allow creating more than 256 LUNs per target
+  * Ship a systemd service file
+ Which replaces python-rtslib-fb-2.1.67.tar.xz with
+ python-rtslib-fb-2.1.69.tar.xz, and updates the SPEC file as well.
+
+-------------------------------------------------------------------

Old:
----
  python-rtslib-fb-2.1.67.tar.xz

New:
----
  python-rtslib-fb-2.1.69.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-rtslib-fb.spec ++++++
--- /var/tmp/diff_new_pack.EZYHrD/_old  2018-10-22 11:23:18.611157836 +0200
+++ /var/tmp/diff_new_pack.EZYHrD/_new  2018-10-22 11:23:18.611157836 +0200
@@ -19,7 +19,7 @@
 %define dbdir %{_sysconfdir}/target
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-rtslib-fb
-Version:        2.1.67
+Version:        2.1.69
 Release:        0%{?dist}
 Summary:        API for Linux kernel SCSI target (aka LIO)
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.EZYHrD/_old  2018-10-22 11:23:18.635157812 +0200
+++ /var/tmp/diff_new_pack.EZYHrD/_new  2018-10-22 11:23:18.635157812 +0200
@@ -7,7 +7,7 @@
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(\d*\.\d*\.)fb(\d*)</param>
     <param name="versionrewrite-replacement">\1\2</param>
-    <param name="revision">v2.1.fb67</param>
+    <param name="revision">v2.1.fb69</param>
     <param name="changesgenerate">enable</param>
   </service>
   <service name="recompress" mode="disabled">

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.EZYHrD/_old  2018-10-22 11:23:18.651157796 +0200
+++ /var/tmp/diff_new_pack.EZYHrD/_new  2018-10-22 11:23:18.651157796 +0200
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
             <param 
name="url">https://github.com/open-iscsi/rtslib-fb.git</param>
-          <param 
name="changesrevision">a46e6bf9ea0f83acdff1761a11c502ea5863945f</param></service></servicedata>
\ No newline at end of file
+          <param 
name="changesrevision">b2ec3746fb772aa3ff8b8853965292ca7dc2d7b1</param></service></servicedata>
\ No newline at end of file

++++++ python-rtslib-fb-2.1.67.tar.xz -> python-rtslib-fb-2.1.69.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/rtslib/alua.py 
new/python-rtslib-fb-2.1.69/rtslib/alua.py
--- old/python-rtslib-fb-2.1.67/rtslib/alua.py  2018-02-12 18:34:38.000000000 
+0100
+++ new/python-rtslib-fb-2.1.69/rtslib/alua.py  2018-09-18 08:47:13.000000000 
+0200
@@ -19,6 +19,7 @@
 
 from .node import CFSNode
 from .utils import RTSLibError, RTSLibALUANotSupported, fread, fwrite
+import six
 
 alua_rw_params = ['alua_access_state', 'alua_access_status',
                   'alua_write_metadata', 'alua_access_type', 'preferred',
@@ -393,5 +394,10 @@
             return
 
         alua_tpg_obj = cls(storage_obj, name, alua_tpg['tg_pt_gp_id'])
-        for param in alua_rw_params:
-            setattr(alua_tpg_obj, param, alua_tpg[param])
+        for param, value in six.iteritems(alua_tpg):
+            if param != 'name' and param != 'tg_pt_gp_id':
+                try:
+                    setattr(alua_tpg_obj, param, value)
+                except:
+                    raise RTSLibError("Could not set attribute '%s' for alua 
tpg '%s'"
+                                      % (param, alua_tpg['name']))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/rtslib/root.py 
new/python-rtslib-fb-2.1.69/rtslib/root.py
--- old/python-rtslib-fb-2.1.67/rtslib/root.py  2018-02-12 18:34:38.000000000 
+0100
+++ new/python-rtslib-fb-2.1.69/rtslib/root.py  2018-09-18 08:47:13.000000000 
+0200
@@ -22,6 +22,7 @@
 import stat
 import json
 import glob
+import errno
 
 from .node import CFSNode
 from .target import Target
@@ -176,6 +177,88 @@
     def _get_dbroot(self):
         return self._dbroot
 
+    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()
+
+        try:
+            with open(save_file, "r") as f:
+                saveconf = json.loads(f.read())
+        except IOError as e:
+            if e.errno == errno.ENOENT:
+                saveconf = {'storage_objects': [], 'targets': []}
+            else:
+                raise ExecutionError("Could not open %s" % save_file)
+
+        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):
@@ -290,7 +373,7 @@
 
         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'.
@@ -298,9 +381,14 @@
         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())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/rtslib/target.py 
new/python-rtslib-fb-2.1.69/rtslib/target.py
--- old/python-rtslib-fb-2.1.67/rtslib/target.py        2018-02-12 
18:34:38.000000000 +0100
+++ new/python-rtslib-fb-2.1.69/rtslib/target.py        2018-09-18 
08:47:13.000000000 +0200
@@ -464,7 +464,7 @@
     A LUN is identified by its parent TPG and LUN index.
     '''
 
-    MAX_LUN = 255
+    MAX_TARGET_LUN = 65535
 
     # LUN private stuff
 
@@ -487,7 +487,7 @@
         @param parent_tpg: The parent TPG object.
         @type parent_tpg: TPG
         @param lun: The LUN index.
-        @type lun: 0-255
+        @type lun: 0-65535
         @param storage_object: The storage object to be exported as a LUN.
         @type storage_object: StorageObject subclass
         @param alias: An optional parameter to manually specify the LUN alias.
@@ -504,16 +504,16 @@
 
         if lun is None:
             luns = [l.lun for l in self.parent_tpg.luns]
-            for index in range(self.MAX_LUN+1):
+            for index in range(self.MAX_TARGET_LUN+1):
                 if index not in luns:
                     lun = index
                     break
             if lun is None:
-                raise RTSLibError("All LUNs 0-%d in use" % self.MAX_LUN)
+                raise RTSLibError("All LUNs 0-%d in use" % self.MAX_TARGET_LUN)
         else:
             lun = int(lun)
-            if lun < 0 or lun > self.MAX_LUN:
-                raise RTSLibError("LUN must be 0 to %d" % self.MAX_LUN)
+            if lun < 0 or lun > self.MAX_TARGET_LUN:
+                raise RTSLibError("LUN must be 0 to %d" % self.MAX_TARGET_LUN)
 
         self._lun = lun
 
@@ -1060,6 +1060,8 @@
     the initiator node as the MappedLUN.
     '''
 
+    MAX_LUN = 255
+
     # MappedLUN private stuff
 
     def __repr__(self):
@@ -1107,6 +1109,9 @@
             raise RTSLibError("The mapped_lun parameter must be an " \
                               + "integer value")
 
+        if self._mapped_lun < 0 or self._mapped_lun > self.MAX_LUN:
+            raise RTSLibError("Mapped LUN must be 0 to %d" % self.MAX_LUN)
+
         self._path = "%s/lun_%d" % (self.parent_nodeacl.path, self.mapped_lun)
 
         if tpg_lun is None and write_protect is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/rtslib/tcm.py 
new/python-rtslib-fb-2.1.69/rtslib/tcm.py
--- old/python-rtslib-fb-2.1.67/rtslib/tcm.py   2018-02-12 18:34:38.000000000 
+0100
+++ new/python-rtslib-fb-2.1.69/rtslib/tcm.py   2018-09-18 08:47:13.000000000 
+0200
@@ -184,8 +184,11 @@
     def _parse_info(self, key):
         self._check_self()
         info = fread("%s/info" % self.path)
-        return re.search(".*%s: ([^: ]+).*" \
-                         % key, ' '.join(info.split())).group(1)
+        try:
+            return re.search(".*%s: ([^: ]+).*" \
+                             % key, ' '.join(info.split())).group(1)
+        except AttributeError:
+            return None
 
     def _get_status(self):
         self._check_self()
@@ -248,7 +251,7 @@
 
     # StorageObject public stuff
 
-    def delete(self):
+    def delete(self, save=False):
         '''
         Recursively deletes a StorageObject object.
         This will delete all attached LUNs currently using the StorageObject
@@ -271,6 +274,9 @@
 
         super(StorageObject, self).delete()
         self._backstore.delete()
+        if save:
+            from .root import RTSRoot, default_save_file
+            RTSRoot().save_to_file(default_save_file, '/backstores/' + 
self.plugin  + '/' + self._name)
 
     def is_configured(self):
         '''
@@ -569,7 +575,7 @@
     # FileIOStorageObject private stuff
 
     def __init__(self, name, dev=None, size=None,
-                 wwn=None, write_back=False):
+                 wwn=None, write_back=False, aio=False):
         '''
         A FileIOStorageObject can be instantiated in two ways:
             - B{Creation mode}: If I{dev} and I{size} are specified, the
@@ -603,14 +609,14 @@
         if dev is not None:
             super(FileIOStorageObject, self).__init__(name, 'create')
             try:
-                self._configure(dev, size, wwn, write_back)
+                self._configure(dev, size, wwn, write_back, aio)
             except:
                 self.delete()
                 raise
         else:
             super(FileIOStorageObject, self).__init__(name, 'lookup')
 
-    def _configure(self, dev, size, wwn, write_back):
+    def _configure(self, dev, size, wwn, write_back, aio):
         self._check_self()
         block_type = get_blockdev_type(dev)
         if block_type is None: # a file
@@ -638,6 +644,9 @@
             self.set_attribute("emulate_write_cache", 1)
             self._control("fd_buffered_io=%d" % write_back)
 
+        if aio:
+            self._control("fd_async_io=%d" % aio)
+
         self._set_udev_path(dev)
 
         self._enable()
@@ -660,6 +669,15 @@
     def _is_block(self):
         return get_blockdev_type(self.udev_path) is not None
 
+    def _aio(self):
+        self._check_self()
+        info = fread("%s/info" % self.path)
+        r = re.search(".*Async: ([^: ]+).*", ' '.join(info.split()))
+        if not r:  # for backward compatibility with old kernels
+            return False
+
+        return bool(int(r.group(1)))
+
     # FileIOStorageObject public stuff
 
     write_back = property(_get_wb_enabled,
@@ -668,6 +686,8 @@
             doc="Get the current FileIOStorage size in bytes")
     is_block = property(_is_block,
             doc="True if FileIoStorage is backed by a block device instead of 
a file")
+    aio = property(_aio,
+            doc="True if asynchronous I/O is enabled")
 
     def dump(self):
         d = super(FileIOStorageObject, self).dump()
@@ -675,6 +695,7 @@
         d['wwn'] = self.wwn
         d['dev'] = self.udev_path
         d['size'] = self.size
+        d['aio'] = self.aio
         return d
 
 
@@ -787,7 +808,7 @@
     '''
 
     def __init__(self, name, config=None, size=None, wwn=None,
-                 hw_max_sectors=None):
+                 hw_max_sectors=None, control=None):
         '''
         @param name: The name of the UserBackedStorageObject.
         @type name: string
@@ -800,6 +821,9 @@
         @type wwn: string
         @hw_max_sectors: Max sectors per command limit to export to initiators.
         @type hw_max_sectors: int
+        @control: String of control=value tuples separate by a ',' that will
+            passed to the kernel control file.
+        @type: string
         @return: A UserBackedStorageObject object.
         '''
 
@@ -812,14 +836,14 @@
                                   "from its configuration string")
             super(UserBackedStorageObject, self).__init__(name, 'create')
             try:
-                self._configure(config, size, wwn, hw_max_sectors)
+                self._configure(config, size, wwn, hw_max_sectors, control)
             except:
                 self.delete()
                 raise
         else:
             super(UserBackedStorageObject, self).__init__(name, 'lookup')
 
-    def _configure(self, config, size, wwn, hw_max_sectors):
+    def _configure(self, config, size, wwn, hw_max_sectors, control):
         self._check_self()
 
         if ':' in config:
@@ -828,6 +852,8 @@
         self._control("dev_size=%d" % size)
         if hw_max_sectors is not None:
             self._control("hw_max_sectors=%s" % hw_max_sectors)
+        if control is not None:
+            self._control(control)
         self._enable()
 
         super(UserBackedStorageObject, self)._configure(wwn)
@@ -840,6 +866,17 @@
         self._check_self()
         return int(self._parse_info('HwMaxSectors'))
 
+    def _get_control_tuples(self):
+        self._check_self()
+        tuples = []
+        # 1. max_data_area_mb
+        val = self._parse_info('MaxDataAreaMB')
+        if val != "NULL":
+            tuples.append("max_data_area_mb=%s" % val)
+        # 2. add next ...
+
+        return ",".join(tuples)
+
     def _get_config(self):
         self._check_self()
         val = self._parse_info('Config')
@@ -853,6 +890,8 @@
 
     hw_max_sectors = property(_get_hw_max_sectors,
             doc="Get the max sectors per command.")
+    control_tuples = property(_get_control_tuples,
+            doc="Get the comma separated string containing control=value 
tuples.")
     size = property(_get_size,
             doc="Get the size in bytes.")
     config = property(_get_config,
@@ -866,6 +905,7 @@
         d['size'] = self.size
         d['config'] = self.config
         d['hw_max_sectors'] = self.hw_max_sectors
+        d['control'] = self.control_tuples
 
         return d
 
@@ -975,8 +1015,11 @@
     def _parse_info(self, key):
         self._check_self()
         info = fread("%s/hba_info" % self.path)
-        return re.search(".*%s: ([^: ]+).*" \
-                         % key, ' '.join(info.split())).group(1)
+        try:
+            return re.search(".*%s: ([^: ]+).*" \
+                             % key, ' '.join(info.split())).group(1)
+        except AttributeError:
+            return None
 
     def _get_version(self):
         self._check_self()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/rtslib/utils.py 
new/python-rtslib-fb-2.1.69/rtslib/utils.py
--- old/python-rtslib-fb-2.1.67/rtslib/utils.py 2018-02-12 18:34:38.000000000 
+0100
+++ new/python-rtslib-fb-2.1.69/rtslib/utils.py 2018-09-18 08:47:13.000000000 
+0200
@@ -326,7 +326,7 @@
     if wwn_type == 'unit_serial':
         return str(uuid.uuid4())
     elif wwn_type == 'iqn':
-        localname = socket.gethostname().split(".")[0]
+        localname = socket.gethostname().split(".")[0].replace("_", "")
         localarch = os.uname()[4].replace("_", "")
         prefix = "iqn.2003-01.org.linux-iscsi.%s.%s" % (localname, localarch)
         prefix = prefix.strip().lower()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/setup.py 
new/python-rtslib-fb-2.1.69/setup.py
--- old/python-rtslib-fb-2.1.67/setup.py        2018-02-12 18:34:38.000000000 
+0100
+++ new/python-rtslib-fb-2.1.69/setup.py        2018-09-18 08:47:13.000000000 
+0200
@@ -20,7 +20,7 @@
 
 setup (
     name = 'rtslib-fb',
-    version = '2.1.67',
+    version = '2.1.69',
     description = 'API for Linux kernel SCSI target (aka LIO)',
     license = 'Apache 2.0',
     maintainer = 'Andy Grover',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/systemd/README.md 
new/python-rtslib-fb-2.1.69/systemd/README.md
--- old/python-rtslib-fb-2.1.67/systemd/README.md       1970-01-01 
01:00:00.000000000 +0100
+++ new/python-rtslib-fb-2.1.69/systemd/README.md       2018-09-18 
08:47:13.000000000 +0200
@@ -0,0 +1,8 @@
+### Service file for rtslib-fb use with systemd
+
+The systemd developers encourage upstream projects to ship and install
+a service file, saving each systemd-based distribution from having to
+create one.
+
+In this directory is the systemd service file for rtslib-fb. However,
+it is not currently installed by default.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-rtslib-fb-2.1.67/systemd/target.service 
new/python-rtslib-fb-2.1.69/systemd/target.service
--- old/python-rtslib-fb-2.1.67/systemd/target.service  1970-01-01 
01:00:00.000000000 +0100
+++ new/python-rtslib-fb-2.1.69/systemd/target.service  2018-09-18 
08:47:13.000000000 +0200
@@ -0,0 +1,15 @@
+[Unit]
+Description=Restore LIO kernel target configuration
+Requires=sys-kernel-config.mount
+After=sys-kernel-config.mount network.target local-fs.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/usr/bin/targetctl restore
+ExecStop=/usr/bin/targetctl clear
+SyslogIdentifier=target
+
+[Install]
+WantedBy=multi-user.target
+


Reply via email to