Implement cinder client plugin

This moves the client creation code out of Clients._cinder() into
its own client plugin.

Cinder is a core project, and python-cinderclient is a dependency,
so the import is now mandatory (including the volume_backups import).

Change-Id: I6b937422cd8e20fa620a7e875ae8b4c61e8f9cf8
This commit is contained in:
Steve Baker 2014-06-04 15:12:03 +12:00
parent 7d3111f941
commit d234e26131
6 changed files with 66 additions and 62 deletions

View File

@ -12,7 +12,6 @@
# under the License. # under the License.
from ceilometerclient import client as ceilometerclient from ceilometerclient import client as ceilometerclient
from cinderclient import client as cinderclient
from heatclient import client as heatclient from heatclient import client as heatclient
from oslo.config import cfg from oslo.config import cfg
from stevedore import extension from stevedore import extension
@ -116,29 +115,6 @@ class OpenStackClients(object):
'Replace with calls to client("cinder")') 'Replace with calls to client("cinder")')
return self.client('cinder') return self.client('cinder')
def _cinder(self):
con = self.context
endpoint_type = self._get_client_option('cinder', 'endpoint_type')
args = {
'service_type': 'volume',
'auth_url': con.auth_url,
'project_id': con.tenant,
'username': None,
'api_key': None,
'endpoint_type': endpoint_type,
'cacert': self._get_client_option('cinder', 'ca_file'),
'insecure': self._get_client_option('cinder', 'insecure')
}
client = cinderclient.Client('1', **args)
management_url = self.url_for(service_type='volume',
endpoint_type=endpoint_type)
client.client.auth_token = self.auth_token
client.client.management_url = management_url
return client
def trove(self): def trove(self):
warnings.warn('trove() is deprecated. ' warnings.warn('trove() is deprecated. '
'Replace with calls to client("trove")') 'Replace with calls to client("trove")')

View File

@ -0,0 +1,42 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from cinderclient import client as cc
from heat.engine.clients import client_plugin
class CinderClientPlugin(client_plugin.ClientPlugin):
def _create(self):
con = self.context
endpoint_type = self._get_client_option('cinder', 'endpoint_type')
args = {
'service_type': 'volume',
'auth_url': con.auth_url,
'project_id': con.tenant,
'username': None,
'api_key': None,
'endpoint_type': endpoint_type,
'cacert': self._get_client_option('cinder', 'ca_file'),
'insecure': self._get_client_option('cinder', 'insecure')
}
client = cc.Client('1', **args)
management_url = self.url_for(service_type='volume',
endpoint_type=endpoint_type)
client.client.auth_token = self.auth_token
client.client.management_url = management_url
return client

View File

@ -11,23 +11,21 @@
# 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 import client as cinderclient
from cinderclient.v1 import volume_backups
import json import json
from novaclient import exceptions as nova_exceptions from novaclient import exceptions as nova_exceptions
from heat.common import exception from heat.common import exception
from heat.engine import attributes from heat.engine import attributes
from heat.engine import clients
from heat.engine import constraints from heat.engine import constraints
from heat.engine import properties from heat.engine import properties
from heat.engine import resource from heat.engine import resource
from heat.engine.resources import glance_utils from heat.engine.resources import glance_utils
from heat.engine import scheduler from heat.engine import scheduler
from heat.engine import support from heat.engine import support
from heat.openstack.common.importutils import try_import
from heat.openstack.common import log as logging from heat.openstack.common import log as logging
volume_backups = try_import('cinderclient.v1.volume_backups')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -163,7 +161,7 @@ class Volume(resource.Resource):
while True: while True:
yield yield
vol.get() vol.get()
except clients.cinderclient.exceptions.NotFound: except cinderclient.exceptions.NotFound:
self.resource_id_set(None) self.resource_id_set(None)
if volume_backups is not None: if volume_backups is not None:
@ -256,7 +254,7 @@ class VolumeExtendTask(object):
try: try:
cinder.extend(self.volume_id, self.size) cinder.extend(self.volume_id, self.size)
except clients.cinderclient.exceptions.ClientException as ex: except cinderclient.exceptions.ClientException as ex:
raise exception.Error(_( raise exception.Error(_(
"Failed to extend volume %(vol)s - %(err)s") % { "Failed to extend volume %(vol)s - %(err)s") % {
'vol': vol.id, 'err': str(ex)}) 'vol': vol.id, 'err': str(ex)})
@ -362,7 +360,7 @@ class VolumeDetachTask(object):
nova_vol = server_api.get_server_volume(self.server_id, nova_vol = server_api.get_server_volume(self.server_id,
self.attachment_id) self.attachment_id)
vol = self.clients.client('cinder').volumes.get(nova_vol.id) vol = self.clients.client('cinder').volumes.get(nova_vol.id)
except (clients.cinderclient.exceptions.NotFound, except (cinderclient.exceptions.NotFound,
nova_exceptions.BadRequest, nova_exceptions.BadRequest,
nova_exceptions.NotFound): nova_exceptions.NotFound):
LOG.warning(_('%s - volume not found') % str(self)) LOG.warning(_('%s - volume not found') % str(self))
@ -389,7 +387,7 @@ class VolumeDetachTask(object):
if vol.status != 'available': if vol.status != 'available':
raise exception.Error(vol.status) raise exception.Error(vol.status)
except clients.cinderclient.exceptions.NotFound: except cinderclient.exceptions.NotFound:
LOG.warning(_('%s - volume not found') % str(self)) LOG.warning(_('%s - volume not found') % str(self))
# The next check is needed for immediate reattachment when updating: # The next check is needed for immediate reattachment when updating:

View File

@ -13,7 +13,6 @@
from glanceclient import exc as glance_exceptions from glanceclient import exc as glance_exceptions
import mock import mock
from testtools import skipIf
from heat.common import exception from heat.common import exception
from heat.common import template_format from heat.common import template_format
@ -25,7 +24,6 @@ from heat.engine import parser
from heat.engine import resources from heat.engine import resources
from heat.engine.resources import glance_utils from heat.engine.resources import glance_utils
from heat.engine import service from heat.engine import service
from heat.openstack.common.importutils import try_import
from heat.tests.common import HeatTestCase from heat.tests.common import HeatTestCase
from heat.tests import utils from heat.tests import utils
from heat.tests.v1_1 import fakes from heat.tests.v1_1 import fakes
@ -1064,8 +1062,6 @@ class validateTest(HeatTestCase):
self.assertEqual( self.assertEqual(
{'Error': '"Snapshot" deletion policy not supported'}, res) {'Error': '"Snapshot" deletion policy not supported'}, res)
@skipIf(try_import('cinderclient.v1.volume_backups') is None,
'unable to import volume_backups')
def test_volume_snapshot_deletion_policy(self): def test_volume_snapshot_deletion_policy(self):
t = template_format.parse(test_template_volume_snapshot) t = template_format.parse(test_template_volume_snapshot)
engine = service.EngineService('a', 't') engine = service.EngineService('a', 't')

View File

@ -14,14 +14,14 @@
import copy import copy
import json import json
from cinderclient import exceptions as cinder_exp
from cinderclient.v1 import client as cinderclient from cinderclient.v1 import client as cinderclient
import mox import mox
import six import six
from testtools import skipIf
from heat.common import exception from heat.common import exception
from heat.common import template_format from heat.common import template_format
from heat.engine import clients from heat.engine.clients.os import cinder
from heat.engine.clients.os import glance from heat.engine.clients.os import glance
from heat.engine.clients.os import nova from heat.engine.clients.os import nova
from heat.engine.resources import glance_utils from heat.engine.resources import glance_utils
@ -31,14 +31,11 @@ from heat.engine.resources import volume as vol
from heat.engine import rsrc_defn from heat.engine import rsrc_defn
from heat.engine import scheduler from heat.engine import scheduler
from heat.engine import template from heat.engine import template
from heat.openstack.common.importutils import try_import
from heat.tests.common import HeatTestCase from heat.tests.common import HeatTestCase
from heat.tests import utils from heat.tests import utils
from heat.tests.v1_1 import fakes from heat.tests.v1_1 import fakes
volume_backups = try_import('cinderclient.v1.volume_backups')
volume_template = ''' volume_template = '''
{ {
"AWSTemplateFormatVersion" : "2010-09-09", "AWSTemplateFormatVersion" : "2010-09-09",
@ -102,7 +99,7 @@ class VolumeTest(HeatTestCase):
super(VolumeTest, self).setUp() super(VolumeTest, self).setUp()
self.fc = fakes.FakeClient() self.fc = fakes.FakeClient()
self.cinder_fc = cinderclient.Client('username', 'password') self.cinder_fc = cinderclient.Client('username', 'password')
self.m.StubOutWithMock(clients.OpenStackClients, '_cinder') self.m.StubOutWithMock(cinder.CinderClientPlugin, '_create')
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create') self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
self.m.StubOutWithMock(self.cinder_fc.volumes, 'create') self.m.StubOutWithMock(self.cinder_fc.volumes, 'create')
self.m.StubOutWithMock(self.cinder_fc.volumes, 'get') self.m.StubOutWithMock(self.cinder_fc.volumes, 'get')
@ -146,7 +143,7 @@ class VolumeTest(HeatTestCase):
return rsrc return rsrc
def _mock_create_volume(self, fv, stack_name, size=1): def _mock_create_volume(self, fv, stack_name, size=1):
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
vol_name = utils.PhysName(stack_name, 'DataVolume') vol_name = utils.PhysName(stack_name, 'DataVolume')
self.cinder_fc.volumes.create( self.cinder_fc.volumes.create(
@ -161,7 +158,7 @@ class VolumeTest(HeatTestCase):
self.m.StubOutWithMock(fv, 'get') self.m.StubOutWithMock(fv, 'get')
fv.get().AndReturn(None) fv.get().AndReturn(None)
fv.get().AndRaise( fv.get().AndRaise(
clients.cinderclient.exceptions.NotFound('Not found')) cinder_exp.NotFound('Not found'))
self.m.ReplayAll() self.m.ReplayAll()
def _mock_create_server_volume_script(self, fva, def _mock_create_server_volume_script(self, fva,
@ -221,7 +218,7 @@ class VolumeTest(HeatTestCase):
self.m.StubOutWithMock(image.ImageConstraint, "validate") self.m.StubOutWithMock(image.ImageConstraint, "validate")
instance.Instance.handle_create().AndReturn(None) instance.Instance.handle_create().AndReturn(None)
instance.Instance.check_create_complete(None).AndReturn(True) instance.Instance.check_create_complete(None).AndReturn(True)
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
image.ImageConstraint.validate( image.ImageConstraint.validate(
mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(True) mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(True)
@ -239,7 +236,7 @@ class VolumeTest(HeatTestCase):
self.m.StubOutWithMock(vol.VolumeAttachment, 'handle_delete') self.m.StubOutWithMock(vol.VolumeAttachment, 'handle_delete')
instance.Instance.handle_delete().AndReturn(None) instance.Instance.handle_delete().AndReturn(None)
self.cinder_fc.volumes.get('vol-123').AndRaise( self.cinder_fc.volumes.get('vol-123').AndRaise(
clients.cinderclient.exceptions.NotFound('Not found')) cinder_exp.NotFound('Not found'))
vol.VolumeAttachment.handle_delete().AndReturn(None) vol.VolumeAttachment.handle_delete().AndReturn(None)
self.m.ReplayAll() self.m.ReplayAll()
@ -401,7 +398,7 @@ class VolumeTest(HeatTestCase):
self.fc.volumes.get_server_volume(u'WikiDatabase', self.fc.volumes.get_server_volume(u'WikiDatabase',
'vol-123').AndReturn(fva) 'vol-123').AndReturn(fva)
self.cinder_fc.volumes.get(fva.id).AndRaise( self.cinder_fc.volumes.get(fva.id).AndRaise(
clients.cinderclient.exceptions.NotFound('Not found')) cinder_exp.NotFound('Not found'))
self.m.ReplayAll() self.m.ReplayAll()
@ -673,7 +670,6 @@ class VolumeTest(HeatTestCase):
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state) self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
self.m.VerifyAll() self.m.VerifyAll()
@skipIf(volume_backups is None, 'unable to import volume_backups')
def test_snapshot(self): def test_snapshot(self):
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
fv = FakeVolume('creating', 'available') fv = FakeVolume('creating', 'available')
@ -699,7 +695,6 @@ class VolumeTest(HeatTestCase):
self.m.VerifyAll() self.m.VerifyAll()
@skipIf(volume_backups is None, 'unable to import volume_backups')
def test_snapshot_error(self): def test_snapshot_error(self):
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
fv = FakeVolume('creating', 'available') fv = FakeVolume('creating', 'available')
@ -724,7 +719,6 @@ class VolumeTest(HeatTestCase):
self.m.VerifyAll() self.m.VerifyAll()
@skipIf(volume_backups is None, 'unable to import volume_backups')
def test_snapshot_no_volume(self): def test_snapshot_no_volume(self):
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
fv = FakeVolume('creating', 'error') fv = FakeVolume('creating', 'error')
@ -752,14 +746,13 @@ class VolumeTest(HeatTestCase):
self.m.VerifyAll() self.m.VerifyAll()
@skipIf(volume_backups is None, 'unable to import volume_backups')
def test_create_from_snapshot(self): def test_create_from_snapshot(self):
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
fv = FakeVolumeWithStateTransition('restoring-backup', 'available') fv = FakeVolumeWithStateTransition('restoring-backup', 'available')
fvbr = FakeBackupRestore('vol-123') fvbr = FakeBackupRestore('vol-123')
# create script # create script
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
self.m.StubOutWithMock(self.cinder_fc.restores, 'restore') self.m.StubOutWithMock(self.cinder_fc.restores, 'restore')
self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr) self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr)
@ -781,14 +774,13 @@ class VolumeTest(HeatTestCase):
self.m.VerifyAll() self.m.VerifyAll()
@skipIf(volume_backups is None, 'unable to import volume_backups')
def test_create_from_snapshot_error(self): def test_create_from_snapshot_error(self):
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
fv = FakeVolumeWithStateTransition('restoring-backup', 'error') fv = FakeVolumeWithStateTransition('restoring-backup', 'error')
fvbr = FakeBackupRestore('vol-123') fvbr = FakeBackupRestore('vol-123')
# create script # create script
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
self.m.StubOutWithMock(self.cinder_fc.restores, 'restore') self.m.StubOutWithMock(self.cinder_fc.restores, 'restore')
self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr) self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr)
@ -819,7 +811,7 @@ class VolumeTest(HeatTestCase):
fv = FakeVolume('creating', 'available') fv = FakeVolume('creating', 'available')
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
self.cinder_fc.volumes.create( self.cinder_fc.volumes.create(
size=1, availability_zone='nova', size=1, availability_zone='nova',
@ -891,7 +883,7 @@ class VolumeTest(HeatTestCase):
fv = FakeVolumeWithStateTransition('downloading', 'available') fv = FakeVolumeWithStateTransition('downloading', 'available')
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
image_id = '46988116-6703-4623-9dbc-2bc6d284021b' image_id = '46988116-6703-4623-9dbc-2bc6d284021b'
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
g_cli_mock = self.m.CreateMockAnything() g_cli_mock = self.m.CreateMockAnything()
self.m.StubOutWithMock(glance.GlanceClientPlugin, '_create') self.m.StubOutWithMock(glance.GlanceClientPlugin, '_create')
@ -934,7 +926,7 @@ class VolumeTest(HeatTestCase):
fv = FakeVolume('creating', 'available') fv = FakeVolume('creating', 'available')
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
vol_name = utils.PhysName(stack_name, 'DataVolume') vol_name = utils.PhysName(stack_name, 'DataVolume')
self.cinder_fc.volumes.create( self.cinder_fc.volumes.create(
@ -971,7 +963,7 @@ class VolumeTest(HeatTestCase):
created_at='2013-02-25T02:40:21.000000') created_at='2013-02-25T02:40:21.000000')
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
vol_name = utils.PhysName(stack_name, 'DataVolume') vol_name = utils.PhysName(stack_name, 'DataVolume')
self.cinder_fc.volumes.create( self.cinder_fc.volumes.create(
@ -1136,7 +1128,7 @@ class VolumeTest(HeatTestCase):
self.cinder_fc.volumes.get(fv.id).AndReturn(fv2) self.cinder_fc.volumes.get(fv.id).AndReturn(fv2)
self.cinder_fc.volumes.extend(fv.id, 2).AndRaise( self.cinder_fc.volumes.extend(fv.id, 2).AndRaise(
clients.cinderclient.exceptions.OverLimit) cinder_exp.OverLimit)
self.m.ReplayAll() self.m.ReplayAll()
@ -1248,7 +1240,6 @@ class VolumeTest(HeatTestCase):
self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state) self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state)
self.m.VerifyAll() self.m.VerifyAll()
@skipIf(volume_backups is None, 'unable to import volume_backups')
def test_volume_extend_created_from_snapshot_with_same_size(self): def test_volume_extend_created_from_snapshot_with_same_size(self):
stack_name = 'test_volume_stack' stack_name = 'test_volume_stack'
fv = FakeVolumeWithStateTransition('restoring-backup', 'available', fv = FakeVolumeWithStateTransition('restoring-backup', 'available',
@ -1256,7 +1247,7 @@ class VolumeTest(HeatTestCase):
fvbr = FakeBackupRestore('vol-123') fvbr = FakeBackupRestore('vol-123')
# create script # create script
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
self.m.StubOutWithMock(self.cinder_fc.restores, 'restore') self.m.StubOutWithMock(self.cinder_fc.restores, 'restore')
self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr) self.cinder_fc.restores.restore('backup-123').AndReturn(fvbr)
@ -1304,7 +1295,7 @@ class VolumeTest(HeatTestCase):
'display_description': update_description 'display_description': update_description
} }
clients.OpenStackClients._cinder().MultipleTimes().AndReturn( cinder.CinderClientPlugin._create().MultipleTimes().AndReturn(
self.cinder_fc) self.cinder_fc)
self.cinder_fc.volumes.create( self.cinder_fc.volumes.create(
availability_zone=None, availability_zone=None,

View File

@ -38,6 +38,7 @@ oslo.config.opts =
heat.common.wsgi = heat.common.wsgi:list_opts heat.common.wsgi = heat.common.wsgi:list_opts
heat.clients = heat.clients =
cinder = heat.engine.clients.os.cinder:CinderClientPlugin
glance = heat.engine.clients.os.glance:GlanceClientPlugin glance = heat.engine.clients.os.glance:GlanceClientPlugin
nova = heat.engine.clients.os.nova:NovaClientPlugin nova = heat.engine.clients.os.nova:NovaClientPlugin
neutron = heat.engine.clients.os.neutron:NeutronClientPlugin neutron = heat.engine.clients.os.neutron:NeutronClientPlugin