Merge "Remove deprecated v1 cinder api support"
This commit is contained in:
commit
249a65f6f2
|
@ -13,7 +13,7 @@
|
|||
|
||||
from cinderclient import client as cc
|
||||
from cinderclient import exceptions
|
||||
from keystoneclient import exceptions as ks_exceptions
|
||||
from keystoneauth1 import exceptions as ks_exceptions
|
||||
from oslo_log import log as logging
|
||||
|
||||
from heat.common import exception
|
||||
|
@ -33,53 +33,40 @@ class CinderClientPlugin(client_plugin.ClientPlugin):
|
|||
|
||||
exceptions_module = exceptions
|
||||
|
||||
service_types = [VOLUME, VOLUME_V2] = ['volume', 'volumev2']
|
||||
service_types = [VOLUME_V2, VOLUME_V3] = ['volumev2', 'volumev3']
|
||||
|
||||
def get_volume_api_version(self):
|
||||
'''Returns the most recent API version.'''
|
||||
|
||||
endpoint_type = self._get_client_option(CLIENT_NAME, 'endpoint_type')
|
||||
self.interface = self._get_client_option(CLIENT_NAME, 'endpoint_type')
|
||||
try:
|
||||
self.url_for(service_type=self.VOLUME_V2,
|
||||
endpoint_type=endpoint_type)
|
||||
return 2
|
||||
self.context.keystone_session.get_endpoint(
|
||||
service_type=self.VOLUME_V3,
|
||||
interface=self.interface)
|
||||
self.service_type = self.VOLUME_V3
|
||||
self.client_version = '3'
|
||||
except ks_exceptions.EndpointNotFound:
|
||||
try:
|
||||
self.url_for(service_type=self.VOLUME,
|
||||
endpoint_type=endpoint_type)
|
||||
return 1
|
||||
self.context.keystone_session.get_endpoint(
|
||||
service_type=self.VOLUME_V2,
|
||||
interface=self.interface)
|
||||
self.service_type = self.VOLUME_V2
|
||||
self.client_version = '2'
|
||||
except ks_exceptions.EndpointNotFound:
|
||||
return None
|
||||
raise exception.Error(_('No volume service available.'))
|
||||
|
||||
def _create(self):
|
||||
|
||||
con = self.context
|
||||
|
||||
volume_api_version = self.get_volume_api_version()
|
||||
if volume_api_version == 1:
|
||||
service_type = self.VOLUME
|
||||
client_version = '1'
|
||||
elif volume_api_version == 2:
|
||||
service_type = self.VOLUME_V2
|
||||
client_version = '2'
|
||||
else:
|
||||
raise exception.Error(_('No volume service available.'))
|
||||
LOG.info(_LI('Creating Cinder client with volume API version %d.'),
|
||||
volume_api_version)
|
||||
|
||||
interface = self._get_client_option(CLIENT_NAME, 'endpoint_type')
|
||||
extensions = cc.discover_extensions(client_version)
|
||||
self.get_volume_api_version()
|
||||
extensions = cc.discover_extensions(self.client_version)
|
||||
args = {
|
||||
'session': con.keystone_session,
|
||||
'session': self.context.keystone_session,
|
||||
'extensions': extensions,
|
||||
'interface': interface,
|
||||
'service_type': service_type,
|
||||
'interface': self.interface,
|
||||
'service_type': self.service_type,
|
||||
'http_log_debug': self._get_client_option(CLIENT_NAME,
|
||||
'http_log_debug')
|
||||
}
|
||||
|
||||
client = cc.Client(client_version, **args)
|
||||
client.volume_api_version = volume_api_version
|
||||
client = cc.Client(self.client_version, **args)
|
||||
return client
|
||||
|
||||
@os_client.MEMOIZE_EXTENSIONS
|
||||
|
|
|
@ -160,8 +160,7 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
|||
),
|
||||
MULTI_ATTACH: properties.Schema(
|
||||
properties.Schema.BOOLEAN,
|
||||
_('Whether allow the volume to be attached more than once. '
|
||||
'This property is only supported from Cinder API v2.'),
|
||||
_('Whether allow the volume to be attached more than once.'),
|
||||
support_status=support.SupportStatus(version='6.0.0'),
|
||||
),
|
||||
}
|
||||
|
@ -287,11 +286,10 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
|||
return six.text_type(jsonutils.dumps(vol.metadata))
|
||||
elif name == self.METADATA_VALUES_ATTR:
|
||||
return vol.metadata
|
||||
if cinder.volume_api_version >= 2:
|
||||
if name == self.DISPLAY_NAME_ATTR:
|
||||
return vol.name
|
||||
elif name == self.DISPLAY_DESCRIPTION_ATTR:
|
||||
return vol.description
|
||||
if name == self.DISPLAY_NAME_ATTR:
|
||||
return vol.name
|
||||
elif name == self.DISPLAY_DESCRIPTION_ATTR:
|
||||
return vol.description
|
||||
return six.text_type(getattr(vol, name))
|
||||
|
||||
def check_create_complete(self, vol_id):
|
||||
|
@ -386,8 +384,8 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
|||
self.properties[self.NAME])
|
||||
update_description = (prop_diff.get(self.DESCRIPTION) or
|
||||
self.properties[self.DESCRIPTION])
|
||||
kwargs = self._fetch_name_and_description(
|
||||
cinder.volume_api_version, update_name, update_description)
|
||||
kwargs = self._fetch_name_and_description(update_name,
|
||||
update_description)
|
||||
cinder.volumes.update(vol, **kwargs)
|
||||
# update the metadata for cinder volume
|
||||
if self.METADATA in prop_diff:
|
||||
|
@ -397,16 +395,10 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
|||
cinder.volumes.update_all_metadata(vol, metadata)
|
||||
# retype
|
||||
if self.VOLUME_TYPE in prop_diff:
|
||||
if cinder.volume_api_version == 1:
|
||||
LOG.info(_LI('Volume type update not supported '
|
||||
'by Cinder API V1.'))
|
||||
raise exception.NotSupported(
|
||||
feature=_('Using Cinder API V1, volume_type update'))
|
||||
else:
|
||||
if not vol:
|
||||
vol = cinder.volumes.get(self.resource_id)
|
||||
new_vol_type = prop_diff.get(self.VOLUME_TYPE)
|
||||
cinder.volumes.retype(vol, new_vol_type, 'never')
|
||||
if not vol:
|
||||
vol = cinder.volumes.get(self.resource_id)
|
||||
new_vol_type = prop_diff.get(self.VOLUME_TYPE)
|
||||
cinder.volumes.retype(vol, new_vol_type, 'never')
|
||||
# update read_only access mode
|
||||
if self.READ_ONLY in prop_diff:
|
||||
if not vol:
|
||||
|
@ -605,19 +597,6 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin):
|
|||
if res is not None:
|
||||
return res
|
||||
|
||||
# Scheduler hints are only supported from Cinder API v2
|
||||
if (self.properties[self.CINDER_SCHEDULER_HINTS]
|
||||
and self.client().volume_api_version == 1):
|
||||
raise exception.StackValidationFailed(
|
||||
message=_('Scheduler hints are not supported by the current '
|
||||
'volume API.'))
|
||||
# Multi attach is only supported from Cinder API v2
|
||||
if (self.properties[self.MULTI_ATTACH]
|
||||
and self.client().volume_api_version == 1):
|
||||
raise exception.StackValidationFailed(
|
||||
message=_('Multiple attach is not supported by the current '
|
||||
'volume API. Use this property since '
|
||||
'Cinder API v2.'))
|
||||
# can not specify both image and imageRef
|
||||
image = self.properties.get(self.IMAGE)
|
||||
imageRef = self.properties.get(self.IMAGE_REF)
|
||||
|
|
|
@ -145,9 +145,6 @@ class CinderVolumeType(resource.Resource):
|
|||
super(CinderVolumeType, self).validate()
|
||||
|
||||
if self.properties[self.PROJECTS]:
|
||||
if self.client().volume_api_version == 1:
|
||||
raise exception.NotSupported(
|
||||
feature=_('Using Cinder API V1, volume type access'))
|
||||
if self.properties[self.IS_PUBLIC]:
|
||||
msg = (_('Can not specify property "%s" '
|
||||
'if the volume type is public.') % self.PROJECTS)
|
||||
|
|
|
@ -22,20 +22,20 @@ class BaseVolume(resource.Resource):
|
|||
|
||||
default_client_name = 'cinder'
|
||||
|
||||
def _create_arguments():
|
||||
return {}
|
||||
|
||||
def handle_create(self):
|
||||
backup_id = self.properties.get(self.BACKUP_ID)
|
||||
cinder = self.client()
|
||||
if backup_id is not None:
|
||||
vol_id = cinder.restores.restore(backup_id).volume_id
|
||||
|
||||
vol = cinder.volumes.get(vol_id)
|
||||
kwargs = self._fetch_name_and_description(
|
||||
cinder.version)
|
||||
kwargs = self._fetch_name_and_description()
|
||||
cinder.volumes.update(vol_id, **kwargs)
|
||||
else:
|
||||
kwargs = self._create_arguments()
|
||||
kwargs.update(self._fetch_name_and_description(
|
||||
cinder.version))
|
||||
kwargs.update(self._fetch_name_and_description())
|
||||
vol = cinder.volumes.create(**kwargs)
|
||||
self.resource_id_set(vol.id)
|
||||
|
||||
|
@ -62,14 +62,10 @@ class BaseVolume(resource.Resource):
|
|||
def _description(self):
|
||||
return self.physical_resource_name()
|
||||
|
||||
def _fetch_name_and_description(self, api_version, name=None,
|
||||
def _fetch_name_and_description(self, name=None,
|
||||
description=None):
|
||||
if api_version == 1:
|
||||
return {'display_name': name or self._name(),
|
||||
'display_description': description or self._description()}
|
||||
else:
|
||||
return {'name': name or self._name(),
|
||||
'description': description or self._description()}
|
||||
return {'name': name or self._name(),
|
||||
'description': description or self._description()}
|
||||
|
||||
def handle_check(self):
|
||||
vol = self.client().volumes.get(self.resource_id)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import uuid
|
||||
|
||||
from keystoneauth1 import exceptions as ks_exceptions
|
||||
import mock
|
||||
|
||||
from heat.common import exception
|
||||
|
@ -136,23 +137,26 @@ class VolumeBackupConstraintTest(common.HeatTestCase):
|
|||
|
||||
class CinderClientAPIVersionTest(common.HeatTestCase):
|
||||
|
||||
def test_cinder_api_v1_and_v2(self):
|
||||
self.stub_auth()
|
||||
def test_cinder_api_v3(self):
|
||||
ctx = utils.dummy_context()
|
||||
self.patchobject(ctx.keystone_session, 'get_endpoint')
|
||||
client = ctx.clients.client('cinder')
|
||||
self.assertEqual(2, client.volume_api_version)
|
||||
self.assertEqual('3.0', client.version)
|
||||
|
||||
def test_cinder_api_v1_only(self):
|
||||
self.stub_auth(only_services=['volume'])
|
||||
def test_cinder_api_v2(self):
|
||||
ctx = utils.dummy_context()
|
||||
self.patchobject(ctx.keystone_session, 'get_endpoint',
|
||||
side_effect=[ks_exceptions.EndpointNotFound,
|
||||
None])
|
||||
client = ctx.clients.client('cinder')
|
||||
self.assertEqual(1, client.volume_api_version)
|
||||
self.assertEqual('2.0', client.version)
|
||||
|
||||
def test_cinder_api_v2_only(self):
|
||||
self.stub_auth(only_services=['volumev2'])
|
||||
def test_cinder_api_not_supported(self):
|
||||
ctx = utils.dummy_context()
|
||||
client = ctx.clients.client('cinder')
|
||||
self.assertEqual(2, client.volume_api_version)
|
||||
self.patchobject(ctx.keystone_session, 'get_endpoint',
|
||||
side_effect=[ks_exceptions.EndpointNotFound,
|
||||
ks_exceptions.EndpointNotFound])
|
||||
self.assertRaises(exception.Error, ctx.clients.client, 'cinder')
|
||||
|
||||
|
||||
class CinderClientPluginExtensionsTest(CinderClientPluginTest):
|
||||
|
|
|
@ -543,21 +543,6 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
|
|||
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
|
||||
self.assertEqual(1, self.cinder_fc.volumes.retype.call_count)
|
||||
|
||||
self.cinder_fc.volume_api_version = 1
|
||||
new_vol_type_1 = 'new_type_1'
|
||||
props = copy.deepcopy(rsrc.properties.data)
|
||||
props['volume_type'] = new_vol_type_1
|
||||
after = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
|
||||
# if the volume api is v1, not support to retype
|
||||
update_task = scheduler.TaskRunner(rsrc.update, after)
|
||||
ex = self.assertRaises(exception.ResourceFailure, update_task)
|
||||
self.assertEqual('NotSupported: resources.volume2: '
|
||||
'Using Cinder API V1, '
|
||||
'volume_type update is not supported.',
|
||||
six.text_type(ex))
|
||||
self.assertEqual((rsrc.UPDATE, rsrc.FAILED), rsrc.state)
|
||||
self.assertEqual(1, self.cinder_fc.volumes.retype.call_count)
|
||||
|
||||
def test_cinder_volume_update_name_and_metadata(self):
|
||||
# update the name, description and metadata
|
||||
fv = vt_base.FakeVolume('creating',
|
||||
|
@ -980,20 +965,6 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
|
|||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_cinder_create_with_scheduler_hints_and_cinder_api_v1(self):
|
||||
cinder.CinderClientPlugin._create().AndReturn(self.cinder_fc)
|
||||
self.cinder_fc.volume_api_version = 1
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
stack_name = 'test_cvolume_scheduler_hints_api_v1_stack'
|
||||
stack = utils.parse_stack(self.t, stack_name=stack_name)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
self.create_volume, self.t, stack, 'volume3')
|
||||
self.assertIn('Scheduler hints are not supported by the current '
|
||||
'volume API.', six.text_type(ex))
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_cinder_create_with_stack_scheduler_hints(self):
|
||||
fv = vt_base.FakeVolume('creating')
|
||||
sh.cfg.CONF.set_override('stack_scheduler_hints', True,
|
||||
|
@ -1031,22 +1002,6 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
|
|||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_cinder_create_with_multiattach_and_cinder_api_v1(self):
|
||||
cinder.CinderClientPlugin._create().AndReturn(self.cinder_fc)
|
||||
self.cinder_fc.volume_api_version = 1
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
stack_name = 'test_cvolume_multiattach_api_v1_stack'
|
||||
stack = utils.parse_stack(self.t, stack_name=stack_name)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
self.create_volume, self.t, stack, 'volume4')
|
||||
self.assertIn('Multiple attach is not supported by the current '
|
||||
'volume API. Use this property since '
|
||||
'Cinder API v2.', six.text_type(ex))
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def _test_cinder_create_invalid_property_combinations(
|
||||
self, stack_name, combinations, err_msg, exc):
|
||||
stack = utils.parse_stack(self.t, stack_name=stack_name)
|
||||
|
|
|
@ -172,20 +172,6 @@ class CinderVolumeTypeTest(common.HeatTestCase):
|
|||
self.volume_type_access.add_project_access.assert_called_once_with(
|
||||
self.my_volume_type.resource_id, 'id3')
|
||||
|
||||
def test_validate_projects_in_v1(self):
|
||||
tmpl = self.stack.t.t
|
||||
props = tmpl['resources']['my_volume_type']['properties'].copy()
|
||||
props['is_public'] = False
|
||||
props['projects'] = ['id1']
|
||||
self.my_volume_type.t = self.my_volume_type.t.freeze(properties=props)
|
||||
self.my_volume_type.reparse()
|
||||
self.cinderclient.volume_api_version = 1
|
||||
self.stub_KeystoneProjectConstraint()
|
||||
ex = self.assertRaises(exception.NotSupported,
|
||||
self.my_volume_type.validate)
|
||||
expected = 'Using Cinder API V1, volume type access is not supported.'
|
||||
self.assertEqual(expected, six.text_type(ex))
|
||||
|
||||
def test_validate_projects_when_public(self):
|
||||
tmpl = self.stack.t.t
|
||||
props = tmpl['resources']['my_volume_type']['properties'].copy()
|
||||
|
|
Loading…
Reference in New Issue