Drop cinder v2 API support

Cinder v2 API is deprecated since pike release. Along with the removal
of cinder v2 API support in cinderclient (change I335db5c1799e drops
v2 support), this commit drops cinder v2 support in horizon.

The next release of python-cinderclient drops v2 support,
so horizon needs to use v3 classes.

Includes a workaround in unit tests for two cinderclient.v3 classes
that are missing in the cinderclient releases prior to 8.0.0.  The
workaround can be removed once cinderclient change I335db5c1799edb2
is merged and released.

Co-Authored-By: Akihiro Motoki <amotoki@gmail.com>
Change-Id: Iab0f097fab6696462572dc6ea53767c91e5411b1
This commit is contained in:
Brian Rosmaita 2021-07-14 12:32:48 -04:00
parent 310a24d054
commit b58ac2894b
18 changed files with 95 additions and 120 deletions

View File

@ -28,7 +28,7 @@ from django.utils.translation import ugettext_lazy as _
from cinderclient import api_versions 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.v3.contrib import list_extensions as cinder_list_extensions
from horizon import exceptions from horizon import exceptions
from horizon.utils.memoized import memoized from horizon.utils.memoized import memoized
@ -58,9 +58,6 @@ VERSIONS = base.APIVersionManager("volume", preferred_version='3')
try: try:
# pylint: disable=ungrouped-imports # pylint: disable=ungrouped-imports
from cinderclient.v2 import client as cinder_client_v2
VERSIONS.load_supported_version('2', {"client": cinder_client_v2,
"version": '2'})
from cinderclient.v3 import client as cinder_client_v3 from cinderclient.v3 import client as cinder_client_v3
VERSIONS.load_supported_version('3', {"client": cinder_client_v3, VERSIONS.load_supported_version('3', {"client": cinder_client_v3,
"version": '3'}) "version": '3'})
@ -216,11 +213,9 @@ def _find_cinder_url(request, version=None):
version = api_version['version'] version = api_version['version']
version = base.Version(version) version = base.Version(version)
# We support only cinder v2 and v3. # We support only cinder v3.
if version.major == 3: # FIXME: 'block-storage' is also a valid service_type for cinder
candidates = ['volumev3', 'volume'] candidates = ['volumev3', 'volume']
else:
candidates = ['volumev2', 'volume']
for service_name in candidates: for service_name in candidates:
try: try:
@ -1049,8 +1044,8 @@ def message_list(request, search_opts=None):
def is_volume_service_enabled(request): def is_volume_service_enabled(request):
return bool( return bool(
# FIXME: 'block-storage' is also a valid service_type for cinder
base.is_service_enabled(request, 'volumev3') or base.is_service_enabled(request, 'volumev3') or
base.is_service_enabled(request, 'volumev2') or
base.is_service_enabled(request, 'volume') base.is_service_enabled(request, 'volume')
) )

View File

@ -77,7 +77,7 @@ class CinderServicesTab(tabs.TableTab):
slug = tables.CinderServicesTable.Meta.name slug = tables.CinderServicesTable.Meta.name
template_name = constants.INFO_DETAIL_TEMPLATE_NAME template_name = constants.INFO_DETAIL_TEMPLATE_NAME
permissions = ( permissions = (
('openstack.services.volume', 'openstack.services.volumev2', ('openstack.services.volume',
'openstack.services.volumev3'), 'openstack.services.volumev3'),
) )

View File

@ -21,7 +21,7 @@ class Snapshots(horizon.Panel):
name = _("Snapshots") name = _("Snapshots")
slug = 'snapshots' slug = 'snapshots'
permissions = ( permissions = (
('openstack.services.volume', 'openstack.services.volumev2', ('openstack.services.volume',
'openstack.services.volumev3'), 'openstack.services.volumev3'),
) )
policy_rules = (("volume", "context_is_admin"),) policy_rules = (("volume", "context_is_admin"),)

View File

@ -21,7 +21,7 @@ class VolumeTypes(horizon.Panel):
name = _("Volume Types") name = _("Volume Types")
slug = 'volume_types' slug = 'volume_types'
permissions = ( permissions = (
('openstack.services.volume', 'openstack.services.volumev2', ('openstack.services.volume',
'openstack.services.volumev3'), 'openstack.services.volumev3'),
) )
policy_rules = (("volume", "volume_extension:types_manage"),) policy_rules = (("volume", "volume_extension:types_manage"),)

View File

@ -19,7 +19,7 @@ class Volumes(horizon.Panel):
name = _("Volumes") name = _("Volumes")
slug = "volumes" slug = "volumes"
permissions = ( permissions = (
('openstack.services.volume', 'openstack.services.volumev2', ('openstack.services.volume',
'openstack.services.volumev3'), 'openstack.services.volumev3'),
) )
policy_rules = (("volume", "context_is_admin"),) policy_rules = (("volume", "context_is_admin"),)

View File

@ -252,9 +252,9 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({api.cinder: ['volume_get', 'volume_unmanage']}) @test.create_mocks({api.cinder: ['volume_get', 'volume_unmanage']})
def test_unmanage_volume(self): def test_unmanage_volume(self):
# important - need to get the v2 cinder volume which has host data # important - need to get the v3 cinder volume which has host data
volume_list = [x for x in self.cinder_volumes.list() volume_list = [x for x in self.cinder_volumes.list()
if x.name == 'v2_volume'] if x.name == 'v3_volume']
volume = volume_list[0] volume = volume_list[0]
form_data = {'volume_name': volume.name, form_data = {'volume_name': volume.name,
'host_name': 'host@backend-name#pool', 'host_name': 'host@backend-name#pool',
@ -276,7 +276,7 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({api.cinder: ['volume_get', 'pool_list']}) @test.create_mocks({api.cinder: ['volume_get', 'pool_list']})
def test_volume_migrate_get(self): def test_volume_migrate_get(self):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
self.mock_pool_list.return_value = self.cinder_pools.list() self.mock_pool_list.return_value = self.cinder_pools.list()
self.mock_volume_get.return_value = volume self.mock_volume_get.return_value = volume
@ -293,7 +293,7 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({api.cinder: ['volume_get']}) @test.create_mocks({api.cinder: ['volume_get']})
def test_volume_migrate_get_volume_get_exception(self): def test_volume_migrate_get_volume_get_exception(self):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
self.mock_volume_get.side_effect = self.exceptions.cinder self.mock_volume_get.side_effect = self.exceptions.cinder
url = reverse('horizon:admin:volumes:migrate', url = reverse('horizon:admin:volumes:migrate',
@ -306,7 +306,7 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({api.cinder: ['volume_get', 'pool_list']}) @test.create_mocks({api.cinder: ['volume_get', 'pool_list']})
def test_volume_migrate_list_pool_get_exception(self): def test_volume_migrate_list_pool_get_exception(self):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
self.mock_volume_get.return_value = volume self.mock_volume_get.return_value = volume
self.mock_pool_list.side_effect = self.exceptions.cinder self.mock_pool_list.side_effect = self.exceptions.cinder
@ -323,7 +323,7 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({ @test.create_mocks({
api.cinder: ['volume_migrate', 'volume_get', 'pool_list']}) api.cinder: ['volume_migrate', 'volume_get', 'pool_list']})
def test_volume_migrate_post(self): def test_volume_migrate_post(self):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
host = self.cinder_pools.first().name host = self.cinder_pools.first().name
self.mock_volume_get.return_value = volume self.mock_volume_get.return_value = volume
@ -345,7 +345,7 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({ @test.create_mocks({
api.cinder: ['volume_migrate', 'volume_get', 'pool_list']}) api.cinder: ['volume_migrate', 'volume_get', 'pool_list']})
def test_volume_migrate_post_api_exception(self): def test_volume_migrate_post_api_exception(self):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
host = self.cinder_pools.first().name host = self.cinder_pools.first().name
self.mock_volume_get.return_value = volume self.mock_volume_get.return_value = volume
@ -365,7 +365,7 @@ class VolumeTests(test.BaseAdminViewTests):
@test.create_mocks({api.cinder: ['volume_get']}) @test.create_mocks({api.cinder: ['volume_get']})
def test_update_volume_status_get(self): def test_update_volume_status_get(self):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
self.mock_volume_get.return_value = volume self.mock_volume_get.return_value = volume
url = reverse('horizon:admin:volumes:update_status', url = reverse('horizon:admin:volumes:update_status',

View File

@ -23,7 +23,7 @@ class Backups(horizon.Panel):
name = _("Backups") name = _("Backups")
slug = 'backups' slug = 'backups'
permissions = ( permissions = (
('openstack.services.volume', 'openstack.services.volumev2', ('openstack.services.volume',
'openstack.services.volumev3'), 'openstack.services.volumev3'),
) )
policy_rules = (("volume", "backup:get_all"),) policy_rules = (("volume", "backup:get_all"),)

View File

@ -21,7 +21,7 @@ class Snapshots(horizon.Panel):
name = _("Snapshots") name = _("Snapshots")
slug = 'snapshots' slug = 'snapshots'
permissions = ( permissions = (
('openstack.services.volume', 'openstack.services.volumev2', ('openstack.services.volume',
'openstack.services.volumev3'), 'openstack.services.volumev3'),
) )
policy_rules = (("volume", "volume:get_all_snapshots"),) policy_rules = (("volume", "volume:get_all_snapshots"),)

View File

@ -606,13 +606,8 @@
var volumeSnapshotDeferred = $q.defer(); var volumeSnapshotDeferred = $q.defer();
var absoluteLimitsDeferred = $q.defer(); var absoluteLimitsDeferred = $q.defer();
serviceCatalog serviceCatalog
.ifTypeEnabled('volumev2') .ifTypeEnabled('volumev3')
.then(onVolumeServiceEnabled, onCheckVolumeV3); .then(onVolumeServiceEnabled, resolvePromises);
function onCheckVolumeV3() {
serviceCatalog
.ifTypeEnabled('volumev3')
.then(onVolumeServiceEnabled, resolvePromises);
}
function onVolumeServiceEnabled() { function onVolumeServiceEnabled() {
model.volumeBootable = true; model.volumeBootable = true;
model.allowCreateVolumeFromImage = true; model.allowCreateVolumeFromImage = true;

View File

@ -235,8 +235,6 @@
if (theType === 'network' && neutronEnabled) { if (theType === 'network' && neutronEnabled) {
deferred.resolve(); deferred.resolve();
} else if (theType === 'volumev2' && cinderEnabled) {
deferred.resolve();
} else if (theType === 'volumev3' && cinderEnabled) { } else if (theType === 'volumev3' && cinderEnabled) {
deferred.resolve(); deferred.resolve();
} else { } else {

View File

@ -21,7 +21,7 @@ class Volumes(horizon.Panel):
name = _("Volumes") name = _("Volumes")
slug = 'volumes' slug = 'volumes'
permissions = ( permissions = (
('openstack.services.volume', 'openstack.services.volumev2', ('openstack.services.volume',
'openstack.services.volumev3'), 'openstack.services.volumev3'),
) )
policy_rules = (("volume", "volume:get_all"),) policy_rules = (("volume", "volume:get_all"),)

View File

@ -1496,7 +1496,7 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
@mock.patch.object(cinder, 'tenant_absolute_limits') @mock.patch.object(cinder, 'tenant_absolute_limits')
@mock.patch.object(cinder, 'volume_get') @mock.patch.object(cinder, 'volume_get')
def test_get_data(self, mock_get, mock_limits, mock_quotas): def test_get_data(self, mock_get, mock_limits, mock_quotas):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
volume._apiresource.name = "" volume._apiresource.name = ""
mock_get.return_value = volume mock_get.return_value = volume
@ -1693,7 +1693,7 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
@mock.patch.object(cinder, 'volume_upload_to_image') @mock.patch.object(cinder, 'volume_upload_to_image')
@mock.patch.object(cinder, 'volume_get') @mock.patch.object(cinder, 'volume_get')
def test_upload_to_image(self, mock_get, mock_upload, mock_schemas_list): def test_upload_to_image(self, mock_get, mock_upload, mock_schemas_list):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
loaded_resp = {'container_format': 'bare', loaded_resp = {'container_format': 'bare',
'disk_format': 'raw', 'disk_format': 'raw',
'id': '741fe2ac-aa2f-4cec-82a9-4994896b43fb', 'id': '741fe2ac-aa2f-4cec-82a9-4994896b43fb',
@ -1782,7 +1782,7 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase):
@mock.patch.object(cinder, 'volume_get') @mock.patch.object(cinder, 'volume_get')
def test_retype_volume_supported_action_item(self, mock_get, def test_retype_volume_supported_action_item(self, mock_get,
mock_limits, mock_quotas): mock_limits, mock_quotas):
volume = self.cinder_volumes.get(name='v2_volume') volume = self.cinder_volumes.get(name='v3_volume')
limits = self.cinder_limits['absolute'] limits = self.cinder_limits['absolute']
mock_get.return_value = volume mock_get.return_value = volume

View File

@ -72,8 +72,7 @@
function initAction() { function initAction() {
createVolumePromise = policy.ifAllowed({rules: [['volume', 'volume:create']]}); createVolumePromise = policy.ifAllowed({rules: [['volume', 'volume:create']]});
if (serviceCatalog.ifTypeEnabled('volumev2') || if (serviceCatalog.ifTypeEnabled('volumev3')) {
serviceCatalog.ifTypeEnabled('volumev3')) {
volumeServiceEnabledPromise = true; volumeServiceEnabledPromise = true;
} else { } else {
volumeServiceEnabledPromise = false; volumeServiceEnabledPromise = false;

View File

@ -12,29 +12,45 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from cinderclient.v2 import availability_zones from cinderclient.v3 import availability_zones
from cinderclient.v2.contrib import list_extensions as cinder_list_extensions from cinderclient.v3.contrib import list_extensions as cinder_list_extensions
from cinderclient.v2 import pools
from cinderclient.v2 import qos_specs
from cinderclient.v2 import quotas
from cinderclient.v2 import services
from cinderclient.v2 import volume_backups as vol_backups
from cinderclient.v2 import volume_encryption_types as vol_enc_types
from cinderclient.v2 import volume_snapshots as vol_snaps
from cinderclient.v2 import volume_transfers
from cinderclient.v2 import volume_type_access
from cinderclient.v2 import volume_types
from cinderclient.v2 import volumes
from cinderclient.v3 import group_snapshots from cinderclient.v3 import group_snapshots
from cinderclient.v3 import group_types from cinderclient.v3 import group_types
from cinderclient.v3 import groups from cinderclient.v3 import groups
from cinderclient.v3 import messages from cinderclient.v3 import messages
from cinderclient.v3 import pools
from cinderclient.v3 import qos_specs
from cinderclient.v3 import services
from cinderclient.v3 import volume_backups as vol_backups
from cinderclient.v3 import volume_encryption_types as vol_enc_types
from cinderclient.v3 import volume_snapshots as vol_snaps
from cinderclient.v3 import volume_type_access
from cinderclient.v3 import volume_types
from cinderclient.v3 import volumes
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.api import cinder as cinder_api from openstack_dashboard.api import cinder as cinder_api
from openstack_dashboard.test.test_data import utils from openstack_dashboard.test.test_data import utils
from openstack_dashboard.usage import quotas as usage_quotas from openstack_dashboard.usage import quotas as usage_quotas
# FIXME: workaround for some classes being missing from cinderclient.v3
# in python-cinderclient versions < 8.0.0. These can become simple
# 'from cinderclient.v3 import xxx' above after we have
# python-cinderclient>=8.0.0 in requirements.txt
try:
# pylint: disable=ungrouped-imports
from cinderclient.v3.quotas import QuotaSet as _qs # noqa
from cinderclient.v3 import quotas # noqa
except ImportError:
from cinderclient.v2 import quotas
try:
# pylint: disable=ungrouped-imports
from cinderclient.v3.volume_transfers import VolumeTransfer as _vt # noqa
from cinderclient.v3 import volume_transfers # noqa
except ImportError:
from cinderclient.v2 import volume_transfers
def data(TEST): def data(TEST):
TEST.cinder_messages = utils.TestDataContainer() TEST.cinder_messages = utils.TestDataContainer()
@ -186,12 +202,12 @@ def data(TEST):
{'volume_type_id': '1', 'project_id': '1'}) {'volume_type_id': '1', 'project_id': '1'})
TEST.cinder_type_access.add(vol_type_access1) TEST.cinder_type_access.add(vol_type_access1)
# Volumes - Cinder v2 # Volumes - Cinder v3 (v2 removed in Xena)
volume_v2 = volumes.Volume( volume_v3 = volumes.Volume(
volumes.VolumeManager(None), volumes.VolumeManager(None),
{'id': "31023e92-8008-4c8b-8059-7f2293ff1234", {'id': "31023e92-8008-4c8b-8059-7f2293ff1234",
'name': 'v2_volume', 'name': 'v3_volume',
'description': "v2 Volume Description", 'description': "v3 Volume Description",
'status': 'available', 'status': 'available',
'size': 20, 'size': 20,
'created_at': '2014-01-27 10:30:00', 'created_at': '2014-01-27 10:30:00',
@ -199,9 +215,9 @@ def data(TEST):
'os-vol-host-attr:host': 'host@backend-name#pool', 'os-vol-host-attr:host': 'host@backend-name#pool',
'bootable': 'true', 'bootable': 'true',
'attachments': []}) 'attachments': []})
volume_v2.bootable = 'true' volume_v3.bootable = 'true'
TEST.cinder_volumes.add(api.cinder.Volume(volume_v2)) TEST.cinder_volumes.add(api.cinder.Volume(volume_v3))
snapshot = vol_snaps.Snapshot( snapshot = vol_snaps.Snapshot(
vol_snaps.SnapshotManager(None), vol_snaps.SnapshotManager(None),
@ -216,7 +232,7 @@ def data(TEST):
vol_snaps.SnapshotManager(None), vol_snaps.SnapshotManager(None),
{'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0f', {'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0f',
'name': '', 'name': '',
'description': 'v2 volume snapshot description', 'description': 'v3 volume snapshot description',
'size': 80, 'size': 80,
'created_at': '2014-01-27 10:30:00', 'created_at': '2014-01-27 10:30:00',
'status': 'available', 'status': 'available',
@ -225,7 +241,7 @@ def data(TEST):
vol_snaps.SnapshotManager(None), vol_snaps.SnapshotManager(None),
{'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0e', {'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0e',
'name': '', 'name': '',
'description': 'v2 volume snapshot description 2', 'description': 'v3 volume snapshot description 2',
'size': 80, 'size': 80,
'created_at': '2014-01-27 10:30:00', 'created_at': '2014-01-27 10:30:00',
'status': 'available', 'status': 'available',
@ -234,7 +250,7 @@ def data(TEST):
vol_snaps.SnapshotManager(None), vol_snaps.SnapshotManager(None),
{'id': 'cd6be1eb-82ca-4587-8036-13c37c00c2b1', {'id': 'cd6be1eb-82ca-4587-8036-13c37c00c2b1',
'name': '', 'name': '',
'description': 'v2 volume snapshot with metadata description', 'description': 'v3 volume snapshot with metadata description',
'size': 80, 'size': 80,
'created_at': '2014-01-27 10:30:00', 'created_at': '2014-01-27 10:30:00',
'status': 'available', 'status': 'available',
@ -320,7 +336,7 @@ def data(TEST):
TEST.cinder_volume_encryption.add(vol_enc_metadata1) TEST.cinder_volume_encryption.add(vol_enc_metadata1)
TEST.cinder_volume_encryption.add(vol_unenc_metadata1) TEST.cinder_volume_encryption.add(vol_unenc_metadata1)
# v2 extensions # v3 extensions
extensions = [ extensions = [
{'alias': 'os-services', {'alias': 'os-services',
@ -333,11 +349,6 @@ def data(TEST):
'links': '[]', 'links': '[]',
'name': 'AdminActions', 'name': 'AdminActions',
'updated': '2012-08-25T00:00:00+00:00'}, 'updated': '2012-08-25T00:00:00+00:00'},
{'alias': 'os-volume-transfer',
'description': 'Volume transfer management support.',
'links': '[]',
'name': 'VolumeTransfer',
'updated': '2013-05-29T00:00:00+00:00'},
] ]
extensions = [ extensions = [
cinder_list_extensions.ListExtResource( cinder_list_extensions.ListExtResource(
@ -540,7 +551,7 @@ def data(TEST):
vol_snaps.SnapshotManager(None), vol_snaps.SnapshotManager(None),
{'id': 'cd6be1eb-82ca-4587-8036-13c37c00c2b1', {'id': 'cd6be1eb-82ca-4587-8036-13c37c00c2b1',
'name': '', 'name': '',
'description': 'v2 volume snapshot with metadata description', 'description': 'v3 volume snapshot with metadata description',
'size': 80, 'size': 80,
'status': 'available', 'status': 'available',
'volume_id': '7e4efa56-9ca1-45ff-b83c-2efb2383930d', 'volume_id': '7e4efa56-9ca1-45ff-b83c-2efb2383930d',

View File

@ -65,29 +65,6 @@ SERVICE_CATALOG = [
"interface": "public", "interface": "public",
"url": "http://public.nova2.example.com:8774/v2"} "url": "http://public.nova2.example.com:8774/v2"}
]}, ]},
{"type": "volumev2",
"name": "cinderv2",
"endpoints_links": [],
"endpoints": [
{"region": "RegionOne",
"interface": "admin",
"url": "http://admin.cinder.example.com:8776/v2"},
{"region": "RegionOne",
"interface": "internal",
"url": "http://int.cinder.example.com:8776/v2"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.cinder.example.com:8776/v2"},
{"region": "RegionTwo",
"interface": "admin",
"url": "http://admin.cinder2.example.com:8776/v2"},
{"region": "RegionTwo",
"interface": "internal",
"url": "http://int.cinder2.example.com:8776/v2"},
{"region": "RegionTwo",
"interface": "public",
"url": "http://public.cinder.example.com:8776/v2"}
]},
{"type": "volumev3", {"type": "volumev3",
"name": "cinderv3", "name": "cinderv3",
"endpoints_links": [], "endpoints_links": [],

View File

@ -711,19 +711,19 @@ class KeystoneRestTestCase(test.TestCase):
'id': '2b5bc2e59b094f898a43f5e8ce446240', 'id': '2b5bc2e59b094f898a43f5e8ce446240',
'name': 'glance'}, 'name': 'glance'},
{'endpoints': [ {'endpoints': [
{'url': 'http://cool_url/volume/v2/test', {'url': 'http://cool_url/volume/v3/test',
'interface': 'public', 'interface': 'public',
'region': 'RegionOne', 'region': 'RegionOne',
'region_id': 'RegionOne', 'region_id': 'RegionOne',
'id': '29a629afb80547ea9baa4266e97b4cb5'}, 'id': '29a629afb80547ea9baa4266e97b4cb5'},
{'url': 'http://cool_url/volume/v2/test', {'url': 'http://cool_url/volume/v3/test',
'interface': 'admin', 'interface': 'admin',
'region': 'RegionOne', 'region': 'RegionOne',
'region_id': 'RegionOne', 'region_id': 'RegionOne',
'id': '29a629afb80547ea9baa4266e97b4cb5'}], 'id': '29a629afb80547ea9baa4266e97b4cb5'}],
'type': 'volumev2', 'type': 'volumev3',
'id': '55ef272cfa714e54b8f2046c157b027d', 'id': '55ef272cfa714e54b8f2046c157b027d',
'name': 'cinderv2'}, 'name': 'cinderv3'},
{'endpoints': [ {'endpoints': [
{'url': 'http://cool_url/compute/v2/check', {'url': 'http://cool_url/compute/v2/check',
'interface': 'internal', 'interface': 'internal',
@ -745,14 +745,14 @@ class KeystoneRestTestCase(test.TestCase):
'id': '2b5bc2e59b094f898a43f5e8ce446240', 'id': '2b5bc2e59b094f898a43f5e8ce446240',
'name': 'glance'}, 'name': 'glance'},
{'endpoints': [ {'endpoints': [
{'url': 'http://cool_url/volume/v2/test', {'url': 'http://cool_url/volume/v3/test',
'interface': 'public', 'interface': 'public',
'region': 'RegionOne', 'region': 'RegionOne',
'region_id': 'RegionOne', 'region_id': 'RegionOne',
'id': '29a629afb80547ea9baa4266e97b4cb5'}], 'id': '29a629afb80547ea9baa4266e97b4cb5'}],
'type': 'volumev2', 'type': 'volumev3',
'id': '55ef272cfa714e54b8f2046c157b027d', 'id': '55ef272cfa714e54b8f2046c157b027d',
'name': 'cinderv2'}] 'name': 'cinderv3'}]
self.assertEqual(content, jsonutils.loads(response.content)) self.assertEqual(content, jsonutils.loads(response.content))
# #

View File

@ -474,44 +474,35 @@ class CinderApiVersionTests(test.TestCase):
client = api.cinder.cinderclient(self.request) client = api.cinder.cinderclient(self.request)
self.assertIsInstance(client, cinder_client.v3.client.Client) self.assertIsInstance(client, cinder_client.v3.client.Client)
@override_settings(OPENSTACK_API_VERSIONS={'volume': 2}) def test_get_v3_volume_attributes(self):
def test_v2_setting_returns_v2_client(self): # Get a v3 volume
# FIXME(e0ne): this is a temporary workaround to bypass volume = self.cinder_volumes.get(name="v3_volume")
# @memoized_with_request decorator caching. We have to find a better
# solution instead this hack.
self.request.user.username = 'test_user_cinder_v2'
client = api.cinder.cinderclient(self.request)
self.assertIsInstance(client, cinder_client.v2.client.Client)
def test_get_v2_volume_attributes(self):
# Get a v2 volume
volume = self.cinder_volumes.get(name="v2_volume")
self.assertTrue(hasattr(volume._apiresource, 'name')) self.assertTrue(hasattr(volume._apiresource, 'name'))
name = "A v2 test volume name" name = "A v3 test volume name"
description = "A v2 volume description" description = "A v3 volume description"
setattr(volume._apiresource, 'name', name) setattr(volume._apiresource, 'name', name)
setattr(volume._apiresource, 'description', description) setattr(volume._apiresource, 'description', description)
self.assertEqual(name, volume.name) self.assertEqual(name, volume.name)
self.assertEqual(description, volume.description) self.assertEqual(description, volume.description)
def test_get_v2_snapshot_attributes(self): def test_get_v3_snapshot_attributes(self):
# Get a v2 snapshot # Get a v3 snapshot
snapshot = self.cinder_volume_snapshots.get( snapshot = self.cinder_volume_snapshots.get(
description="v2 volume snapshot description") description="v3 volume snapshot description")
self.assertFalse(hasattr(snapshot._apiresource, 'display_name')) self.assertFalse(hasattr(snapshot._apiresource, 'display_name'))
name = "A v2 test snapshot name" name = "A v3 test snapshot name"
description = "A v2 snapshot description" description = "A v3 snapshot description"
setattr(snapshot._apiresource, 'name', name) setattr(snapshot._apiresource, 'name', name)
setattr(snapshot._apiresource, 'description', description) setattr(snapshot._apiresource, 'description', description)
self.assertEqual(name, snapshot.name) self.assertEqual(name, snapshot.name)
self.assertEqual(description, snapshot.description) self.assertEqual(description, snapshot.description)
def test_get_v2_snapshot_metadata(self): def test_get_v3_snapshot_metadata(self):
# Get a v2 snapshot with metadata # Get a v3 snapshot with metadata
snapshot = self.cinder_volume_snapshots.get( snapshot = self.cinder_volume_snapshots.get(
description="v2 volume snapshot with metadata description") description="v3 volume snapshot with metadata description")
self.assertTrue(hasattr(snapshot._apiresource, 'metadata')) self.assertTrue(hasattr(snapshot._apiresource, 'metadata'))
self.assertFalse(hasattr(snapshot._apiresource, 'display_name')) self.assertFalse(hasattr(snapshot._apiresource, 'display_name'))

View File

@ -0,0 +1,9 @@
---
upgrade:
- |
With this release, Horizon uses only the Block Storage API v3.
Horizon has been using the Block Storage API v3 by default since
Queens, so this change should not impact Horizon functionality.
(The Block Storage API v2 was deprecated by the Cinder project
in the Pike release, and is scheduled to be removed in the Xena
release.)