Remove deprecated v1 cinder api support

This removes the deprecated cinder v1 api and adds
support for v3 api in the client plugin.

Change-Id: I6af06ed85c7022e0e47072985c578aa455b7eb1a
This commit is contained in:
Rabi Mishra 2016-07-27 13:12:15 +05:30
parent 2d61ac7763
commit 0dabb9febc
7 changed files with 53 additions and 149 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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):

View File

@ -544,21 +544,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',
@ -981,20 +966,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,
@ -1032,22 +1003,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)

View File

@ -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()