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
This commit is contained in:
Alexey Stepanov 2016-04-18 14:36:04 +03:00
parent 35af1c0c39
commit e48d37a518
4 changed files with 139 additions and 100 deletions

View File

@ -16,14 +16,16 @@ import sys
import time import time
import traceback import traceback
from cinderclient import client as cinderclient from cinderclient.client import Client as CinderClient
from heatclient.v1.client import Client as HeatClient from heatclient.v1.client import Client as HeatClient
from glanceclient.v1 import Client as GlanceClient from glanceclient.v1 import Client as GlanceClient
import ironicclient.client as ironicclient from ironicclient.client import Client as IronicClient
from keystoneauth1.exceptions import ClientException
from keystoneauth1.identity import V2Password
from keystoneauth1.session import Session as KeystoneSession
from keystoneclient.v2_0 import Client as KeystoneClient from keystoneclient.v2_0 import Client as KeystoneClient
from keystoneclient.exceptions import ClientException from novaclient.client import Client as NovaClient
from novaclient.v2 import Client as NovaClient from neutronclient.v2_0.client import Client as NeutronClient
import neutronclient.v2_0.client as neutronclient
from proboscis.asserts import assert_equal from proboscis.asserts import assert_equal
import six import six
# pylint: disable=redefined-builtin # pylint: disable=redefined-builtin
@ -47,14 +49,16 @@ from fuelweb_test.settings import VERIFY_SSL
class Common(object): class Common(object):
"""Common.""" # TODO documentation """Common.""" # TODO documentation
def __make_endpoint(self, endpoint):
parse = urllib.parse.urlparse(endpoint)
return parse._replace(
netloc='{}:{}'.format(
self.controller_ip, parse.port)).geturl()
def __init__(self, controller_ip, user, password, tenant): def __init__(self, controller_ip, user, password, tenant):
self.controller_ip = controller_ip self.controller_ip = controller_ip
def make_endpoint(endpoint): self.keystone_session = None
parse = urllib.parse.urlparse(endpoint)
return parse._replace(
netloc='{}:{}'.format(
self.controller_ip, parse.port)).geturl()
if DISABLE_SSL: if DISABLE_SSL:
auth_url = 'http://{0}:5000/v2.0/'.format(self.controller_ip) auth_url = 'http://{0}:5000/v2.0/'.format(self.controller_ip)
@ -67,69 +71,90 @@ class Common(object):
logger.debug('Auth URL is {0}'.format(auth_url)) logger.debug('Auth URL is {0}'.format(auth_url))
keystone_args = {'username': user, 'password': password, self.__keystone_auth = V2Password(
'tenant_name': tenant, 'auth_url': auth_url, auth_url=auth_url,
'ca_cert': path_to_cert, 'insecure': insecure} username=user,
self.keystone = self._get_keystoneclient(**keystone_args) password=password,
tenant_name=tenant) # TODO: in v3 project_name
token = self.keystone.auth_token self.__start_keystone_session(ca_cert=path_to_cert, insecure=insecure)
logger.debug('Token is {0}'.format(token))
neutron_endpoint = self.keystone.service_catalog.url_for( @property
service_type='network', endpoint_type='publicURL') def keystone(self):
neutron_args = {'username': user, 'password': password, return KeystoneClient(session=self.keystone_session)
'tenant_name': tenant, 'auth_url': auth_url,
'ca_cert': path_to_cert, 'insecure': insecure,
'endpoint_url': make_endpoint(neutron_endpoint)}
self.neutron = neutronclient.Client(**neutron_args)
nova_endpoint = self.keystone.service_catalog.url_for( @property
service_type='compute', endpoint_type='publicURL') def glance(self):
nova_args = {'username': user, 'api_key': password, endpoint = self.__make_endpoint(
'project_id': tenant, 'auth_url': auth_url, self._get_url_for_svc(service_type='image'))
'cacert': path_to_cert, 'insecure': insecure, return GlanceClient(
'bypass_url': make_endpoint(nova_endpoint), session=self.keystone_session,
'auth_token': token} endpoint=endpoint,
self.nova = NovaClient(**nova_args) endpoint_override=endpoint)
cinder_endpoint = self.keystone.service_catalog.url_for( @property
service_type='volume', endpoint_type='publicURL') def neutron(self):
cinder_args = {'version': 1, 'username': user, endpoint = self.__make_endpoint(
'api_key': password, 'project_id': tenant, self._get_url_for_svc(service_type='network'))
'auth_url': auth_url, 'cacert': path_to_cert, return NeutronClient(
'insecure': insecure, session=self.keystone_session,
'bypass_url': make_endpoint(cinder_endpoint)} endpoint_override=endpoint)
self.cinder = cinderclient.Client(**cinder_args)
glance_endpoint = self.keystone.service_catalog.url_for( @property
service_type='image', endpoint_type='publicURL') def nova(self):
logger.debug('Glance endpoint is {0}'.format( endpoint = self.__make_endpoint(
make_endpoint(glance_endpoint))) self._get_url_for_svc(service_type='compute'))
glance_args = {'endpoint': make_endpoint(glance_endpoint), return NovaClient(
'token': token, version='2',
'cacert': path_to_cert, session=self.keystone_session,
'insecure': insecure} endpoint_override=endpoint)
self.glance = GlanceClient(**glance_args)
heat_endpoint = self.keystone.service_catalog.url_for( @property
service_type='orchestration', endpoint_type='publicURL') def cinder(self):
endpoint = self.__make_endpoint(
self._get_url_for_svc(service_type='volume'))
return CinderClient(
version='1',
session=self.keystone_session,
endpoint_override=endpoint)
heat_args = {'endpoint': make_endpoint(heat_endpoint), @property
'token': token, def heat(self):
'cacert': path_to_cert, endpoint = self.__make_endpoint(
'insecure': insecure} self._get_url_for_svc(service_type='orchestration'))
self.heat = HeatClient(**heat_args) return HeatClient(
session=self.keystone_session,
endpoint_override=endpoint)
@property
def ironic(self):
try: try:
ironic_endpoint = self.keystone.service_catalog.url_for( endpoint = self.__make_endpoint(
service_type='baremetal', self._get_url_for_svc(service_type='baremetal'))
endpoint_type='publicURL') return IronicClient(
self.ironic = ironicclient.get_client( version='1',
api_version=1, session=self.keystone_session,
os_auth_token=token, insecure=True,
ironic_url=make_endpoint(ironic_endpoint), insecure=True) endpoint_override=endpoint
)
except ClientException as e: except ClientException as e:
logger.warning('Could not initialize ironic client {0}'.format(e)) logger.warning('Could not initialize ironic client {0}'.format(e))
raise
@property
def keystone_access(self):
return self.__keystone_auth.get_access(session=self.keystone_session)
def _get_url_for_svc(
self, service_type=None, interface='public',
region_name=None, service_name=None,
service_id=None, endpoint_id=None
):
return self.keystone_access.service_catalog.url_for(
service_type=service_type, interface=interface,
region_name=region_name, service_name=service_name,
service_id=service_id, endpoint_id=endpoint_id
)
def goodbye_security(self): def goodbye_security(self):
secgroup_list = self.nova.security_groups.list() secgroup_list = self.nova.security_groups.list()
@ -164,6 +189,7 @@ class Common(object):
logger.debug('Try to create instance') logger.debug('Try to create instance')
start_time = time.time() start_time = time.time()
exc_type, exc_value, exc_traceback = None, None, None
while time.time() - start_time < 100: while time.time() - start_time < 100:
try: try:
if image_name: if image_name:
@ -173,9 +199,12 @@ class Common(object):
image = [i.id for i in self.nova.images.list()] image = [i.id for i in self.nova.images.list()]
break break
except Exception as e: except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
logger.warning('Ignoring exception: {!r}'.format(e)) logger.warning('Ignoring exception: {!r}'.format(e))
logger.debug(traceback.format_exc()) logger.debug(traceback.format_exc())
else: else:
if all((exc_type, exc_traceback, exc_value)):
six.reraise(exc_type, exc_value, exc_traceback)
raise Exception('Can not get image') raise Exception('Can not get image')
kwargs = {} kwargs = {}
@ -241,28 +270,26 @@ class Common(object):
self.nova.aggregates.remove_host(aggregate, host) self.nova.aggregates.remove_host(aggregate, host)
return self.nova.aggregates.delete(aggregate) return self.nova.aggregates.delete(aggregate)
@staticmethod def __start_keystone_session(
def _get_keystoneclient(username, password, tenant_name, auth_url, self, retries=3, ca_cert=None, insecure=not VERIFY_SSL):
retries=3, ca_cert=None, insecure=False):
exc_type, exc_value, exc_traceback = None, None, None exc_type, exc_value, exc_traceback = None, None, None
for i in xrange(retries): for i in xrange(retries):
try: try:
if ca_cert: if insecure:
return KeystoneClient(username=username, self.keystone_session = KeystoneSession(
password=password, auth=self.__keystone_auth, verify=False)
tenant_name=tenant_name, elif ca_cert:
auth_url=auth_url, self.keystone_session = KeystoneSession(
cacert=ca_cert, auth=self.__keystone_auth, verify=ca_cert)
insecure=insecure)
else: else:
return KeystoneClient(username=username, self.keystone_session = KeystoneSession(
password=password, auth=self.__keystone_auth)
tenant_name=tenant_name, self.keystone_session.get_auth_headers()
auth_url=auth_url) return
except ClientException as exc: except ClientException as exc:
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
err = "Try nr {0}. Could not get keystone client, error: {1}" err = "Try nr {0}. Could not get keystone token, error: {1}"
logger.warning(err.format(i + 1, exc)) logger.warning(err.format(i + 1, exc))
time.sleep(5) time.sleep(5)
if exc_type and exc_traceback and exc_value: if exc_type and exc_traceback and exc_value:

View File

@ -15,8 +15,10 @@
import json import json
import traceback import traceback
from keystoneauth1 import exceptions
from keystoneauth1.identity import V2Password
from keystoneauth1.session import Session as KeystoneSession
from keystoneclient.v2_0 import Client as KeystoneClient from keystoneclient.v2_0 import Client as KeystoneClient
from keystoneclient import exceptions
# pylint: disable=import-error # pylint: disable=import-error
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from six.moves.urllib import request from six.moves.urllib import request
@ -38,17 +40,21 @@ class HTTPClient(object):
self.keystone_url = keystone_url self.keystone_url = keystone_url
self.creds = dict(credentials, **kwargs) self.creds = dict(credentials, **kwargs)
self.keystone = None self.keystone = None
self.session = None
self.opener = request.build_opener(request.HTTPHandler) self.opener = request.build_opener(request.HTTPHandler)
def authenticate(self): def authenticate(self):
try: try:
logger.info('Initialize keystoneclient with url %s', logger.info('Initialize keystoneclient with url %s',
self.keystone_url) self.keystone_url)
self.keystone = KeystoneClient( auth = V2Password(
auth_url=self.keystone_url, **self.creds) auth_url=self.keystone_url,
# it depends on keystone version, some versions doing auth username=self.creds['username'],
# explicitly some don't, but we are making it explicitly always password=self.creds['password'],
self.keystone.authenticate() tenant_name=self.creds['tenant_name'])
# TODO: in v3 project_name
self.session = KeystoneSession(auth=auth, verify=False)
self.keystone = KeystoneClient(session=self.session)
logger.debug('Authorization token is successfully updated') logger.debug('Authorization token is successfully updated')
except exceptions.AuthorizationFailure: except exceptions.AuthorizationFailure:
logger.warning( logger.warning(
@ -59,7 +65,7 @@ class HTTPClient(object):
def token(self): def token(self):
if self.keystone is not None: if self.keystone is not None:
try: try:
return self.keystone.auth_token return self.session.get_token()
except exceptions.AuthorizationFailure: except exceptions.AuthorizationFailure:
logger.warning( logger.warning(
'Cant establish connection to keystone with url %s', 'Cant establish connection to keystone with url %s',
@ -68,7 +74,7 @@ class HTTPClient(object):
logger.warning("Keystone returned unauthorized error, trying " logger.warning("Keystone returned unauthorized error, trying "
"to pass authentication.") "to pass authentication.")
self.authenticate() self.authenticate()
return self.keystone.auth_token return self.session.get_token()
return None return None
def get(self, endpoint): def get(self, endpoint):

View File

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

View File

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