Hello community,

here is the log from the commit of package ceph-iscsi for openSUSE:Factory 
checked in at 2019-04-09 20:18:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ceph-iscsi (Old)
 and      /work/SRC/openSUSE:Factory/.ceph-iscsi.new.3908 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ceph-iscsi"

Tue Apr  9 20:18:42 2019 rev:9 rq:692489 version:3.0+1554735444.g63aceaf

Changes:
--------
--- /work/SRC/openSUSE:Factory/ceph-iscsi/ceph-iscsi.changes    2019-03-26 
15:45:13.968092820 +0100
+++ /work/SRC/openSUSE:Factory/.ceph-iscsi.new.3908/ceph-iscsi.changes  
2019-04-09 20:18:42.421844161 +0200
@@ -1,0 +2,10 @@
+Mon Apr  8 14:35:04 UTC 2019 - [email protected]
+
+- Update to 3.0+1554735444.g63aceaf:
+  + Adds endpoints:
+    * /api/targetinfo/<target_iqn>
+    * /api/gatewayinfo
+    * /api/clientinfo/<target_iqn>/<client_iqn>
+  + Fix upgrade from config v3 when 'controls' field is missing
+
+-------------------------------------------------------------------

Old:
----
  ceph-iscsi-3.0+1553528639.g1149ac6.tar.gz

New:
----
  ceph-iscsi-3.0+1554735444.g63aceaf.tar.gz

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

Other differences:
------------------
++++++ ceph-iscsi.spec ++++++
--- /var/tmp/diff_new_pack.Ygo303/_old  2019-04-09 20:18:43.901846179 +0200
+++ /var/tmp/diff_new_pack.Ygo303/_new  2019-04-09 20:18:43.901846179 +0200
@@ -20,7 +20,7 @@
 
 
 Name:           ceph-iscsi
-Version:        3.0+1553528639.g1149ac6
+Version:        3.0+1554735444.g63aceaf
 Release:        1%{?dist}
 Group:          System/Filesystems
 Summary:        Python modules for Ceph iSCSI gateway configuration management

++++++ ceph-iscsi-3.0+1553528639.g1149ac6.tar.gz -> 
ceph-iscsi-3.0+1554735444.g63aceaf.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph-iscsi.spec 
new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph-iscsi.spec
--- old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph-iscsi.spec      2019-03-25 
16:43:59.851691154 +0100
+++ new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph-iscsi.spec      2019-04-08 
16:57:24.610585206 +0200
@@ -20,7 +20,7 @@
 
 
 Name:           ceph-iscsi
-Version:        3.0+1553528639.g1149ac6
+Version:        3.0+1554735444.g63aceaf
 Release:        1%{?dist}
 Group:          System/Filesystems
 Summary:        Python modules for Ceph iSCSI gateway configuration management
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph_iscsi_config/client.py 
new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph_iscsi_config/client.py
--- old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph_iscsi_config/client.py  
2019-03-25 16:43:59.583689649 +0100
+++ new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph_iscsi_config/client.py  
2019-04-08 16:57:24.310583510 +0200
@@ -235,6 +235,34 @@
             self.change_count += 1
 
     @staticmethod
+    def get_client_info(target_iqn, client_iqn):
+        result = {
+            "alias": '',
+            "state": '',
+            "ip_address": []
+        }
+        iscsi_fabric = ISCSIFabricModule()
+        target = Target(iscsi_fabric, target_iqn, 'lookup')
+        for tpg in target.tpgs:
+            if tpg.enable:
+                for client in tpg.node_acls:
+                    if client.node_wwn != client_iqn:
+                        continue
+                    session = client.session
+                    if session is None:
+                        break
+                    result['alias'] = session.get('alias')
+                    state = session.get('state').upper()
+                    result['state'] = state
+                    ips = set()
+                    if state == 'LOGGED_IN':
+                        for conn in session.get('connections'):
+                            ips.add(conn.get('address'))
+                        result['ip_address'] = list(ips)
+                    break
+        return result
+
+    @staticmethod
     def define_clients(logger, config, target_iqn):
         """
         define the clients (nodeACLs) to the gateway definition
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph_iscsi_config/common.py 
new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph_iscsi_config/common.py
--- old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph_iscsi_config/common.py  
2019-03-25 16:43:59.583689649 +0100
+++ new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph_iscsi_config/common.py  
2019-04-08 16:57:24.310583510 +0200
@@ -199,7 +199,7 @@
                 'clients': self.config['clients'],
                 'portals': portals,
                 'groups': self.config['groups'],
-                'controls': self.config['controls'],
+                'controls': self.config.get('controls', {}),
                 'ip_list': self.config['gateways']['ip_list']
             }
             self.add_item('discovery_auth', None, {
@@ -209,7 +209,8 @@
             self.add_item("targets", None, {})
             self.add_item("targets", iqn, target)
             self.update_item("targets", iqn, target)
-            self.del_item('controls', None)
+            if 'controls' in self.config:
+                self.del_item('controls', None)
             self.del_item('clients', None)
             self.del_item('groups', None)
             self.update_item("gateways", None, gateways)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph_iscsi_config/target.py 
new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph_iscsi_config/target.py
--- old/ceph-iscsi-3.0+1553528639.g1149ac6/ceph_iscsi_config/target.py  
2019-03-25 16:43:59.583689649 +0100
+++ new/ceph-iscsi-3.0+1554735444.g63aceaf/ceph_iscsi_config/target.py  
2019-04-08 16:57:24.310583510 +0200
@@ -709,3 +709,9 @@
                         config.del_item('gateways', local_gw)
 
                 config.commit()
+
+    @staticmethod
+    def get_num_sessions(target_iqn):
+        with 
open('/sys/kernel/config/target/iscsi/{}/fabric_statistics/iscsi_instance'
+                  '/sessions'.format(target_iqn)) as sessions_file:
+            return int(sessions_file.read().rstrip('\n'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ceph-iscsi-3.0+1553528639.g1149ac6/gwcli/client.py 
new/ceph-iscsi-3.0+1554735444.g63aceaf/gwcli/client.py
--- old/ceph-iscsi-3.0+1553528639.g1149ac6/gwcli/client.py      2019-03-25 
16:43:59.583689649 +0100
+++ new/ceph-iscsi-3.0+1554735444.g63aceaf/gwcli/client.py      2019-04-08 
16:57:24.314583532 +0200
@@ -2,11 +2,10 @@
 
 from gwcli.utils import response_message, APIRequest, get_config
 
-from ceph_iscsi_config.client import CHAP
+from ceph_iscsi_config.client import CHAP, GWClient
 import ceph_iscsi_config.settings as settings
 from ceph_iscsi_config.utils import human_size
 
-import rtslib_fb.root as root
 from rtslib_fb.utils import normalize_wwn, RTSLibError
 
 # this ignores the warning issued when verify=False is used
@@ -690,22 +689,11 @@
 
     @property
     def logged_in(self):
-
-        r = root.RTSRoot()
-        for sess in r.sessions:
-            if sess['parent_nodeacl'].node_wwn == self.client_iqn:
-                self.alias = sess.get('alias')
-                state = sess.get('state').upper()
-                ips = set()
-                if state == 'LOGGED_IN':
-                    for conn in sess.get('connections'):
-                        ips.add(conn.get('address'))
-                    self.ip_address = ','.join(list(ips))
-                else:
-                    self.ip_address = ''
-
-                return state
-        return ''
+        target_iqn = self.parent.parent.name
+        client_info = GWClient.get_client_info(target_iqn, self.client_iqn)
+        self.alias = client_info['alias']
+        self.ip_address = ','.join(client_info['ip_address'])
+        return client_info['state']
 
 
 class MappedLun(UINode):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ceph-iscsi-3.0+1553528639.g1149ac6/gwcli/utils.py 
new/ceph-iscsi-3.0+1554735444.g63aceaf/gwcli/utils.py
--- old/ceph-iscsi-3.0+1553528639.g1149ac6/gwcli/utils.py       2019-03-25 
16:43:59.587689671 +0100
+++ new/ceph-iscsi-3.0+1554735444.g63aceaf/gwcli/utils.py       2019-04-08 
16:57:24.314583532 +0200
@@ -8,8 +8,8 @@
 
 
 from rtslib_fb.utils import normalize_wwn, RTSLibError
-import rtslib_fb.root as root
 
+from ceph_iscsi_config.client import GWClient
 import ceph_iscsi_config.settings as settings
 from ceph_iscsi_config.utils import (resolve_ip_addresses, gen_file_hash,
                                      CephiSCSIError)
@@ -283,14 +283,10 @@
         # client to delete must not be logged in - we're just checking locally,
         # since *all* nodes are set up the same, and a client login request
         # would normally login to each gateway
-        lio_root = root.RTSRoot()
-        clients_logged_in = [session['parent_nodeacl'].node_wwn
-                             for session in lio_root.sessions
-                             if session['state'] == 'LOGGED_IN']
-
-        if client_iqn in clients_logged_in:
-            return ("Client '{}' is logged in - unable to delete until"
-                    " it's logged out".format(client_iqn))
+        client_info = GWClient.get_client_info(target_iqn, client_iqn)
+        if client_info['state'] == 'LOGGED_IN':
+            return ("Client '{}' is logged in to {}- unable to delete until"
+                    " it's logged out".format(client_iqn, target_iqn))
 
         # at this point, the client looks ok for a DELETE operation
         return 'ok'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ceph-iscsi-3.0+1553528639.g1149ac6/rbd-target-api.py 
new/ceph-iscsi-3.0+1554735444.g63aceaf/rbd-target-api.py
--- old/ceph-iscsi-3.0+1553528639.g1149ac6/rbd-target-api.py    2019-03-25 
16:43:59.587689671 +0100
+++ new/ceph-iscsi-3.0+1554735444.g63aceaf/rbd-target-api.py    2019-04-08 
16:57:24.314583532 +0200
@@ -1618,6 +1618,76 @@
     return jsonify(message='OK'), 200
 
 
[email protected]('/api/targetinfo/<target_iqn>', methods=['GET'])
+@requires_restricted_auth
+def targetinfo(target_iqn):
+    """
+    Returns the total number of active sessions for <target_iqn>
+    **RESTRICTED**
+    Examples:
+    curl --insecure --user admin:admin -X GET
+        
http://192.168.122.69:5000/api/targetinfo/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw
+    """
+    if target_iqn not in config.config['targets']:
+        return jsonify(message="Target {} does not exist".format(target_iqn)), 
400
+    target_config = config.config['targets'][target_iqn]
+    gateways = target_config['portals']
+    num_sessions = 0
+    for gateway in gateways.keys():
+        resp_text, resp_code = call_api([gateway], '_targetinfo', target_iqn, 
http_method='get')
+        if resp_code != 200:
+            return jsonify(message="{}".format(resp_text)), resp_code
+        gateway_response = json.loads(resp_text)
+        num_sessions += gateway_response['num_sessions']
+    return jsonify({
+        "num_sessions": num_sessions
+    }), 200
+
+
[email protected]('/api/_targetinfo/<target_iqn>', methods=['GET'])
+@requires_restricted_auth
+def _targetinfo(target_iqn):
+    """
+    Returns the number of active sessions for <target_iqn> on local gateway
+    **RESTRICTED**
+    Examples:
+    curl --insecure --user admin:admin -X GET
+        
http://192.168.122.69:5000/api/_targetinfo/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw
+    """
+    if target_iqn not in config.config['targets']:
+        return jsonify(message="Target {} does not exist".format(target_iqn)), 
400
+    target_config = config.config['targets'][target_iqn]
+    local_gw = this_host()
+    if local_gw not in target_config['portals']:
+        return jsonify(message="{} is not a portal of target 
{}".format(local_gw, target_iqn)), 400
+    num_sessions = GWTarget.get_num_sessions(target_iqn)
+    return jsonify({
+        "num_sessions": num_sessions
+    }), 200
+
+
[email protected]('/api/gatewayinfo', methods=['GET'])
+@requires_restricted_auth
+def gatewayinfo():
+    """
+    Returns the number of active sessions on local gateway
+    **RESTRICTED**
+    Examples:
+    curl --insecure --user admin:admin -X GET
+        http://192.168.122.69:5000/api/gatewayinfo
+    """
+    local_gw = this_host()
+    if local_gw not in config.config['gateways']:
+        return jsonify(message="Gateway {} does not exist in 
configuration".format(local_gw)), 400
+    num_sessions = 0
+    for target_iqn, target in config.config['targets'].items():
+        if local_gw in target['portals']:
+            num_sessions += GWTarget.get_num_sessions(target_iqn)
+    return jsonify({
+        "num_sessions": num_sessions
+    }), 200
+
+
 @app.route('/api/clients/<target_iqn>', methods=['GET'])
 @requires_restricted_auth
 def get_clients(target_iqn=None):
@@ -2059,6 +2129,73 @@
             return jsonify(message="Client does not exist!"), 404
 
 
[email protected]('/api/clientinfo/<target_iqn>/<client_iqn>', methods=['GET'])
+@requires_restricted_auth
+def clientinfo(target_iqn, client_iqn):
+    """
+    Returns client alias, ip_address and state for each connected portal
+    **RESTRICTED**
+    Examples:
+    curl --insecure --user admin:admin -X GET
+        http://192.168.122.69:5000/api/clientinfo/
+        
iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw-client
+    """
+    if target_iqn not in config.config['targets']:
+        return jsonify(message="Target {} does not exist".format(target_iqn)), 
400
+    target_config = config.config['targets'][target_iqn]
+    if client_iqn not in target_config['clients']:
+        return jsonify(message="Client {} does not exist".format(client_iqn)), 
400
+    gateways = target_config['portals']
+    response = {
+        "alias": '',
+        "state": {},
+        "ip_address": []
+    }
+    for gateway in gateways.keys():
+        resp_text, resp_code = call_api([gateway],
+                                        '_clientinfo',
+                                        '{}/{}'.format(target_iqn, client_iqn),
+                                        http_method='get')
+        if resp_code != 200:
+            return jsonify(message="{}".format(resp_text)), resp_code
+        gateway_response = json.loads(resp_text)
+        alias = gateway_response['alias']
+        if alias:
+            response['alias'] = gateway_response['alias']
+        state = gateway_response['state']
+        if state:
+            if state not in response['state']:
+                response['state'][state] = []
+            response['state'][state].append(gateway)
+        response['ip_address'].extend(gateway_response['ip_address'])
+    response['ip_address'] = list(set(response['ip_address']))
+    return jsonify(response), 200
+
+
[email protected]('/api/_clientinfo/<target_iqn>/<client_iqn>', methods=['GET'])
+@requires_restricted_auth
+def _clientinfo(target_iqn, client_iqn):
+    """
+    Returns client alias, ip_address and state for local gateway
+    **RESTRICTED**
+    Examples:
+    curl --insecure --user admin:admin -X GET
+        http://192.168.122.69:5000/api/_clientinfo/
+        
iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw/iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw-client
+    """
+    if target_iqn not in config.config['targets']:
+        return jsonify(message="Target {} does not exist".format(target_iqn)), 
400
+    target_config = config.config['targets'][target_iqn]
+    if client_iqn not in target_config['clients']:
+        return jsonify(message="Client {} does not exist".format(client_iqn)), 
400
+    local_gw = this_host()
+    if local_gw not in target_config['portals']:
+        return jsonify(message="{} is not a portal of target 
{}".format(local_gw, target_iqn)), 400
+
+    logged_in = GWClient.get_client_info(target_iqn, client_iqn)
+    return jsonify(logged_in), 200
+
+
 @app.route('/api/hostgroups/<target_iqn>', methods=['GET'])
 @requires_restricted_auth
 def hostgroups(target_iqn=None):
@@ -2444,7 +2581,7 @@
 
             return fail_msg, api.response.status_code
 
-    return "successful", 200
+    return api.response.text if http_method == 'get' else 'successful', 200
 
 
 def pre_reqs_errors():


Reply via email to