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

(cherry picked from commit e48d37a)

Change-Id: I4d15b994ef274f0ecede3635759ec85dd7544148
tags/9.1
Alexey Stepanov 3 years ago
parent
commit
2368f5bfb1

+ 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
@@ -45,14 +47,16 @@ from fuelweb_test.settings import VERIFY_SSL
45 47
 class Common(object):
46 48
     """Common."""  # TODO documentation
47 49
 
50
+    def __make_endpoint(self, endpoint):
51
+        parse = urllib.parse.urlparse(endpoint)
52
+        return parse._replace(
53
+            netloc='{}:{}'.format(
54
+                self.controller_ip, parse.port)).geturl()
55
+
48 56
     def __init__(self, controller_ip, user, password, tenant):
49 57
         self.controller_ip = controller_ip
50 58
 
51
-        def make_endpoint(endpoint):
52
-            parse = urllib.parse.urlparse(endpoint)
53
-            return parse._replace(
54
-                netloc='{}:{}'.format(
55
-                    self.controller_ip, parse.port)).geturl()
59
+        self.keystone_session = None
56 60
 
57 61
         if DISABLE_SSL:
58 62
             auth_url = 'http://{0}:5000/v2.0/'.format(self.controller_ip)
@@ -65,69 +69,90 @@ class Common(object):
65 69
 
66 70
         logger.debug('Auth URL is {0}'.format(auth_url))
67 71
 
68
-        keystone_args = {'username': user, 'password': password,
69
-                         'tenant_name': tenant, 'auth_url': auth_url,
70
-                         'ca_cert': path_to_cert, 'insecure': insecure}
71
-        self.keystone = self._get_keystoneclient(**keystone_args)
72
-
73
-        token = self.keystone.auth_token
74
-        logger.debug('Token is {0}'.format(token))
75
-
76
-        neutron_endpoint = self.keystone.service_catalog.url_for(
77
-            service_type='network', endpoint_type='publicURL')
78
-        neutron_args = {'username': user, 'password': password,
79
-                        'tenant_name': tenant, 'auth_url': auth_url,
80
-                        'ca_cert': path_to_cert, 'insecure': insecure,
81
-                        'endpoint_url': make_endpoint(neutron_endpoint)}
82
-        self.neutron = neutronclient.Client(**neutron_args)
83
-
84
-        nova_endpoint = self.keystone.service_catalog.url_for(
85
-            service_type='compute', endpoint_type='publicURL')
86
-        nova_args = {'username': user, 'api_key': password,
87
-                     'project_id': tenant, 'auth_url': auth_url,
88
-                     'cacert': path_to_cert, 'insecure': insecure,
89
-                     'bypass_url': make_endpoint(nova_endpoint),
90
-                     'auth_token': token}
91
-        self.nova = NovaClient(**nova_args)
92
-
93
-        cinder_endpoint = self.keystone.service_catalog.url_for(
94
-            service_type='volume', endpoint_type='publicURL')
95
-        cinder_args = {'version': 1, 'username': user,
96
-                       'api_key': password, 'project_id': tenant,
97
-                       'auth_url': auth_url, 'cacert': path_to_cert,
98
-                       'insecure': insecure,
99
-                       'bypass_url': make_endpoint(cinder_endpoint)}
100
-        self.cinder = cinderclient.Client(**cinder_args)
101
-
102
-        glance_endpoint = self.keystone.service_catalog.url_for(
103
-            service_type='image', endpoint_type='publicURL')
104
-        logger.debug('Glance endpoint is {0}'.format(
105
-            make_endpoint(glance_endpoint)))
106
-        glance_args = {'endpoint': make_endpoint(glance_endpoint),
107
-                       'token': token,
108
-                       'cacert': path_to_cert,
109
-                       'insecure': insecure}
110
-        self.glance = GlanceClient(**glance_args)
111
-
112
-        heat_endpoint = self.keystone.service_catalog.url_for(
113
-            service_type='orchestration', endpoint_type='publicURL')
114
-
115
-        heat_args = {'endpoint': make_endpoint(heat_endpoint),
116
-                     'token': token,
117
-                     'cacert': path_to_cert,
118
-                     'insecure': insecure}
119
-        self.heat = HeatClient(**heat_args)
120
-
72
+        self.__keystone_auth = V2Password(
73
+            auth_url=auth_url,
74
+            username=user,
75
+            password=password,
76
+            tenant_name=tenant)  # TODO: in v3 project_name
77
+
78
+        self.__start_keystone_session(ca_cert=path_to_cert, insecure=insecure)
79
+
80
+    @property
81
+    def keystone(self):
82
+        return KeystoneClient(session=self.keystone_session)
83
+
84
+    @property
85
+    def glance(self):
86
+        endpoint = self.__make_endpoint(
87
+            self._get_url_for_svc(service_type='image'))
88
+        return GlanceClient(
89
+            session=self.keystone_session,
90
+            endpoint=endpoint,
91
+            endpoint_override=endpoint)
92
+
93
+    @property
94
+    def neutron(self):
95
+        endpoint = self.__make_endpoint(
96
+            self._get_url_for_svc(service_type='network'))
97
+        return NeutronClient(
98
+            session=self.keystone_session,
99
+            endpoint_override=endpoint)
100
+
101
+    @property
102
+    def nova(self):
103
+        endpoint = self.__make_endpoint(
104
+            self._get_url_for_svc(service_type='compute'))
105
+        return NovaClient(
106
+            version='2',
107
+            session=self.keystone_session,
108
+            endpoint_override=endpoint)
109
+
110
+    @property
111
+    def cinder(self):
112
+        endpoint = self.__make_endpoint(
113
+            self._get_url_for_svc(service_type='volume'))
114
+        return CinderClient(
115
+            version='1',
116
+            session=self.keystone_session,
117
+            endpoint_override=endpoint)
118
+
119
+    @property
120
+    def heat(self):
121
+        endpoint = self.__make_endpoint(
122
+            self._get_url_for_svc(service_type='orchestration'))
123
+        return HeatClient(
124
+            session=self.keystone_session,
125
+            endpoint_override=endpoint)
126
+
127
+    @property
128
+    def ironic(self):
121 129
         try:
122
-            ironic_endpoint = self.keystone.service_catalog.url_for(
123
-                service_type='baremetal',
124
-                endpoint_type='publicURL')
125
-            self.ironic = ironicclient.get_client(
126
-                api_version=1,
127
-                os_auth_token=token,
128
-                ironic_url=make_endpoint(ironic_endpoint), insecure=True)
130
+            endpoint = self.__make_endpoint(
131
+                self._get_url_for_svc(service_type='baremetal'))
132
+            return IronicClient(
133
+                version='1',
134
+                session=self.keystone_session,
135
+                insecure=True,
136
+                endpoint_override=endpoint
137
+            )
129 138
         except ClientException as e:
130 139
             logger.warning('Could not initialize ironic client {0}'.format(e))
140
+            raise
141
+
142
+    @property
143
+    def keystone_access(self):
144
+        return self.__keystone_auth.get_access(session=self.keystone_session)
145
+
146
+    def _get_url_for_svc(
147
+            self, service_type=None, interface='public',
148
+            region_name=None, service_name=None,
149
+            service_id=None, endpoint_id=None
150
+    ):
151
+        return self.keystone_access.service_catalog.url_for(
152
+            service_type=service_type, interface=interface,
153
+            region_name=region_name, service_name=service_name,
154
+            service_id=service_id, endpoint_id=endpoint_id
155
+        )
131 156
 
132 157
     def goodbye_security(self):
133 158
         secgroup_list = self.nova.security_groups.list()
@@ -162,6 +187,7 @@ class Common(object):
162 187
         logger.debug('Try to create instance')
163 188
 
164 189
         start_time = time.time()
190
+        exc_type, exc_value, exc_traceback = None, None, None
165 191
         while time.time() - start_time < 100:
166 192
             try:
167 193
                 if image_name:
@@ -171,9 +197,12 @@ class Common(object):
171 197
                     image = [i.id for i in self.nova.images.list()]
172 198
                 break
173 199
             except Exception as e:
200
+                exc_type, exc_value, exc_traceback = sys.exc_info()
174 201
                 logger.warning('Ignoring exception: {!r}'.format(e))
175 202
                 logger.debug(traceback.format_exc())
176 203
         else:
204
+            if all((exc_type, exc_traceback, exc_value)):
205
+                six.reraise(exc_type, exc_value, exc_traceback)
177 206
             raise Exception('Can not get image')
178 207
 
179 208
         kwargs = {}
@@ -239,28 +268,26 @@ class Common(object):
239 268
             self.nova.aggregates.remove_host(aggregate, host)
240 269
         return self.nova.aggregates.delete(aggregate)
241 270
 
242
-    @staticmethod
243
-    def _get_keystoneclient(username, password, tenant_name, auth_url,
244
-                            retries=3, ca_cert=None, insecure=False):
271
+    def __start_keystone_session(
272
+            self, retries=3, ca_cert=None, insecure=not VERIFY_SSL):
245 273
         exc_type, exc_value, exc_traceback = None, None, None
246 274
         for i in xrange(retries):
247 275
             try:
248
-                if ca_cert:
249
-                    return KeystoneClient(username=username,
250
-                                          password=password,
251
-                                          tenant_name=tenant_name,
252
-                                          auth_url=auth_url,
253
-                                          cacert=ca_cert,
254
-                                          insecure=insecure)
255
-
276
+                if insecure:
277
+                    self.keystone_session = KeystoneSession(
278
+                        auth=self.__keystone_auth, verify=False)
279
+                elif ca_cert:
280
+                    self.keystone_session = KeystoneSession(
281
+                        auth=self.__keystone_auth, verify=ca_cert)
256 282
                 else:
257
-                    return KeystoneClient(username=username,
258
-                                          password=password,
259
-                                          tenant_name=tenant_name,
260
-                                          auth_url=auth_url)
283
+                    self.keystone_session = KeystoneSession(
284
+                        auth=self.__keystone_auth)
285
+                self.keystone_session.get_auth_headers()
286
+                return
287
+
261 288
             except ClientException as exc:
262 289
                 exc_type, exc_value, exc_traceback = sys.exc_info()
263
-                err = "Try nr {0}. Could not get keystone client, error: {1}"
290
+                err = "Try nr {0}. Could not get keystone token, error: {1}"
264 291
                 logger.warning(err.format(i + 1, exc))
265 292
                 time.sleep(5)
266 293
         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
 from six.moves.urllib import request
22 24
 from six.moves.urllib.error import HTTPError
@@ -36,17 +38,21 @@ class HTTPClient(object):
36 38
         self.keystone_url = keystone_url
37 39
         self.creds = dict(credentials, **kwargs)
38 40
         self.keystone = None
41
+        self.session = None
39 42
         self.opener = request.build_opener(request.HTTPHandler)
40 43
 
41 44
     def authenticate(self):
42 45
         try:
43 46
             logger.info('Initialize keystoneclient with url %s',
44 47
                         self.keystone_url)
45
-            self.keystone = KeystoneClient(
46
-                auth_url=self.keystone_url, **self.creds)
47
-            # it depends on keystone version, some versions doing auth
48
-            # explicitly some don't, but we are making it explicitly always
49
-            self.keystone.authenticate()
48
+            auth = V2Password(
49
+                auth_url=self.keystone_url,
50
+                username=self.creds['username'],
51
+                password=self.creds['password'],
52
+                tenant_name=self.creds['tenant_name'])
53
+            # TODO: in v3 project_name
54
+            self.session = KeystoneSession(auth=auth, verify=False)
55
+            self.keystone = KeystoneClient(session=self.session)
50 56
             logger.debug('Authorization token is successfully updated')
51 57
         except exceptions.AuthorizationFailure:
52 58
             logger.warning(
@@ -57,7 +63,7 @@ class HTTPClient(object):
57 63
     def token(self):
58 64
         if self.keystone is not None:
59 65
             try:
60
-                return self.keystone.auth_token
66
+                return self.session.get_token()
61 67
             except exceptions.AuthorizationFailure:
62 68
                 logger.warning(
63 69
                     'Cant establish connection to keystone with url %s',
@@ -66,7 +72,7 @@ class HTTPClient(object):
66 72
                 logger.warning("Keystone returned unauthorized error, trying "
67 73
                                "to pass authentication.")
68 74
                 self.authenticate()
69
-                return self.keystone.auth_token
75
+                return self.session.get_token()
70 76
         return None
71 77
 
72 78
     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'

+ 16
- 10
fuelweb_test/requirements.txt View File

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

Loading…
Cancel
Save