Hello community,

here is the log from the commit of package nvmetcli for openSUSE:Factory 
checked in at 2020-03-31 17:15:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nvmetcli (Old)
 and      /work/SRC/openSUSE:Factory/.nvmetcli.new.3160 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nvmetcli"

Tue Mar 31 17:15:54 2020 rev:10 rq:790010 version:0.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/nvmetcli/nvmetcli.changes        2018-04-19 
15:32:46.574952117 +0200
+++ /work/SRC/openSUSE:Factory/.nvmetcli.new.3160/nvmetcli.changes      
2020-03-31 17:16:04.759659379 +0200
@@ -1,0 +2,18 @@
+Fri Mar 27 07:48:31 UTC 2020 - h...@suse.de
+
+- Update to version v0.7:
+  * bump version to v0.7
+  * nvmetcli: ANA configuration support
+  * nvmetcli: simplify the enabled logic
+  * nvmetcli: pep8 fixes
+  * nvmetcli: support inline_data_size port parameter
+  * Revert "nvmetcli: expose nvmet port status and state"
+  * Support python3 dictionary access.
+  * nvmetcli: expose nvmet port status and state
+- Remove patch merged with upstream
+  * nvmetcli-make-dict-access-python-version-independant.patch
+- 'clear' command doesn't handle ANA groups correctly (bsc#1167644)
+  adding patch
+  - 0001-nvmetcli-don-t-remove-ANA-Group-1-on-clear.patch
+
+-------------------------------------------------------------------

Old:
----
  nvmetcli-make-dict-access-python-version-independant.patch
  nvmetcli-v0.6.tar.gz

New:
----
  0001-nvmetcli-don-t-remove-ANA-Group-1-on-clear.patch
  nvmetcli-v0.7.tar.gz

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

Other differences:
------------------
++++++ nvmetcli.spec ++++++
--- /var/tmp/diff_new_pack.sw0Klo/_old  2020-03-31 17:16:05.591659908 +0200
+++ /var/tmp/diff_new_pack.sw0Klo/_new  2020-03-31 17:16:05.595659910 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package nvmetcli
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           nvmetcli
-Version:        0.6
+Version:        0.7
 Release:        1%{?dist}
 Summary:        Command line interface for the kernel NVMe nvmet
 License:        Apache-2.0
@@ -25,7 +25,7 @@
 Url:            http://git.infradead.org/users/hch/nvmetcli.git
 Source:         nvmetcli-v%{version}.tar.gz
 Patch1:         %{name}-update-python-to-python3.patch
-Patch2:         %{name}-make-dict-access-python-version-independant.patch
+Patch2:         0001-nvmetcli-don-t-remove-ANA-Group-1-on-clear.patch
 BuildRequires:  python3-devel
 BuildRequires:  python3-setuptools
 Requires:       python3-configshell-fb

++++++ 0001-nvmetcli-don-t-remove-ANA-Group-1-on-clear.patch ++++++
>From 5e5e45f5e2800ff1f791e67f683891963f1583a4 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <h...@suse.de>
Date: Fri, 27 Mar 2020 07:55:34 +0100
Subject: [PATCH] nvmetcli: don't remove ANA Group 1 on clear

The first ANA group is maintained by the kernel so it cannot
be deleted.

Signed-off-by: Hannes Reinecke <h...@suse.de>
---
 nvmet/nvme.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/nvmet/nvme.py b/nvmet/nvme.py
index 0647ddc..fdec4ff 100644
--- a/nvmet/nvme.py
+++ b/nvmet/nvme.py
@@ -845,6 +845,11 @@ class ANAGroup(CFSNode):
 
         a._setup_attrs(n, err_func)
 
+    def delete(self):
+        # ANA Group 1 is automatically created/deleted
+        if self.grpid != 1:
+            super(ANAGroup, self).delete()
+
     def dump(self):
         d = super(ANAGroup, self).dump()
         d['grpid'] = self.grpid
-- 
2.16.4

++++++ _service ++++++
--- /var/tmp/diff_new_pack.sw0Klo/_old  2020-03-31 17:16:05.623659928 +0200
+++ /var/tmp/diff_new_pack.sw0Klo/_new  2020-03-31 17:16:05.623659928 +0200
@@ -4,8 +4,8 @@
     <param name="scm">git</param>
     <param name="url">git://git.infradead.org/users/hch/nvmetcli.git</param>
     <param name="filename">nvmetcli</param>
-    <param name="version">v0.6</param>
-    <param name="revision">v0.6</param>
+    <param name="version">v0.7</param>
+    <param name="revision">v0.7</param>
     <param name="exclude">.git</param>
     <param name="changesgenerate">enable</param>
   </service>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.sw0Klo/_old  2020-03-31 17:16:05.635659935 +0200
+++ /var/tmp/diff_new_pack.sw0Klo/_new  2020-03-31 17:16:05.635659935 +0200
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
             <param 
name="url">git://git.infradead.org/users/hch/nvmetcli.git</param>
-          <param 
name="changesrevision">9d51ae651a1c39a83b0192fbbe1e400abf3a0409</param></service></servicedata>
\ No newline at end of file
+          <param 
name="changesrevision">0a6b088db2dc2e5de11e6f23f1e890e4b54fee64</param></service></servicedata>
\ No newline at end of file

++++++ nvmetcli-v0.6.tar.gz -> nvmetcli-v0.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nvmetcli-v0.6/README new/nvmetcli-v0.7/README
--- old/nvmetcli-v0.6/README    2018-01-22 19:45:05.000000000 +0100
+++ new/nvmetcli-v0.7/README    2019-04-28 14:47:14.000000000 +0200
@@ -14,9 +14,11 @@
 
 Common Package Dependencies and Problems
 -----------------------------------------
-nvmetcli uses the 'python-six' and 'pyparsing' packages
-(running nvmetcli without these packages may produce
-hard-to-decipher errors).
+Both python2 and python3 are supported via use of the 'python-six'
+package.
+
+nvmetcli uses the 'pyparsing' package -- running nvmetcli without this
+package may produce hard-to-decipher errors.
 
 Usage
 -----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nvmetcli-v0.6/nvmet/__init__.py 
new/nvmetcli-v0.7/nvmet/__init__.py
--- old/nvmetcli-v0.6/nvmet/__init__.py 2018-01-22 19:45:05.000000000 +0100
+++ new/nvmetcli-v0.7/nvmet/__init__.py 2019-04-28 14:47:14.000000000 +0200
@@ -1 +1 @@
-from .nvme import Root, Subsystem, Namespace, Port, Host, Referral
+from .nvme import Root, Subsystem, Namespace, Port, Host, Referral, ANAGroup
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nvmetcli-v0.6/nvmet/nvme.py 
new/nvmetcli-v0.7/nvmet/nvme.py
--- old/nvmetcli-v0.6/nvmet/nvme.py     2018-01-22 19:45:05.000000000 +0100
+++ new/nvmetcli-v0.7/nvmet/nvme.py     2019-04-28 14:47:14.000000000 +0200
@@ -23,6 +23,7 @@
 import uuid
 import json
 from glob import iglob as glob
+from six import iteritems
 
 DEFAULT_SAVE_FILE = '/etc/nvmet/config.json'
 
@@ -219,7 +220,7 @@
 
     def _setup_attrs(self, attr_dict, err_func):
         for group in self.attr_groups:
-            for name, value in attr_dict.get(group, {}).iteritems():
+            for name, value in iteritems(attr_dict.get(group, {})):
                 try:
                     self.set_attr(group, name, value)
                 except CFSError as e:
@@ -565,6 +566,24 @@
     def _get_nsid(self):
         return self._nsid
 
+    def _get_grpid(self):
+        self._check_self()
+        _grpid = 0
+        path = "%s/ana_grpid" % self.path
+        if os.path.isfile(path):
+            with open(path, 'r') as file_fd:
+                _grpid = int(file_fd.read().strip())
+        return _grpid
+
+    def set_grpid(self, grpid):
+        self._check_self()
+        path = "%s/ana_grpid" % self.path
+        if os.path.isfile(path):
+            with open(path, 'w') as file_fd:
+                file_fd.write(str(grpid))
+
+    grpid = property(_get_grpid, doc="Get the ANA Group ID.")
+
     subsystem = property(_get_subsystem,
                          doc="Get the parent Subsystem object.")
     nsid = property(_get_nsid, doc="Get the NSID as an int.")
@@ -588,10 +607,13 @@
             return
 
         ns._setup_attrs(n, err_func)
+        if 'ana_grpid' in n:
+            ns.set_grpid(int(n['ana_grpid']))
 
     def dump(self):
         d = super(Namespace, self).dump()
         d['nsid'] = self.nsid
+        d['ana_grpid'] = self.grpid
         return d
 
 
@@ -608,7 +630,7 @@
     def __init__(self, portid, mode='any'):
         super(Port, self).__init__()
 
-        self.attr_groups = ['addr']
+        self.attr_groups = ['addr', 'param']
         self._portid = int(portid)
         self._path = "%s/ports/%d" % (self.configfs_dir, self._portid)
         self._create_in_cfs(mode)
@@ -651,6 +673,8 @@
         self._check_self()
         for s in self.subsystems:
             self.remove_subsystem(s)
+        for a in self.ana_groups:
+            a.delete()
         for r in self.referrals:
             r.delete()
         super(Port, self).delete()
@@ -663,10 +687,19 @@
     referrals = property(_list_referrals,
                          doc="Get the list of Referrals for this Port.")
 
+    def _list_ana_groups(self):
+        self._check_self()
+        if os.path.isdir("%s/ana_groups/" % self._path):
+            for d in os.listdir("%s/ana_groups/" % self._path):
+                yield ANAGroup(self, int(d), 'lookup')
+
+    ana_groups = property(_list_ana_groups,
+                          doc="Get the list of ANA Groups for this Port.")
+
     @classmethod
     def setup(cls, root, n, err_func):
         '''
-        Set up a Namespace object based upon n dict, from saved config.
+        Set up a Port object based upon n dict, from saved config.
         Guard against missing or bad dict items, but keep going.
         Call 'err_func' for each error.
         '''
@@ -684,6 +717,8 @@
         port._setup_attrs(n, err_func)
         for s in n.get('subsystems', []):
             port.add_subsystem(s)
+        for a in n.get('ana_groups', []):
+            ANAGroup.setup(port, a, err_func)
         for r in n.get('referrals', []):
             Referral.setup(port, r, err_func)
 
@@ -691,6 +726,7 @@
         d = super(Port, self).dump()
         d['portid'] = self.portid
         d['subsystems'] = self.subsystems
+        d['ana_groups'] = [a.dump() for a in self.ana_groups]
         d['referrals'] = [r.dump() for r in self.referrals]
         return d
 
@@ -746,6 +782,75 @@
         return d
 
 
+class ANAGroup(CFSNode):
+    '''
+    This is an interface to a NVMe ANA Group in configFS.
+    '''
+
+    MAX_GRPID = 1024
+
+    def __repr__(self):
+        return "<ANA Group %d>" % self.grpid
+
+    def __init__(self, port, grpid, mode='any'):
+        super(ANAGroup, self).__init__()
+
+        if not os.path.isdir("%s/ana_groups" % port.path):
+            raise CFSError("ANA not supported")
+
+        if grpid is None:
+            if mode == 'lookup':
+                raise CFSError("Need grpid for lookup")
+
+            grpids = [n.grpid for n in port.ana_groups]
+            for index in xrange(2, self.MAX_GRPID + 1):
+                if index not in grpids:
+                    grpid = index
+                    break
+            if grpid is None:
+                raise CFSError("All ANA Group IDs 1-%d in use" % 
self.MAX_GRPID)
+        else:
+            grpid = int(grpid)
+            if grpid < 1 or grpid > self.MAX_GRPID:
+                raise CFSError("GRPID %d must be 1 to %d" % (grpid, 
self.MAX_GRPID))
+
+        self.attr_groups = ['ana']
+        self._port = port
+        self._grpid = grpid
+        self._path = "%s/ana_groups/%d" % (self._port.path, self.grpid)
+        self._create_in_cfs(mode)
+
+    def _get_grpid(self):
+        return self._grpid
+
+    grpid = property(_get_grpid, doc="Get the ANA Group ID.")
+
+    @classmethod
+    def setup(cls, port, n, err_func):
+        '''
+        Set up an ANA Group object based upon n dict, from saved config.
+        Guard against missing or bad dict items, but keep going.
+        Call 'err_func' for each error.
+        '''
+
+        if 'grpid' not in n:
+            err_func("'grpid' not defined for ANA Group")
+            return
+
+        try:
+            a = ANAGroup(port, n['grpid'])
+        except CFSError as e:
+            err_func("Could not create ANA Group object: %s" % e)
+            return
+
+        a._setup_attrs(n, err_func)
+
+    def dump(self):
+        d = super(ANAGroup, self).dump()
+        d['grpid'] = self.grpid
+        return d
+
+
 class Host(CFSNode):
     '''
     This is an interface to a NVMe Host in configFS.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nvmetcli-v0.6/nvmetcli new/nvmetcli-v0.7/nvmetcli
--- old/nvmetcli-v0.6/nvmetcli  2018-01-22 19:45:05.000000000 +0100
+++ new/nvmetcli-v0.7/nvmetcli  2019-04-28 14:47:14.000000000 +0200
@@ -27,9 +27,11 @@
 from string import hexdigits
 import uuid
 
+
 def ngiud_set(nguid):
     return any(c in hexdigits and c != '0' for c in nguid)
 
+
 class UINode(configshell.node.ConfigNode):
     def __init__(self, name, parent=None, cfnode=None, shell=None):
         configshell.node.ConfigNode.__init__(self, name, parent, shell)
@@ -166,9 +168,10 @@
 
     def summary(self):
         info = []
-        info.append("version=" + self.cfnode.get_attr("attr","version"))
-        info.append("allow_any=" + 
self.cfnode.get_attr("attr","allow_any_host"))
-        info.append("serial=" + self.cfnode.get_attr("attr","serial"))
+        info.append("version=" + self.cfnode.get_attr("attr", "version"))
+        info.append("allow_any=" +
+                    self.cfnode.get_attr("attr", "allow_any_host"))
+        info.append("serial=" + self.cfnode.get_attr("attr", "serial"))
         return (", ".join(info), True)
 
 
@@ -258,6 +261,16 @@
                 raise configshell.ExecutionError(
                     "The Namespace could not be disabled.")
 
+    def ui_command_grpid(self, grpid):
+        '''
+        Sets the ANA Group ID of the current Namespace to I{grpid}
+        '''
+        try:
+            self.cfnode.set_grpid(grpid)
+        except Exception as e:
+            raise configshell.ExecutionError(
+                "Failed to set ANA Group ID for this Namespace.")
+
     def summary(self):
         info = []
         info.append("path=" + self.cfnode.get_attr("device", "path"))
@@ -267,6 +280,8 @@
         ns_nguid = self.cfnode.get_attr("device", "nguid")
         if ngiud_set(ns_nguid):
             info.append("nguid=" + ns_nguid)
+        if self.cfnode.grpid != 0:
+            info.append("grpid=" + str(self.cfnode.grpid))
         info.append("enabled" if self.cfnode.get_enable() else "disabled")
         ns_enabled = self.cfnode.get_enable()
         return (", ".join(info), True if ns_enabled == 1 else ns_enabled)
@@ -370,14 +385,24 @@
     ui_desc_addr = {
         'adrfam': ('string', 'Address Family (e.g. ipv4 or fc)'),
         'treq': ('string', 'Transport Security Requirements'),
-        'traddr': ('string', 'Transport Address (e.g. IP Address or FC 
wwnn:wwpn)'),
+        'traddr': ('string',
+                   'Transport Address (e.g. IP Address or FC wwnn:wwpn)'),
         'trsvcid': ('string', 'Transport Service ID (e.g. IP Port)'),
         'trtype': ('string', 'Transport Type (e.g. rdma or loop or fc)'),
     }
+    ui_desc_param = {
+        'inline_data_size': ('string', 'Port inline data size in bytes'),
+    }
 
     def __init__(self, parent, cfnode):
         UINode.__init__(self, str(cfnode.portid), parent, cfnode)
         UIPortSubsystemsNode(self)
+        try:
+            next(cfnode.ana_groups)
+        except StopIteration:
+            pass
+        else:
+            UIANAGroupsNode(self)
         UIReferralsNode(self)
 
     def summary(self):
@@ -387,9 +412,20 @@
         trsvcid = self.cfnode.get_attr("addr", "trsvcid")
         if trsvcid != "none":
             info.append("trsvcid=%s" % trsvcid)
-        enabled = not (not self.cfnode.subsystems and not 
list(self.cfnode.referrals))
+
+        '''
+        Support older target driver w/o the inline_data_size parameter
+        '''
+        try:
+            inline_data_size = self.cfnode.get_attr("param", 
"inline_data_size")
+        except Exception as e:
+            inline_data_size = "n/a"
+        if inline_data_size != "n/a":
+            info.append("inline_data_size=" + inline_data_size)
+        enabled = self.cfnode.subsystems or list(self.cfnode.referrals)
         return (", ".join(info), True if enabled else 0)
 
+
 class UIPortSubsystemsNode(UINode):
     def __init__(self, parent):
         UINode.__init__(self, 'subsystems', parent)
@@ -488,7 +524,8 @@
     ui_desc_addr = {
         'adrfam': ('string', 'Address Family (e.g. ipv4 or fc)'),
         'treq': ('string', 'Transport Security Requirements'),
-        'traddr': ('string', 'Transport Address (e.g. IP Address or FC 
wwnn:wwpn)'),
+        'traddr': ('string',
+                   'Transport Address (e.g. IP Address or FC wwnn:wwpn)'),
         'trsvcid': ('string', 'Transport Service ID (e.g. IP Port)'),
         'trtype': ('string', 'Transport Type (e.g. rdma or loop or fc)'),
         'portid': ('number', 'Port identifier'),
@@ -539,6 +576,52 @@
                     "The Referral could not be disabled.")
 
 
+class UIANAGroupsNode(UINode):
+    def __init__(self, parent):
+        UINode.__init__(self, 'ana_groups', parent)
+
+    def refresh(self):
+        self._children = set([])
+        for a in self.parent.cfnode.ana_groups:
+            UIANAGroupNode(self, a)
+
+    def ui_command_create(self, grpid):
+        '''
+        Creates a new ANA Group.
+
+        SEE ALSO
+        ========
+        B{delete}
+        '''
+        a = nvme.ANAGroup(self.parent.cfnode, grpid, mode='create')
+        UIANAGroupNode(self, a)
+
+    def ui_command_delete(self, grpid):
+        '''
+        Deletes the ANA Group with the specified I{name}.
+
+        SEE ALSO
+        ========
+        B{create}
+        '''
+        a = nvme.ANAGroup(self.parent.cfnode, grpid, mode='lookup')
+        a.delete()
+        self.refresh()
+
+
+class UIANAGroupNode(UINode):
+    ui_desc_ana = {
+        'state' : ('string', 'ANA state'),
+    }
+
+    def __init__(self, parent, cfnode):
+        UINode.__init__(self, str(cfnode.grpid), parent, cfnode)
+
+    def summary(self):
+        info = []
+        info.append("state=" + self.cfnode.get_attr("ana", "state"))
+        return (", ".join(info), True)
+
 class UIHostsNode(UINode):
     def __init__(self, parent):
         UINode.__init__(self, 'hosts', parent)
@@ -652,5 +735,6 @@
         except Exception as msg:
             shell.log.error(str(msg))
 
+
 if __name__ == "__main__":
     main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nvmetcli-v0.6/setup.py new/nvmetcli-v0.7/setup.py
--- old/nvmetcli-v0.6/setup.py  2018-01-22 19:45:05.000000000 +0100
+++ new/nvmetcli-v0.7/setup.py  2019-04-28 14:47:14.000000000 +0200
@@ -20,7 +20,7 @@
 
 setup(
     name = 'nvmetcli',
-    version = 0.6,
+    version = 0.7,
     description = 'NVMe target configuration tool',
     license = 'Apache 2.0',
     maintainer = 'Christoph Hellwig',


Reply via email to