Fix identity url version detection
Before we could diferentiate the api version for identity because the use of /v2 or /v3. Even though v2 is now deprecated, we need to continue support previous versions of openstack. In this case We cannot relay on the /v2 or /v3 in the url. The best user case is to do a request in the base url (without any version) and check if we have v3 version stable. If so, we assume identity version is v3 otherwise, is v2. Change-Id: Ia41d21ebad9329ae9fa506868957a72e6f9a5ca5
This commit is contained in:
parent
b0b8a9a6bb
commit
4ea3580672
@ -13,6 +13,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import re
|
||||||
|
import requests
|
||||||
|
from six.moves import urllib
|
||||||
from tempest.lib import auth
|
from tempest.lib import auth
|
||||||
|
|
||||||
|
|
||||||
@ -62,15 +65,36 @@ class Credentials(object):
|
|||||||
# tool keeps them in identity section for further usage
|
# tool keeps them in identity section for further usage
|
||||||
return self._conf.get_defaulted('identity', key)
|
return self._conf.get_defaulted('identity', key)
|
||||||
|
|
||||||
|
def _get_base_url(self, endpoint):
|
||||||
|
"""Return the base url.
|
||||||
|
|
||||||
|
:param key: endpoint
|
||||||
|
:type key: string
|
||||||
|
:returns: base_url
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
|
url = urllib.parse.urlsplit(endpoint)
|
||||||
|
new_path = re.split(r'(^|/)+v\d+(\.\d+)?', url.path)[0]
|
||||||
|
url = list(url)
|
||||||
|
url[2] = new_path + '/'
|
||||||
|
return urllib.parse.urlunsplit(url)
|
||||||
|
|
||||||
|
def _list_versions(self, base_url):
|
||||||
|
resp = requests.get(base_url)
|
||||||
|
data = resp.json()
|
||||||
|
return data["versions"]["values"]
|
||||||
|
|
||||||
def _get_identity_version(self):
|
def _get_identity_version(self):
|
||||||
"""Looks for identity version in TempestConf object.
|
"""Looks for identity version in TempestConf object.
|
||||||
|
|
||||||
:returns: identity version
|
:returns: identity version
|
||||||
:rtype: string
|
:rtype: string
|
||||||
"""
|
"""
|
||||||
if "v3" in self._conf.get("identity", "uri"):
|
base_url = self._get_base_url(self._conf.get("identity", "uri"))
|
||||||
|
versions = self._list_versions(base_url)
|
||||||
|
for version in versions:
|
||||||
|
if version["status"] == "stable" and "v3" in version["id"]:
|
||||||
return "v3"
|
return "v3"
|
||||||
else:
|
|
||||||
return "v2"
|
return "v2"
|
||||||
|
|
||||||
def _get_creds_kwargs(self):
|
def _get_creds_kwargs(self):
|
||||||
@ -111,6 +135,11 @@ class Credentials(object):
|
|||||||
:rtype: auth.KeystoneV2AuthProvider/auth.KeystoneV3AuthProvider
|
:rtype: auth.KeystoneV2AuthProvider/auth.KeystoneV3AuthProvider
|
||||||
"""
|
"""
|
||||||
if isinstance(self.tempest_creds, auth.KeystoneV3Credentials):
|
if isinstance(self.tempest_creds, auth.KeystoneV3Credentials):
|
||||||
|
# We set uri and uri_v3 to /v3 here because if the endpoint on the
|
||||||
|
# rc file don't set the /v3 it will fail with a error 404
|
||||||
|
uri = self._conf.get_defaulted('identity', 'uri_v3')
|
||||||
|
uri = self._get_base_url(uri) + 'v3'
|
||||||
|
self._conf.set('identity', 'uri_v3', uri)
|
||||||
return auth.KeystoneV3AuthProvider(
|
return auth.KeystoneV3AuthProvider(
|
||||||
self.tempest_creds,
|
self.tempest_creds,
|
||||||
self._conf.get_defaulted('identity', 'uri_v3'),
|
self._conf.get_defaulted('identity', 'uri_v3'),
|
||||||
|
@ -29,6 +29,25 @@ class BaseConfigTempestTest(base.BaseTestCase):
|
|||||||
|
|
||||||
"""Test case base class for all config_tempest unit tests"""
|
"""Test case base class for all config_tempest unit tests"""
|
||||||
|
|
||||||
|
FAKE_V3_VERSIONS = (
|
||||||
|
[{
|
||||||
|
'status': 'stable',
|
||||||
|
'id': 'v3.8',
|
||||||
|
}, {
|
||||||
|
'status': 'deprecated',
|
||||||
|
'id': 'v2.0',
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
FAKE_V2_VERSIONS = (
|
||||||
|
[{
|
||||||
|
'status': 'deprecated',
|
||||||
|
'id': 'v3.8',
|
||||||
|
}, {
|
||||||
|
'status': 'stable',
|
||||||
|
'id': 'v2.0',
|
||||||
|
}]
|
||||||
|
)
|
||||||
|
|
||||||
def _get_conf(self, V2, V3):
|
def _get_conf(self, V2, V3):
|
||||||
"""Creates fake conf for testing purposes"""
|
"""Creates fake conf for testing purposes"""
|
||||||
conf = tempest_conf.TempestConf()
|
conf = tempest_conf.TempestConf()
|
||||||
@ -63,14 +82,21 @@ class BaseConfigTempestTest(base.BaseTestCase):
|
|||||||
conf.set("auth", "use_dynamic_credentials", "True")
|
conf.set("auth", "use_dynamic_credentials", "True")
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
def _get_creds(self, conf, admin=False):
|
def _get_creds(self, conf, admin=False, v2=False):
|
||||||
|
# We return creds configured to v2 or v3
|
||||||
|
func2mock = 'config_tempest.credentials.Credentials._list_versions'
|
||||||
|
return_value = self.FAKE_V3_VERSIONS
|
||||||
|
if v2:
|
||||||
|
return_value = self.FAKE_V2_VERSIONS
|
||||||
|
mock_function = mock.Mock(return_value=return_value)
|
||||||
|
self.useFixture(MonkeyPatch(func2mock, mock_function))
|
||||||
return Credentials(conf, admin)
|
return Credentials(conf, admin)
|
||||||
|
|
||||||
@mock.patch('os_client_config.cloud_config.CloudConfig')
|
@mock.patch('os_client_config.cloud_config.CloudConfig')
|
||||||
def _get_clients(self, conf, mock_args, creds=None):
|
def _get_clients(self, conf, mock_args, creds=None):
|
||||||
"""Returns ClientManager instance"""
|
"""Returns ClientManager instance"""
|
||||||
if creds is None:
|
if creds is None:
|
||||||
creds = self._get_creds(conf)
|
creds = self._get_creds(conf, v2=True)
|
||||||
mock_function = mock.Mock(return_value=False)
|
mock_function = mock.Mock(return_value=False)
|
||||||
func2mock = 'os_client_config.cloud_config.CloudConfig.config.get'
|
func2mock = 'os_client_config.cloud_config.CloudConfig.config.get'
|
||||||
self.useFixture(MonkeyPatch(func2mock, mock_function))
|
self.useFixture(MonkeyPatch(func2mock, mock_function))
|
||||||
|
@ -37,15 +37,15 @@ class TestServices(BaseConfigTempestTest):
|
|||||||
super(TestServices, self).setUp()
|
super(TestServices, self).setUp()
|
||||||
|
|
||||||
@mock.patch('config_tempest.services.services.Services.discover')
|
@mock.patch('config_tempest.services.services.Services.discover')
|
||||||
def _create_services_instance(self, mock_discover):
|
def _create_services_instance(self, mock_discover, v2=False):
|
||||||
conf = self._get_conf('v2', 'v3')
|
conf = self._get_conf('v2', 'v3')
|
||||||
creds = self._get_creds(conf)
|
creds = self._get_creds(conf, v2=v2)
|
||||||
clients = mock.Mock()
|
clients = mock.Mock()
|
||||||
services = Services(clients, conf, creds)
|
services = Services(clients, conf, creds)
|
||||||
return services
|
return services
|
||||||
|
|
||||||
def test_get_endpoints_api_2(self):
|
def test_get_endpoints_api_2(self):
|
||||||
services = self._create_services_instance()
|
services = self._create_services_instance(v2=True)
|
||||||
services._region = 'my_region'
|
services._region = 'my_region'
|
||||||
resp = services.get_endpoints(self.FAKE_ENTRY)
|
resp = services.get_endpoints(self.FAKE_ENTRY)
|
||||||
self.assertEqual(resp, self.FAKE_ENTRY['endpoints'][0])
|
self.assertEqual(resp, self.FAKE_ENTRY['endpoints'][0])
|
||||||
@ -72,13 +72,13 @@ class TestServices(BaseConfigTempestTest):
|
|||||||
self.assertEqual(resp, [])
|
self.assertEqual(resp, [])
|
||||||
|
|
||||||
def test_set_catalog_and_url(self):
|
def test_set_catalog_and_url(self):
|
||||||
services = self._create_services_instance()
|
|
||||||
# api version = 2
|
# api version = 2
|
||||||
|
services = self._create_services_instance(v2=True)
|
||||||
services.set_catalog_and_url()
|
services.set_catalog_and_url()
|
||||||
self.assertEqual(services.service_catalog, 'serviceCatalog')
|
self.assertEqual(services.service_catalog, 'serviceCatalog')
|
||||||
self.assertEqual(services.public_url, 'publicURL')
|
self.assertEqual(services.public_url, 'publicURL')
|
||||||
# api version = 3
|
# api version = 3
|
||||||
services._creds.api_version = 3
|
services = self._create_services_instance()
|
||||||
services.set_catalog_and_url()
|
services.set_catalog_and_url()
|
||||||
self.assertEqual(services.service_catalog, 'catalog')
|
self.assertEqual(services.service_catalog, 'catalog')
|
||||||
self.assertEqual(services.public_url, 'url')
|
self.assertEqual(services.public_url, 'url')
|
||||||
@ -101,10 +101,10 @@ class TestServices(BaseConfigTempestTest):
|
|||||||
url = services.parse_endpoints(ep, "ServiceName")
|
url = services.parse_endpoints(ep, "ServiceName")
|
||||||
self.assertEqual('http://10.0.0.107:8386/v1.1/96409a589d', url)
|
self.assertEqual('http://10.0.0.107:8386/v1.1/96409a589d', url)
|
||||||
ep['url'] = 'https://10.0.0.101/identity'
|
ep['url'] = 'https://10.0.0.101/identity'
|
||||||
auth_url = 'https://10.0.0.101:13000/v2.0'
|
auth_url = 'https://10.0.0.101:13000/v3.0'
|
||||||
services._clients.auth_provider.auth_url = auth_url
|
services._clients.auth_provider.auth_url = auth_url
|
||||||
url = services.parse_endpoints(ep, 'ServiceName')
|
url = services.parse_endpoints(ep, 'ServiceName')
|
||||||
self.assertEqual('https://10.0.0.101:13000/identity/v2', url)
|
self.assertEqual('https://10.0.0.101:13000/identity/v3', url)
|
||||||
|
|
||||||
def test_parse_endpoints_not_ip_hostname(self):
|
def test_parse_endpoints_not_ip_hostname(self):
|
||||||
services = self._create_services_instance()
|
services = self._create_services_instance()
|
||||||
@ -119,8 +119,24 @@ class TestServices(BaseConfigTempestTest):
|
|||||||
url_resp = services.parse_endpoints(ep, "ServiceName")
|
url_resp = services.parse_endpoints(ep, "ServiceName")
|
||||||
self.assertEqual(url, url_resp)
|
self.assertEqual(url, url_resp)
|
||||||
|
|
||||||
def test_edit_identity_url(self):
|
def test_edit_identity_url_v3(self):
|
||||||
services = self._create_services_instance()
|
services = self._create_services_instance()
|
||||||
|
url_port = 'https://10.0.0.101:13000/v3.0'
|
||||||
|
identity_url = 'https://10.0.0.101/identity'
|
||||||
|
url_no_port = 'https://10.0.0.101/v333'
|
||||||
|
services._clients.auth_provider.auth_url = url_port
|
||||||
|
url = services.edit_identity_url(url_port)
|
||||||
|
self.assertEqual(url_port, url)
|
||||||
|
url = services.edit_identity_url(identity_url)
|
||||||
|
self.assertEqual("https://10.0.0.101:13000/identity/v3", url)
|
||||||
|
url = services.edit_identity_url(url_no_port)
|
||||||
|
self.assertEqual(url_no_port, url)
|
||||||
|
services._clients.auth_provider.auth_url = url_no_port
|
||||||
|
url = services.edit_identity_url(identity_url)
|
||||||
|
self.assertEqual(identity_url + "/v3", url)
|
||||||
|
|
||||||
|
def test_edit_identity_url_v2(self):
|
||||||
|
services = self._create_services_instance(v2=True)
|
||||||
url_port = 'https://10.0.0.101:13000/v2.0'
|
url_port = 'https://10.0.0.101:13000/v2.0'
|
||||||
identity_url = 'https://10.0.0.101/identity'
|
identity_url = 'https://10.0.0.101/identity'
|
||||||
url_no_port = 'https://10.0.0.101/v2.0'
|
url_no_port = 'https://10.0.0.101/v2.0'
|
||||||
|
@ -27,6 +27,7 @@ class TestCredentials(BaseConfigTempestTest):
|
|||||||
super(TestCredentials, self).setUp()
|
super(TestCredentials, self).setUp()
|
||||||
self.conf = self._get_conf("v2.0", "v3")
|
self.conf = self._get_conf("v2.0", "v3")
|
||||||
self.creds = self._get_creds(self.conf)
|
self.creds = self._get_creds(self.conf)
|
||||||
|
self.creds_v2 = self._get_creds(self.conf, v2=True)
|
||||||
|
|
||||||
def test_get_credential(self):
|
def test_get_credential(self):
|
||||||
# set conf containing the newer values (admin creds in auth section)
|
# set conf containing the newer values (admin creds in auth section)
|
||||||
@ -39,7 +40,7 @@ class TestCredentials(BaseConfigTempestTest):
|
|||||||
self.assertEqual(resp, "admin")
|
self.assertEqual(resp, "admin")
|
||||||
|
|
||||||
def test_get_identity_version_v2(self):
|
def test_get_identity_version_v2(self):
|
||||||
resp = self.creds._get_identity_version()
|
resp = self.creds_v2._get_identity_version()
|
||||||
self.assertEqual(resp, 'v2')
|
self.assertEqual(resp, 'v2')
|
||||||
|
|
||||||
def test_get_identity_version_v3(self):
|
def test_get_identity_version_v3(self):
|
||||||
@ -54,8 +55,8 @@ class TestCredentials(BaseConfigTempestTest):
|
|||||||
'password': 'secret',
|
'password': 'secret',
|
||||||
'project_name': 'demo'
|
'project_name': 'demo'
|
||||||
}
|
}
|
||||||
self.assertEqual(self.creds._get_creds_kwargs(), expected_resp)
|
self.assertEqual(self.creds_v2._get_creds_kwargs(), expected_resp)
|
||||||
self.creds.identity_version = 'v3'
|
self.creds_v2.identity_version = 'v3'
|
||||||
expected_resp = {
|
expected_resp = {
|
||||||
'username': 'demo',
|
'username': 'demo',
|
||||||
'password': 'secret',
|
'password': 'secret',
|
||||||
@ -69,10 +70,10 @@ class TestCredentials(BaseConfigTempestTest):
|
|||||||
mock_function = mock.Mock()
|
mock_function = mock.Mock()
|
||||||
function2mock = 'config_tempest.credentials.auth.get_credentials'
|
function2mock = 'config_tempest.credentials.auth.get_credentials'
|
||||||
self.useFixture(MonkeyPatch(function2mock, mock_function))
|
self.useFixture(MonkeyPatch(function2mock, mock_function))
|
||||||
self.creds.username = "name"
|
self.creds_v2.username = "name"
|
||||||
self.creds.password = "pass"
|
self.creds_v2.password = "pass"
|
||||||
self.creds.project_name = "Tname"
|
self.creds_v2.project_name = "Tname"
|
||||||
self.creds.set_credentials()
|
self.creds_v2.set_credentials()
|
||||||
mock_function.assert_called_with(
|
mock_function.assert_called_with(
|
||||||
auth_url=None, fill_in=False, identity_version='v2',
|
auth_url=None, fill_in=False, identity_version='v2',
|
||||||
disable_ssl_certificate_validation='true',
|
disable_ssl_certificate_validation='true',
|
||||||
@ -103,11 +104,11 @@ class TestCredentials(BaseConfigTempestTest):
|
|||||||
# mock V2Provider, if other provider is called, it fails
|
# mock V2Provider, if other provider is called, it fails
|
||||||
func2mock = 'config_tempest.credentials.auth.KeystoneV2AuthProvider'
|
func2mock = 'config_tempest.credentials.auth.KeystoneV2AuthProvider'
|
||||||
self.useFixture(MonkeyPatch(func2mock, mock_function))
|
self.useFixture(MonkeyPatch(func2mock, mock_function))
|
||||||
resp = self.creds.get_auth_provider()
|
resp = self.creds_v2.get_auth_provider()
|
||||||
self.assertEqual(resp, mock_function())
|
self.assertEqual(resp, mock_function())
|
||||||
# check parameters of returned function
|
# check parameters of returned function
|
||||||
self.creds.get_auth_provider()
|
self.creds_v2.get_auth_provider()
|
||||||
mock_function.assert_called_with(self.creds.tempest_creds,
|
mock_function.assert_called_with(self.creds_v2.tempest_creds,
|
||||||
'http://172.16.52.151:5000/v2.0',
|
'http://172.16.52.151:5000/v2.0',
|
||||||
'true', None)
|
'true', None)
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@ from tempest.lib import exceptions
|
|||||||
class TestUsers(BaseConfigTempestTest):
|
class TestUsers(BaseConfigTempestTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
# TODO(arxcruz): All these tests are running on identity v2 only, we
|
||||||
|
# need to create tests for v3 too!
|
||||||
|
# Story 2003388
|
||||||
super(TestUsers, self).setUp()
|
super(TestUsers, self).setUp()
|
||||||
self.conf = self._get_conf("v2.0", "v3")
|
self.conf = self._get_conf("v2.0", "v3")
|
||||||
projects_client = self._get_clients(self.conf).projects
|
projects_client = self._get_clients(self.conf).projects
|
||||||
|
Loading…
x
Reference in New Issue
Block a user