diff --git a/fuelweb_test/helpers/common.py b/fuelweb_test/helpers/common.py index 573ac6731..cad475d51 100644 --- a/fuelweb_test/helpers/common.py +++ b/fuelweb_test/helpers/common.py @@ -16,14 +16,16 @@ import sys import time import traceback -from cinderclient import client as cinderclient +from cinderclient.client import Client as CinderClient from heatclient.v1.client import Client as HeatClient 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.exceptions import ClientException -from novaclient.v2 import Client as NovaClient -import neutronclient.v2_0.client as neutronclient +from novaclient.client import Client as NovaClient +from neutronclient.v2_0.client import Client as NeutronClient from proboscis.asserts import assert_equal import six # pylint: disable=redefined-builtin @@ -45,14 +47,16 @@ from fuelweb_test.settings import VERIFY_SSL class Common(object): """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): self.controller_ip = controller_ip - def make_endpoint(endpoint): - parse = urllib.parse.urlparse(endpoint) - return parse._replace( - netloc='{}:{}'.format( - self.controller_ip, parse.port)).geturl() + self.keystone_session = None if DISABLE_SSL: auth_url = 'http://{0}:5000/v2.0/'.format(self.controller_ip) @@ -65,69 +69,90 @@ class Common(object): logger.debug('Auth URL is {0}'.format(auth_url)) - keystone_args = {'username': user, 'password': password, - 'tenant_name': tenant, 'auth_url': auth_url, - 'ca_cert': path_to_cert, 'insecure': insecure} - self.keystone = self._get_keystoneclient(**keystone_args) + self.__keystone_auth = V2Password( + auth_url=auth_url, + username=user, + password=password, + tenant_name=tenant) # TODO: in v3 project_name - token = self.keystone.auth_token - logger.debug('Token is {0}'.format(token)) + self.__start_keystone_session(ca_cert=path_to_cert, insecure=insecure) - neutron_endpoint = self.keystone.service_catalog.url_for( - service_type='network', endpoint_type='publicURL') - neutron_args = {'username': user, 'password': password, - '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) + @property + def keystone(self): + return KeystoneClient(session=self.keystone_session) - nova_endpoint = self.keystone.service_catalog.url_for( - service_type='compute', endpoint_type='publicURL') - nova_args = {'username': user, 'api_key': password, - 'project_id': tenant, 'auth_url': auth_url, - 'cacert': path_to_cert, 'insecure': insecure, - 'bypass_url': make_endpoint(nova_endpoint), - 'auth_token': token} - self.nova = NovaClient(**nova_args) + @property + def glance(self): + endpoint = self.__make_endpoint( + self._get_url_for_svc(service_type='image')) + return GlanceClient( + session=self.keystone_session, + endpoint=endpoint, + endpoint_override=endpoint) - cinder_endpoint = self.keystone.service_catalog.url_for( - service_type='volume', endpoint_type='publicURL') - cinder_args = {'version': 1, 'username': user, - 'api_key': password, 'project_id': tenant, - 'auth_url': auth_url, 'cacert': path_to_cert, - 'insecure': insecure, - 'bypass_url': make_endpoint(cinder_endpoint)} - self.cinder = cinderclient.Client(**cinder_args) + @property + def neutron(self): + endpoint = self.__make_endpoint( + self._get_url_for_svc(service_type='network')) + return NeutronClient( + session=self.keystone_session, + endpoint_override=endpoint) - glance_endpoint = self.keystone.service_catalog.url_for( - service_type='image', endpoint_type='publicURL') - logger.debug('Glance endpoint is {0}'.format( - make_endpoint(glance_endpoint))) - glance_args = {'endpoint': make_endpoint(glance_endpoint), - 'token': token, - 'cacert': path_to_cert, - 'insecure': insecure} - self.glance = GlanceClient(**glance_args) + @property + def nova(self): + endpoint = self.__make_endpoint( + self._get_url_for_svc(service_type='compute')) + return NovaClient( + version='2', + session=self.keystone_session, + endpoint_override=endpoint) - heat_endpoint = self.keystone.service_catalog.url_for( - service_type='orchestration', endpoint_type='publicURL') + @property + 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), - 'token': token, - 'cacert': path_to_cert, - 'insecure': insecure} - self.heat = HeatClient(**heat_args) + @property + def heat(self): + endpoint = self.__make_endpoint( + self._get_url_for_svc(service_type='orchestration')) + return HeatClient( + session=self.keystone_session, + endpoint_override=endpoint) + @property + def ironic(self): try: - ironic_endpoint = self.keystone.service_catalog.url_for( - service_type='baremetal', - endpoint_type='publicURL') - self.ironic = ironicclient.get_client( - api_version=1, - os_auth_token=token, - ironic_url=make_endpoint(ironic_endpoint), insecure=True) + endpoint = self.__make_endpoint( + self._get_url_for_svc(service_type='baremetal')) + return IronicClient( + version='1', + session=self.keystone_session, + insecure=True, + endpoint_override=endpoint + ) except ClientException as 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): secgroup_list = self.nova.security_groups.list() @@ -162,6 +187,7 @@ class Common(object): logger.debug('Try to create instance') start_time = time.time() + exc_type, exc_value, exc_traceback = None, None, None while time.time() - start_time < 100: try: if image_name: @@ -171,9 +197,12 @@ class Common(object): image = [i.id for i in self.nova.images.list()] break except Exception as e: + exc_type, exc_value, exc_traceback = sys.exc_info() logger.warning('Ignoring exception: {!r}'.format(e)) logger.debug(traceback.format_exc()) else: + if all((exc_type, exc_traceback, exc_value)): + six.reraise(exc_type, exc_value, exc_traceback) raise Exception('Can not get image') kwargs = {} @@ -239,28 +268,26 @@ class Common(object): self.nova.aggregates.remove_host(aggregate, host) return self.nova.aggregates.delete(aggregate) - @staticmethod - def _get_keystoneclient(username, password, tenant_name, auth_url, - retries=3, ca_cert=None, insecure=False): + def __start_keystone_session( + self, retries=3, ca_cert=None, insecure=not VERIFY_SSL): exc_type, exc_value, exc_traceback = None, None, None for i in xrange(retries): try: - if ca_cert: - return KeystoneClient(username=username, - password=password, - tenant_name=tenant_name, - auth_url=auth_url, - cacert=ca_cert, - insecure=insecure) - + if insecure: + self.keystone_session = KeystoneSession( + auth=self.__keystone_auth, verify=False) + elif ca_cert: + self.keystone_session = KeystoneSession( + auth=self.__keystone_auth, verify=ca_cert) else: - return KeystoneClient(username=username, - password=password, - tenant_name=tenant_name, - auth_url=auth_url) + self.keystone_session = KeystoneSession( + auth=self.__keystone_auth) + self.keystone_session.get_auth_headers() + return + except ClientException as exc: 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)) time.sleep(5) if exc_type and exc_traceback and exc_value: diff --git a/fuelweb_test/helpers/http.py b/fuelweb_test/helpers/http.py index dc11e2f55..88e6dc3cb 100644 --- a/fuelweb_test/helpers/http.py +++ b/fuelweb_test/helpers/http.py @@ -15,8 +15,10 @@ import json 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 import exceptions # pylint: disable=import-error from six.moves.urllib import request from six.moves.urllib.error import HTTPError @@ -36,17 +38,21 @@ class HTTPClient(object): self.keystone_url = keystone_url self.creds = dict(credentials, **kwargs) self.keystone = None + self.session = None self.opener = request.build_opener(request.HTTPHandler) def authenticate(self): try: logger.info('Initialize keystoneclient with url %s', self.keystone_url) - self.keystone = KeystoneClient( - auth_url=self.keystone_url, **self.creds) - # it depends on keystone version, some versions doing auth - # explicitly some don't, but we are making it explicitly always - self.keystone.authenticate() + auth = V2Password( + auth_url=self.keystone_url, + username=self.creds['username'], + password=self.creds['password'], + 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') except exceptions.AuthorizationFailure: logger.warning( @@ -57,7 +63,7 @@ class HTTPClient(object): def token(self): if self.keystone is not None: try: - return self.keystone.auth_token + return self.session.get_token() except exceptions.AuthorizationFailure: logger.warning( 'Cant establish connection to keystone with url %s', @@ -66,7 +72,7 @@ class HTTPClient(object): logger.warning("Keystone returned unauthorized error, trying " "to pass authentication.") self.authenticate() - return self.keystone.auth_token + return self.session.get_token() return None def get(self, endpoint): diff --git a/fuelweb_test/helpers/os_actions.py b/fuelweb_test/helpers/os_actions.py index ebe446a42..1c5ae8325 100644 --- a/fuelweb_test/helpers/os_actions.py +++ b/fuelweb_test/helpers/os_actions.py @@ -150,9 +150,9 @@ class OpenStackActions(common.Common): logger.info("Error opening file: {:s}".format(exc)) raise Exception() 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() - security_groups = [security_group[self.keystone.tenant_id].name] + security_groups = [security_group[self.keystone_access.tenant_id].name] if neutron: net_label = label if label else 'net04' diff --git a/fuelweb_test/requirements.txt b/fuelweb_test/requirements.txt index 35e90ac0f..fcb5af507 100644 --- a/fuelweb_test/requirements.txt +++ b/fuelweb_test/requirements.txt @@ -3,17 +3,23 @@ anyjson>=0.3.3 # BSD paramiko>=1.16.0 # LGPL proboscis==1.2.6.0 junitxml>=0.7.0 -netaddr>=0.7.12,!=0.7.16 -python-glanceclient==0.17.1 -python-keystoneclient>=0.3.2 -python-novaclient>=2.15.0 -python-cinderclient>=1.0.5 -python-neutronclient>=2.0 -python-ironicclient>=0.8.0 -python-heatclient>=0.6.0 +netaddr>=0.7.12,!=0.7.16 # BSD +pyOpenSSL>=0.14 # Apache-2.0 +Sphinx # BSD # Not required for tests, but required to build docs (pbr) +docutils # Not required for tests, but required to build docs (pbr) +markupsafe # Not required for tests, but required to build docs (pbr) +pytz>=2013.6 # MIT # Not required for tests, but required to build docs (pbr) +keystoneauth1>=2.1.0 # Apache-2.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 -six -Jinja2 +six>=1.9.0 # MIT +Jinja2>=2.8 # BSD License (3 clause) AllPairs==2.0.1 launchpadlib beautifulsoup4>=4.2.0