Browse Source

Fix deprecated API usage of keystone client

* Use keystoneauth1 for making session, which is shared throw all clients
* KeystoneClient is now only wrapper over session
Requirements has been updated to meet global requirements for mitaka release:
1. Bumped clients versions
2. requests has blacklisted versions due to bugs

Closes-bug: #1571611

Change-Id: Icc59761b590b76a8d3ddac9b4f219efc097447a5
tags/10.0.0rc1
Alexey Stepanov 3 years ago
parent
commit
e48d37a518

+ 113
- 86
fuelweb_test/helpers/common.py View File

@@ -16,14 +16,16 @@ import sys
16 16
 import time
17 17
 import traceback
18 18
 
19
-from cinderclient import client as cinderclient
19
+from cinderclient.client import Client as CinderClient
20 20
 from heatclient.v1.client import Client as HeatClient
21 21
 from glanceclient.v1 import Client as GlanceClient
22
-import ironicclient.client as ironicclient
22
+from ironicclient.client import Client as IronicClient
23
+from keystoneauth1.exceptions import ClientException
24
+from keystoneauth1.identity import V2Password
25
+from keystoneauth1.session import Session as KeystoneSession
23 26
 from keystoneclient.v2_0 import Client as KeystoneClient
24
-from keystoneclient.exceptions import ClientException
25
-from novaclient.v2 import Client as NovaClient
26
-import neutronclient.v2_0.client as neutronclient
27
+from novaclient.client import Client as NovaClient
28
+from neutronclient.v2_0.client import Client as NeutronClient
27 29
 from proboscis.asserts import assert_equal
28 30
 import six
29 31
 # pylint: disable=redefined-builtin
@@ -47,14 +49,16 @@ from fuelweb_test.settings import VERIFY_SSL
47 49
 class Common(object):
48 50
     """Common."""  # TODO documentation
49 51
 
52
+    def __make_endpoint(self, endpoint):
53
+        parse = urllib.parse.urlparse(endpoint)
54
+        return parse._replace(
55
+            netloc='{}:{}'.format(
56
+                self.controller_ip, parse.port)).geturl()
57
+
50 58
     def __init__(self, controller_ip, user, password, tenant):
51 59
         self.controller_ip = controller_ip
52 60
 
53
-        def make_endpoint(endpoint):
54
-            parse = urllib.parse.urlparse(endpoint)
55
-            return parse._replace(
56
-                netloc='{}:{}'.format(
57
-                    self.controller_ip, parse.port)).geturl()
61
+        self.keystone_session = None
58 62
 
59 63
         if DISABLE_SSL:
60 64
             auth_url = 'http://{0}:5000/v2.0/'.format(self.controller_ip)
@@ -67,69 +71,90 @@ class Common(object):
67 71
 
68 72
         logger.debug('Auth URL is {0}'.format(auth_url))
69 73
 
70
-        keystone_args = {'username': user, 'password': password,
71
-                         'tenant_name': tenant, 'auth_url': auth_url,
72
-                         'ca_cert': path_to_cert, 'insecure': insecure}
73
-        self.keystone = self._get_keystoneclient(**keystone_args)
74
-
75
-        token = self.keystone.auth_token
76
-        logger.debug('Token is {0}'.format(token))
77
-
78
-        neutron_endpoint = self.keystone.service_catalog.url_for(
79
-            service_type='network', endpoint_type='publicURL')
80
-        neutron_args = {'username': user, 'password': password,
81
-                        'tenant_name': tenant, 'auth_url': auth_url,
82
-                        'ca_cert': path_to_cert, 'insecure': insecure,
83
-                        'endpoint_url': make_endpoint(neutron_endpoint)}
84
-        self.neutron = neutronclient.Client(**neutron_args)
85
-
86
-        nova_endpoint = self.keystone.service_catalog.url_for(
87
-            service_type='compute', endpoint_type='publicURL')
88
-        nova_args = {'username': user, 'api_key': password,
89
-                     'project_id': tenant, 'auth_url': auth_url,
90
-                     'cacert': path_to_cert, 'insecure': insecure,
91
-                     'bypass_url': make_endpoint(nova_endpoint),
92
-                     'auth_token': token}
93
-        self.nova = NovaClient(**nova_args)
94
-
95
-        cinder_endpoint = self.keystone.service_catalog.url_for(
96
-            service_type='volume', endpoint_type='publicURL')
97
-        cinder_args = {'version': 1, 'username': user,
98
-                       'api_key': password, 'project_id': tenant,
99
-                       'auth_url': auth_url, 'cacert': path_to_cert,
100
-                       'insecure': insecure,
101
-                       'bypass_url': make_endpoint(cinder_endpoint)}
102
-        self.cinder = cinderclient.Client(**cinder_args)
103
-
104
-        glance_endpoint = self.keystone.service_catalog.url_for(
105
-            service_type='image', endpoint_type='publicURL')
106
-        logger.debug('Glance endpoint is {0}'.format(
107
-            make_endpoint(glance_endpoint)))
108
-        glance_args = {'endpoint': make_endpoint(glance_endpoint),
109
-                       'token': token,
110
-                       'cacert': path_to_cert,
111
-                       'insecure': insecure}
112
-        self.glance = GlanceClient(**glance_args)
113
-
114
-        heat_endpoint = self.keystone.service_catalog.url_for(
115
-            service_type='orchestration', endpoint_type='publicURL')
116
-
117
-        heat_args = {'endpoint': make_endpoint(heat_endpoint),
118
-                     'token': token,
119
-                     'cacert': path_to_cert,
120
-                     'insecure': insecure}
121
-        self.heat = HeatClient(**heat_args)
122
-
74
+        self.__keystone_auth = V2Password(
75
+            auth_url=auth_url,
76
+            username=user,
77
+            password=password,
78
+            tenant_name=tenant)  # TODO: in v3 project_name
79
+
80
+        self.__start_keystone_session(ca_cert=path_to_cert, insecure=insecure)
81
+
82
+    @property
83
+    def keystone(self):
84
+        return KeystoneClient(session=self.keystone_session)
85
+
86
+    @property
87
+    def glance(self):
88
+        endpoint = self.__make_endpoint(
89
+            self._get_url_for_svc(service_type='image'))
90
+        return GlanceClient(
91
+            session=self.keystone_session,
92
+            endpoint=endpoint,
93
+            endpoint_override=endpoint)
94
+
95
+    @property
96
+    def neutron(self):
97
+        endpoint = self.__make_endpoint(
98
+            self._get_url_for_svc(service_type='network'))
99
+        return NeutronClient(
100
+            session=self.keystone_session,
101
+            endpoint_override=endpoint)
102
+
103
+    @property
104
+    def nova(self):
105
+        endpoint = self.__make_endpoint(
106
+            self._get_url_for_svc(service_type='compute'))
107
+        return NovaClient(
108
+            version='2',
109
+            session=self.keystone_session,
110
+            endpoint_override=endpoint)
111
+
112
+    @property
113
+    def cinder(self):
114
+        endpoint = self.__make_endpoint(
115
+            self._get_url_for_svc(service_type='volume'))
116
+        return CinderClient(
117
+            version='1',
118
+            session=self.keystone_session,
119
+            endpoint_override=endpoint)
120
+
121
+    @property
122
+    def heat(self):
123
+        endpoint = self.__make_endpoint(
124
+            self._get_url_for_svc(service_type='orchestration'))
125
+        return HeatClient(
126
+            session=self.keystone_session,
127
+            endpoint_override=endpoint)
128
+
129
+    @property
130
+    def ironic(self):
123 131
         try:
124
-            ironic_endpoint = self.keystone.service_catalog.url_for(
125
-                service_type='baremetal',
126
-                endpoint_type='publicURL')
127
-            self.ironic = ironicclient.get_client(
128
-                api_version=1,
129
-                os_auth_token=token,
130
-                ironic_url=make_endpoint(ironic_endpoint), insecure=True)
132
+            endpoint = self.__make_endpoint(
133
+                self._get_url_for_svc(service_type='baremetal'))
134
+            return IronicClient(
135
+                version='1',
136
+                session=self.keystone_session,
137
+                insecure=True,
138
+                endpoint_override=endpoint
139
+            )
131 140
         except ClientException as e:
132 141
             logger.warning('Could not initialize ironic client {0}'.format(e))
142
+            raise
143
+
144
+    @property
145
+    def keystone_access(self):
146
+        return self.__keystone_auth.get_access(session=self.keystone_session)
147
+
148
+    def _get_url_for_svc(
149
+            self, service_type=None, interface='public',
150
+            region_name=None, service_name=None,
151
+            service_id=None, endpoint_id=None
152
+    ):
153
+        return self.keystone_access.service_catalog.url_for(
154
+            service_type=service_type, interface=interface,
155
+            region_name=region_name, service_name=service_name,
156
+            service_id=service_id, endpoint_id=endpoint_id
157
+        )
133 158
 
134 159
     def goodbye_security(self):
135 160
         secgroup_list = self.nova.security_groups.list()
@@ -164,6 +189,7 @@ class Common(object):
164 189
         logger.debug('Try to create instance')
165 190
 
166 191
         start_time = time.time()
192
+        exc_type, exc_value, exc_traceback = None, None, None
167 193
         while time.time() - start_time < 100:
168 194
             try:
169 195
                 if image_name:
@@ -173,9 +199,12 @@ class Common(object):
173 199
                     image = [i.id for i in self.nova.images.list()]
174 200
                 break
175 201
             except Exception as e:
202
+                exc_type, exc_value, exc_traceback = sys.exc_info()
176 203
                 logger.warning('Ignoring exception: {!r}'.format(e))
177 204
                 logger.debug(traceback.format_exc())
178 205
         else:
206
+            if all((exc_type, exc_traceback, exc_value)):
207
+                six.reraise(exc_type, exc_value, exc_traceback)
179 208
             raise Exception('Can not get image')
180 209
 
181 210
         kwargs = {}
@@ -241,28 +270,26 @@ class Common(object):
241 270
             self.nova.aggregates.remove_host(aggregate, host)
242 271
         return self.nova.aggregates.delete(aggregate)
243 272
 
244
-    @staticmethod
245
-    def _get_keystoneclient(username, password, tenant_name, auth_url,
246
-                            retries=3, ca_cert=None, insecure=False):
273
+    def __start_keystone_session(
274
+            self, retries=3, ca_cert=None, insecure=not VERIFY_SSL):
247 275
         exc_type, exc_value, exc_traceback = None, None, None
248 276
         for i in xrange(retries):
249 277
             try:
250
-                if ca_cert:
251
-                    return KeystoneClient(username=username,
252
-                                          password=password,
253
-                                          tenant_name=tenant_name,
254
-                                          auth_url=auth_url,
255
-                                          cacert=ca_cert,
256
-                                          insecure=insecure)
257
-
278
+                if insecure:
279
+                    self.keystone_session = KeystoneSession(
280
+                        auth=self.__keystone_auth, verify=False)
281
+                elif ca_cert:
282
+                    self.keystone_session = KeystoneSession(
283
+                        auth=self.__keystone_auth, verify=ca_cert)
258 284
                 else:
259
-                    return KeystoneClient(username=username,
260
-                                          password=password,
261
-                                          tenant_name=tenant_name,
262
-                                          auth_url=auth_url)
285
+                    self.keystone_session = KeystoneSession(
286
+                        auth=self.__keystone_auth)
287
+                self.keystone_session.get_auth_headers()
288
+                return
289
+
263 290
             except ClientException as exc:
264 291
                 exc_type, exc_value, exc_traceback = sys.exc_info()
265
-                err = "Try nr {0}. Could not get keystone client, error: {1}"
292
+                err = "Try nr {0}. Could not get keystone token, error: {1}"
266 293
                 logger.warning(err.format(i + 1, exc))
267 294
                 time.sleep(5)
268 295
         if exc_type and exc_traceback and exc_value:

+ 14
- 8
fuelweb_test/helpers/http.py View File

@@ -15,8 +15,10 @@
15 15
 import json
16 16
 import traceback
17 17
 
18
+from keystoneauth1 import exceptions
19
+from keystoneauth1.identity import V2Password
20
+from keystoneauth1.session import Session as KeystoneSession
18 21
 from keystoneclient.v2_0 import Client as KeystoneClient
19
-from keystoneclient import exceptions
20 22
 # pylint: disable=import-error
21 23
 # noinspection PyUnresolvedReferences
22 24
 from six.moves.urllib import request
@@ -38,17 +40,21 @@ class HTTPClient(object):
38 40
         self.keystone_url = keystone_url
39 41
         self.creds = dict(credentials, **kwargs)
40 42
         self.keystone = None
43
+        self.session = None
41 44
         self.opener = request.build_opener(request.HTTPHandler)
42 45
 
43 46
     def authenticate(self):
44 47
         try:
45 48
             logger.info('Initialize keystoneclient with url %s',
46 49
                         self.keystone_url)
47
-            self.keystone = KeystoneClient(
48
-                auth_url=self.keystone_url, **self.creds)
49
-            # it depends on keystone version, some versions doing auth
50
-            # explicitly some don't, but we are making it explicitly always
51
-            self.keystone.authenticate()
50
+            auth = V2Password(
51
+                auth_url=self.keystone_url,
52
+                username=self.creds['username'],
53
+                password=self.creds['password'],
54
+                tenant_name=self.creds['tenant_name'])
55
+            # TODO: in v3 project_name
56
+            self.session = KeystoneSession(auth=auth, verify=False)
57
+            self.keystone = KeystoneClient(session=self.session)
52 58
             logger.debug('Authorization token is successfully updated')
53 59
         except exceptions.AuthorizationFailure:
54 60
             logger.warning(
@@ -59,7 +65,7 @@ class HTTPClient(object):
59 65
     def token(self):
60 66
         if self.keystone is not None:
61 67
             try:
62
-                return self.keystone.auth_token
68
+                return self.session.get_token()
63 69
             except exceptions.AuthorizationFailure:
64 70
                 logger.warning(
65 71
                     'Cant establish connection to keystone with url %s',
@@ -68,7 +74,7 @@ class HTTPClient(object):
68 74
                 logger.warning("Keystone returned unauthorized error, trying "
69 75
                                "to pass authentication.")
70 76
                 self.authenticate()
71
-                return self.keystone.auth_token
77
+                return self.session.get_token()
72 78
         return None
73 79
 
74 80
     def get(self, endpoint):

+ 2
- 2
fuelweb_test/helpers/os_actions.py View File

@@ -150,9 +150,9 @@ class OpenStackActions(common.Common):
150 150
             logger.info("Error opening file: {:s}".format(exc))
151 151
             raise Exception()
152 152
         image_id = self._get_cirros_image().id
153
-        security_group[self.keystone.tenant_id] =\
153
+        security_group[self.keystone_access.tenant_id] =\
154 154
             self.create_sec_group_for_ssh()
155
-        security_groups = [security_group[self.keystone.tenant_id].name]
155
+        security_groups = [security_group[self.keystone_access.tenant_id].name]
156 156
 
157 157
         if neutron:
158 158
             net_label = label if label else 'net04'

+ 18
- 12
fuelweb_test/requirements.txt View File

@@ -1,20 +1,26 @@
1 1
 nose==1.2.1
2 2
 git+git://github.com/openstack/fuel-devops.git@2.9.20
3
-anyjson==0.3.1
4
-paramiko
3
+anyjson>=0.3.3  # BSD
4
+paramiko>=1.16.0  # LGPL
5 5
 proboscis==1.2.6.0
6 6
 junitxml>=0.7.0
7
-netaddr>=0.7.12,!=0.7.16
8
-python-glanceclient==0.17.1
9
-python-keystoneclient>=0.3.2
10
-python-novaclient>=2.15.0
11
-python-cinderclient>=1.0.5
12
-python-neutronclient>=2.0
13
-python-ironicclient>=0.8.0
14
-python-heatclient>=0.6.0
7
+netaddr>=0.7.12,!=0.7.16  # BSD
8
+pyOpenSSL>=0.14  # Apache-2.0
9
+Sphinx  # BSD  # Not required for tests, but required to build docs (pbr)
10
+docutils  # Not required for tests, but required to build docs (pbr)
11
+markupsafe  # Not required for tests, but required to build docs (pbr)
12
+pytz>=2013.6  # MIT  # Not required for tests, but required to build docs (pbr)
13
+keystoneauth1>=2.1.0  # Apache-2.0
14
+python-glanceclient>=2.0.0  # Apache-2.0
15
+python-keystoneclient>=1.6.0,!=1.8.0,!=2.1.0  # Apache-2.0
16
+python-novaclient>=2.29.0,!=2.33.0  # Apache-2.0
17
+python-cinderclient>=1.3.1  # Apache-2.0
18
+python-neutronclient>=2.6.0,!=4.1.0  # Apache-2.0
19
+python-ironicclient>=1.1.0  # Apache-2.0
20
+python-heatclient>=0.6.0  # Apache-2.0
15 21
 oslo.i18n>=3.1.0
16
-six
17
-Jinja2
22
+six>=1.9.0 # MIT
23
+Jinja2>=2.8  # BSD License (3 clause)
18 24
 AllPairs==2.0.1
19 25
 launchpadlib
20 26
 beautifulsoup4>=4.2.0

Loading…
Cancel
Save