Merge "Add custom SSL CA Cert support for api.cinder.get_microversion" into stable/train
This commit is contained in:
commit
dd8943b536
|
@ -30,6 +30,7 @@ from cinderclient import api_versions
|
||||||
from cinderclient import client as cinder_client
|
from cinderclient import client as cinder_client
|
||||||
from cinderclient import exceptions as cinder_exception
|
from cinderclient import exceptions as cinder_exception
|
||||||
from cinderclient.v2.contrib import list_extensions as cinder_list_extensions
|
from cinderclient.v2.contrib import list_extensions as cinder_list_extensions
|
||||||
|
from six.moves import urllib
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon.utils.memoized import memoized
|
from horizon.utils.memoized import memoized
|
||||||
|
@ -253,11 +254,60 @@ def get_microversion(request, features):
|
||||||
version, cinder_url = _find_cinder_url(request)
|
version, cinder_url = _find_cinder_url(request)
|
||||||
except exceptions.ServiceCatalogException:
|
except exceptions.ServiceCatalogException:
|
||||||
return None
|
return None
|
||||||
min_ver, max_ver = cinder_client.get_server_version(cinder_url)
|
min_ver, max_ver = _get_server_version(request, cinder_url)
|
||||||
return microversions.get_microversion_for_features(
|
return microversions.get_microversion_for_features(
|
||||||
'cinder', features, api_versions.APIVersion, min_ver, max_ver)
|
'cinder', features, api_versions.APIVersion, min_ver, max_ver)
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE(amotoki): Borrowed from cinderclient.client.get_server_version()
|
||||||
|
# to support custom SSL CA Cert support with cinderclient<5.
|
||||||
|
def _get_server_version(request, url):
|
||||||
|
min_version = "2.0"
|
||||||
|
current_version = "2.0"
|
||||||
|
try:
|
||||||
|
u = urllib.parse.urlparse(url)
|
||||||
|
version_url = None
|
||||||
|
|
||||||
|
# NOTE(andreykurilin): endpoint URL has at least 2 formats:
|
||||||
|
# 1. The classic (legacy) endpoint:
|
||||||
|
# http://{host}:{optional_port}/v{2 or 3}/{project-id}
|
||||||
|
# http://{host}:{optional_port}/v{2 or 3}
|
||||||
|
# 3. Under wsgi:
|
||||||
|
# http://{host}:{optional_port}/volume/v{2 or 3}
|
||||||
|
for ver in ['v2', 'v3']:
|
||||||
|
if u.path.endswith(ver) or "/{0}/".format(ver) in u.path:
|
||||||
|
path = u.path[:u.path.rfind(ver)]
|
||||||
|
version_url = '%s://%s%s' % (u.scheme, u.netloc, path)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not version_url:
|
||||||
|
# NOTE(andreykurilin): probably, it is one of the next cases:
|
||||||
|
# * https://volume.example.com/
|
||||||
|
# * https://example.com/volume
|
||||||
|
# leave as is without cropping.
|
||||||
|
version_url = url
|
||||||
|
|
||||||
|
c = cinderclient(request)
|
||||||
|
resp, data = c.client.request(version_url, 'GET')
|
||||||
|
|
||||||
|
versions = data['versions']
|
||||||
|
for version in versions:
|
||||||
|
if '3.' in version['version']:
|
||||||
|
min_version = version['min_version']
|
||||||
|
current_version = version['version']
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# Set the values, but don't break out the loop here in case v3
|
||||||
|
# comes later
|
||||||
|
min_version = '2.0'
|
||||||
|
current_version = '2.0'
|
||||||
|
except cinder_exception.ClientException as e:
|
||||||
|
LOG.warning("Error in server version query:%s\n"
|
||||||
|
"Returning APIVersion 2.0", e)
|
||||||
|
return (api_versions.APIVersion(min_version),
|
||||||
|
api_versions.APIVersion(current_version))
|
||||||
|
|
||||||
|
|
||||||
def _cinderclient_with_features(request, features,
|
def _cinderclient_with_features(request, features,
|
||||||
raise_exc=False, message=False):
|
raise_exc=False, message=False):
|
||||||
version = get_microversion(request, features)
|
version = get_microversion(request, features)
|
||||||
|
|
|
@ -36,6 +36,7 @@ from openstack_dashboard.usage import quotas as usage_quotas
|
||||||
|
|
||||||
|
|
||||||
def data(TEST):
|
def data(TEST):
|
||||||
|
TEST.cinder_versions = utils.TestDataContainer()
|
||||||
TEST.cinder_services = utils.TestDataContainer()
|
TEST.cinder_services = utils.TestDataContainer()
|
||||||
TEST.cinder_volumes = utils.TestDataContainer()
|
TEST.cinder_volumes = utils.TestDataContainer()
|
||||||
TEST.cinder_volume_backups = utils.TestDataContainer()
|
TEST.cinder_volume_backups = utils.TestDataContainer()
|
||||||
|
@ -59,6 +60,41 @@ def data(TEST):
|
||||||
TEST.cinder_group_volumes = utils.TestDataContainer()
|
TEST.cinder_group_volumes = utils.TestDataContainer()
|
||||||
TEST.cinder_volume_snapshots_with_groups = utils.TestDataContainer()
|
TEST.cinder_volume_snapshots_with_groups = utils.TestDataContainer()
|
||||||
|
|
||||||
|
ver2 = {
|
||||||
|
'id': 'v2.0',
|
||||||
|
'links': [{'href': 'http://docs.openstack.org/',
|
||||||
|
'rel': 'describedby',
|
||||||
|
'type': 'text/html'},
|
||||||
|
{'href': 'http://192.168.50.25/volume/v2/',
|
||||||
|
'rel': 'self'}],
|
||||||
|
'media-types': [
|
||||||
|
{'base': 'application/json',
|
||||||
|
'type': 'application/vnd.openstack.volume+json;version=2'}
|
||||||
|
],
|
||||||
|
'min_version': '',
|
||||||
|
'status': 'DEPRECATED',
|
||||||
|
'updated': '2014-06-28T12:20:21Z',
|
||||||
|
'version': '',
|
||||||
|
}
|
||||||
|
ver3 = {
|
||||||
|
'id': 'v3.0',
|
||||||
|
'links': [{'href': 'http://docs.openstack.org/',
|
||||||
|
'rel': 'describedby',
|
||||||
|
'type': 'text/html'},
|
||||||
|
{'href': 'http://192.168.50.25/volume/v3/',
|
||||||
|
'rel': 'self'}],
|
||||||
|
'media-types': [
|
||||||
|
{'base': 'application/json',
|
||||||
|
'type': 'application/vnd.openstack.volume+json;version=3'}
|
||||||
|
],
|
||||||
|
'min_version': '3.0',
|
||||||
|
'status': 'CURRENT',
|
||||||
|
'updated': '2016-02-08T12:20:21Z',
|
||||||
|
'version': '3.16',
|
||||||
|
}
|
||||||
|
TEST.cinder_versions.add(ver2)
|
||||||
|
TEST.cinder_versions.add(ver3)
|
||||||
|
|
||||||
# Services
|
# Services
|
||||||
service_1 = services.Service(services.ServiceManager(None), {
|
service_1 = services.Service(services.ServiceManager(None), {
|
||||||
"service": "cinder-scheduler",
|
"service": "cinder-scheduler",
|
||||||
|
|
|
@ -16,6 +16,8 @@ from django.conf import settings
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
import cinderclient as cinder_client
|
import cinderclient as cinder_client
|
||||||
|
from cinderclient import api_versions
|
||||||
|
from cinderclient import exceptions as cinder_exception
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
|
@ -446,6 +448,83 @@ class CinderApiTests(test.APIMockTestCase):
|
||||||
self.assertEqual(default_volume_type, volume_type)
|
self.assertEqual(default_volume_type, volume_type)
|
||||||
cinderclient.volume_types.default.assert_called_once()
|
cinderclient.volume_types.default.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch.object(api.cinder, 'cinderclient')
|
||||||
|
def _check_get_server_version_v3(self, volume_url, version_url, expected,
|
||||||
|
mock_cinderclient):
|
||||||
|
versions = {'versions': self.cinder_versions.list()}
|
||||||
|
cinder_client = mock_cinderclient.return_value
|
||||||
|
cinder_client.client.request.return_value = (200, versions)
|
||||||
|
|
||||||
|
versions = api.cinder._get_server_version(self.request, volume_url)
|
||||||
|
|
||||||
|
self.assertEqual(expected, versions)
|
||||||
|
cinder_client.client.request.assert_called_once_with(
|
||||||
|
version_url, 'GET')
|
||||||
|
|
||||||
|
def test_get_server_version_v3_dedicated_port_http(self):
|
||||||
|
volume_url = ('http://192.168.122.127:8776/v3/'
|
||||||
|
'e5526285ebd741b1819393f772f11fc3')
|
||||||
|
version_url = 'http://192.168.122.127:8776/'
|
||||||
|
expected = (api_versions.APIVersion('3.0'),
|
||||||
|
api_versions.APIVersion('3.16'))
|
||||||
|
self._check_get_server_version_v3(volume_url, version_url, expected)
|
||||||
|
|
||||||
|
def test_get_server_version_v3_dedicated_port_https(self):
|
||||||
|
volume_url = ('https://192.168.122.127:8776/v3/'
|
||||||
|
'e55285ebd741b1819393f772f11fc3')
|
||||||
|
version_url = 'https://192.168.122.127:8776/'
|
||||||
|
expected = (api_versions.APIVersion('3.0'),
|
||||||
|
api_versions.APIVersion('3.16'))
|
||||||
|
self._check_get_server_version_v3(volume_url, version_url, expected)
|
||||||
|
|
||||||
|
def test_get_server_version_v3_path(self):
|
||||||
|
volume_url = ('http://192.168.122.127/volumes/v3/'
|
||||||
|
'e5526285ebd741b1819393f772f11fc3')
|
||||||
|
version_url = 'http://192.168.122.127/volumes/'
|
||||||
|
expected = (api_versions.APIVersion('3.0'),
|
||||||
|
api_versions.APIVersion('3.16'))
|
||||||
|
self._check_get_server_version_v3(volume_url, version_url, expected)
|
||||||
|
|
||||||
|
def test_get_server_version_v3_without_project_id(self):
|
||||||
|
volume_url = 'http://192.168.122.127/volumes/v3/'
|
||||||
|
version_url = 'http://192.168.122.127/volumes/'
|
||||||
|
expected = (api_versions.APIVersion('3.0'),
|
||||||
|
api_versions.APIVersion('3.16'))
|
||||||
|
self._check_get_server_version_v3(volume_url, version_url, expected)
|
||||||
|
|
||||||
|
@mock.patch.object(api.cinder, 'cinderclient')
|
||||||
|
def test_get_server_version_v2(self, mock_cinderclient):
|
||||||
|
versions = {'versions': [x for x in self.cinder_versions.list()
|
||||||
|
if x['id'] == 'v2.0']}
|
||||||
|
cinder_client = mock_cinderclient.return_value
|
||||||
|
cinder_client.client.request.return_value = (200, versions)
|
||||||
|
|
||||||
|
versions = api.cinder._get_server_version(
|
||||||
|
self.request,
|
||||||
|
'http://192.168.122.127:8776/v2/e5526285ebd741b1819393f772f11fc3')
|
||||||
|
|
||||||
|
self.assertEqual((api_versions.APIVersion('2.0'),
|
||||||
|
api_versions.APIVersion('2.0')),
|
||||||
|
versions)
|
||||||
|
cinder_client.client.request.assert_called_once_with(
|
||||||
|
'http://192.168.122.127:8776/', 'GET')
|
||||||
|
|
||||||
|
@mock.patch.object(api.cinder, 'cinderclient')
|
||||||
|
def test_get_server_version_exception(self, mock_cinderclient):
|
||||||
|
cinder_client = mock_cinderclient.return_value
|
||||||
|
cinder_client.client.request.side_effect = \
|
||||||
|
cinder_exception.ClientException(500)
|
||||||
|
|
||||||
|
versions = api.cinder._get_server_version(
|
||||||
|
self.request,
|
||||||
|
'http://192.168.122.127:8776/v3/')
|
||||||
|
|
||||||
|
self.assertEqual((api_versions.APIVersion('2.0'),
|
||||||
|
api_versions.APIVersion('2.0')),
|
||||||
|
versions)
|
||||||
|
cinder_client.client.request.assert_called_once_with(
|
||||||
|
'http://192.168.122.127:8776/', 'GET')
|
||||||
|
|
||||||
|
|
||||||
class CinderApiVersionTests(test.TestCase):
|
class CinderApiVersionTests(test.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
[:bug:`1744670`]
|
||||||
|
Previously when a custom SSL CA is used horizon cannot retrieve volume
|
||||||
|
and snapshot information from cinder. It is fixed now and a custom CA
|
||||||
|
is handled properly in horizon when communicating with cinder.
|
Loading…
Reference in New Issue