Merge "SF remove deprecated sf_allow_template_caching"
This commit is contained in:
@@ -347,6 +347,8 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
}]
|
||||
}
|
||||
}
|
||||
elif method == 'ListSnapshots':
|
||||
raise exception.VolumeNotFound('test clone unconfigured image')
|
||||
else:
|
||||
# Crap, unimplemented API call in Fake
|
||||
return None
|
||||
@@ -380,12 +382,9 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
return {'fake': 'fake-model'}
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_template_account')
|
||||
def test_create_volume_with_qos_type(self,
|
||||
_mock_create_template_account,
|
||||
_mock_issue_api_request):
|
||||
_mock_issue_api_request.side_effect = self.fake_issue_api_request
|
||||
_mock_create_template_account.return_value = 1
|
||||
testvol = {'project_id': 'testprjid',
|
||||
'name': 'testvol',
|
||||
'size': 1,
|
||||
@@ -444,12 +443,9 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
sfv.create_volume(testvol)['qos'])
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_template_account')
|
||||
def test_create_volume(self,
|
||||
_mock_create_template_account,
|
||||
_mock_issue_api_request):
|
||||
_mock_issue_api_request.side_effect = self.fake_issue_api_request
|
||||
_mock_create_template_account.return_value = 1
|
||||
testvol = {'project_id': 'testprjid',
|
||||
'name': 'testvol',
|
||||
'size': 1,
|
||||
@@ -473,12 +469,9 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
self.assertNotIn('provider_geometry', model_update)
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_template_account')
|
||||
def test_create_volume_non_512e(self,
|
||||
_mock_create_template_account,
|
||||
_mock_issue_api_request):
|
||||
_mock_issue_api_request.side_effect = self.fake_issue_api_request
|
||||
_mock_create_template_account.return_value = 1
|
||||
testvol = {'project_id': 'testprjid',
|
||||
'name': 'testvol',
|
||||
'size': 1,
|
||||
@@ -533,12 +526,9 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
sfv.delete_snapshot(testsnap)
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_template_account')
|
||||
def test_create_clone(self,
|
||||
_mock_create_template_account,
|
||||
_mock_issue_api_request):
|
||||
_mock_issue_api_request.side_effect = self.fake_issue_api_request
|
||||
_mock_create_template_account.return_value = 1
|
||||
_fake_get_snaps = [{'snapshotID': 5, 'name': 'testvol'}]
|
||||
_fake_get_volume = (
|
||||
{'volumeID': 99,
|
||||
@@ -1335,12 +1325,9 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
self.assertEqual(2, size)
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_template_account')
|
||||
def test_create_volume_for_migration(self,
|
||||
_mock_create_template_account,
|
||||
_mock_issue_api_request):
|
||||
_mock_issue_api_request.side_effect = self.fake_issue_api_request
|
||||
_mock_create_template_account.return_value = 1
|
||||
testvol = {'project_id': 'testprjid',
|
||||
'name': 'testvol',
|
||||
'size': 1,
|
||||
@@ -1375,81 +1362,6 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
self.assertEqual('UUID-a720b3c0-d1f0-11e1-9b23-0800200c9a66',
|
||||
sf_vol_object['name'])
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_image_volume')
|
||||
def test_verify_image_volume_out_of_date(self,
|
||||
_mock_create_image_volume,
|
||||
_mock_get_sf_volume,
|
||||
_mock_get_sfaccount,
|
||||
_mock_issue_api_request,
|
||||
_mock_update_cluster_status):
|
||||
fake_sf_vref = {
|
||||
'status': 'active', 'volumeID': 1,
|
||||
'attributes': {
|
||||
'image_info':
|
||||
{'image_updated_at': '2014-12-17T00:16:23+00:00',
|
||||
'image_id': '17c550bb-a411-44c0-9aaf-0d96dd47f501',
|
||||
'image_name': 'fake-image',
|
||||
'image_created_at': '2014-12-17T00:16:23+00:00'}}}
|
||||
|
||||
_mock_update_cluster_status.return_value = None
|
||||
_mock_issue_api_request.side_effect = (
|
||||
self.fake_issue_api_request)
|
||||
_mock_get_sfaccount.return_value = {'username': 'openstack-vtemplate',
|
||||
'accountID': 7777}
|
||||
_mock_get_sf_volume.return_value = fake_sf_vref
|
||||
_mock_create_image_volume.return_value = fake_sf_vref
|
||||
|
||||
image_meta = {'id': '17c550bb-a411-44c0-9aaf-0d96dd47f501',
|
||||
'updated_at': datetime.datetime(2013, 9, 28,
|
||||
15, 27, 36,
|
||||
325355)}
|
||||
image_service = 'null'
|
||||
|
||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||
sfv._verify_image_volume(self.ctxt, image_meta, image_service)
|
||||
self.assertTrue(_mock_create_image_volume.called)
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_update_cluster_status')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_get_sfaccount')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_get_sf_volume')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_image_volume')
|
||||
def test_verify_image_volume_ok(self,
|
||||
_mock_create_image_volume,
|
||||
_mock_get_sf_volume,
|
||||
_mock_get_sfaccount,
|
||||
_mock_issue_api_request,
|
||||
_mock_update_cluster_status):
|
||||
|
||||
_mock_issue_api_request.side_effect = self.fake_issue_api_request
|
||||
_mock_update_cluster_status.return_value = None
|
||||
_mock_get_sfaccount.return_value = {'username': 'openstack-vtemplate',
|
||||
'accountID': 7777}
|
||||
_mock_get_sf_volume.return_value =\
|
||||
{'status': 'active', 'volumeID': 1,
|
||||
'attributes': {
|
||||
'image_info':
|
||||
{'image_updated_at': '2013-09-28T15:27:36.325355',
|
||||
'image_id': '17c550bb-a411-44c0-9aaf-0d96dd47f501',
|
||||
'image_name': 'fake-image',
|
||||
'image_created_at': '2014-12-17T00:16:23+00:00'}}}
|
||||
_mock_create_image_volume.return_value = None
|
||||
|
||||
image_meta = {'id': '17c550bb-a411-44c0-9aaf-0d96dd47f501',
|
||||
'updated_at': datetime.datetime(2013, 9, 28,
|
||||
15, 27, 36,
|
||||
325355)}
|
||||
image_service = 'null'
|
||||
|
||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||
|
||||
sfv._verify_image_volume(self.ctxt, image_meta, image_service)
|
||||
self.assertFalse(_mock_create_image_volume.called)
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_issue_api_request')
|
||||
def test_clone_image_not_configured(self, _mock_issue_api_request):
|
||||
_mock_issue_api_request.side_effect = self.fake_issue_api_request
|
||||
@@ -1462,129 +1374,6 @@ class SolidFireVolumeTestCase(test.TestCase):
|
||||
self.fake_image_meta,
|
||||
'fake'))
|
||||
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_template_account')
|
||||
@mock.patch.object(solidfire.SolidFireDriver, '_create_image_volume')
|
||||
def test_clone_image_authorization(self,
|
||||
_mock_create_image_volume,
|
||||
_mock_create_template_account):
|
||||
fake_sf_vref = {
|
||||
'status': 'active', 'volumeID': 1,
|
||||
'attributes': {
|
||||
'image_info':
|
||||
{'image_updated_at': '2014-12-17T00:16:23+00:00',
|
||||
'image_id': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
|
||||
'image_name': 'fake-image',
|
||||
'image_created_at': '2014-12-17T00:16:23+00:00'}}}
|
||||
_mock_create_image_volume.return_value = fake_sf_vref
|
||||
_mock_create_template_account.return_value = 1
|
||||
|
||||
self.configuration.sf_allow_template_caching = True
|
||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||
|
||||
# Make sure if it's NOT public and we're NOT the owner it
|
||||
# doesn't try and cache
|
||||
timestamp = datetime.datetime(2011, 1, 1, 1, 2, 3)
|
||||
_fake_image_meta = {
|
||||
'id': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
|
||||
'name': 'fakeimage123456',
|
||||
'created_at': timestamp,
|
||||
'updated_at': timestamp,
|
||||
'deleted_at': None,
|
||||
'deleted': False,
|
||||
'status': 'active',
|
||||
'visibility': 'private',
|
||||
'protected': False,
|
||||
'container_format': 'raw',
|
||||
'disk_format': 'raw',
|
||||
'owner': 'wrong-owner',
|
||||
'properties': {'kernel_id': 'nokernel',
|
||||
'ramdisk_id': 'nokernel',
|
||||
'architecture': 'x86_64'}}
|
||||
|
||||
with mock.patch.object(sfv, '_do_clone_volume',
|
||||
return_value=('fe', 'fi', 'fo')):
|
||||
self.assertEqual((None, False),
|
||||
sfv.clone_image(self.ctxt,
|
||||
self.mock_volume,
|
||||
'fake',
|
||||
_fake_image_meta,
|
||||
self.fake_image_service))
|
||||
|
||||
# And is_public False, but the correct owner does work
|
||||
_fake_image_meta['owner'] = 'testprjid'
|
||||
self.assertEqual(
|
||||
('fo', True),
|
||||
sfv.clone_image(
|
||||
self.ctxt,
|
||||
self.mock_volume,
|
||||
'fake',
|
||||
_fake_image_meta,
|
||||
self.fake_image_service))
|
||||
|
||||
# And is_public True, even if not the correct owner
|
||||
_fake_image_meta['is_public'] = True
|
||||
_fake_image_meta['owner'] = 'wrong-owner'
|
||||
self.assertEqual(
|
||||
('fo', True),
|
||||
sfv.clone_image(self.ctxt,
|
||||
self.mock_volume,
|
||||
'fake',
|
||||
_fake_image_meta,
|
||||
self.fake_image_service))
|
||||
# And using the new V2 visibility tag
|
||||
_fake_image_meta['visibility'] = 'public'
|
||||
_fake_image_meta['owner'] = 'wrong-owner'
|
||||
self.assertEqual(
|
||||
('fo', True),
|
||||
sfv.clone_image(self.ctxt,
|
||||
self.mock_volume,
|
||||
'fake',
|
||||
_fake_image_meta,
|
||||
self.fake_image_service))
|
||||
|
||||
def test_create_template_no_account(self):
|
||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||
|
||||
def _fake_issue_api_req(method, params, version=0):
|
||||
if 'GetAccountByName' in method:
|
||||
raise solidfire.SolidFireAPIException
|
||||
return {'result': {'accountID': 1}}
|
||||
|
||||
with mock.patch.object(sfv,
|
||||
'_issue_api_request',
|
||||
side_effect=_fake_issue_api_req):
|
||||
self.assertEqual(1,
|
||||
sfv._create_template_account('foo'))
|
||||
|
||||
def test_configured_svip(self):
|
||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||
|
||||
def _fake_get_volumes(account_id, endpoint=None):
|
||||
return [{'volumeID': 1,
|
||||
'iqn': ''}]
|
||||
|
||||
def _fake_get_cluster_info():
|
||||
return {'clusterInfo': {'svip': '10.10.10.10',
|
||||
'mvip': '1.1.1.1'}}
|
||||
|
||||
with mock.patch.object(sfv,
|
||||
'_get_volumes_by_sfaccount',
|
||||
side_effect=_fake_get_volumes),\
|
||||
mock.patch.object(sfv,
|
||||
'_issue_api_request',
|
||||
side_effect=self.fake_issue_api_request):
|
||||
|
||||
sfaccount = {'targetSecret': 'yakitiyak',
|
||||
'accountID': 5,
|
||||
'username': 'bobthebuilder'}
|
||||
v = sfv._get_model_info(sfaccount, 1)
|
||||
self.assertEqual('1.1.1.1:3260 0', v['provider_location'])
|
||||
|
||||
configured_svip = '9.9.9.9:6500'
|
||||
sfv.active_cluster['svip'] = configured_svip
|
||||
v = sfv._get_model_info(sfaccount, 1)
|
||||
self.assertEqual('%s 0' % configured_svip, v['provider_location'])
|
||||
|
||||
def test_init_volume_mappings(self):
|
||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import six
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder.image import image_utils
|
||||
from cinder import interface
|
||||
from cinder.objects import fields
|
||||
from cinder import utils
|
||||
@@ -68,21 +67,6 @@ sf_opts = [
|
||||
'are of the form <sf_volume_prefix><cinder-volume-id>. '
|
||||
'The default is to use a prefix of \'UUID-\'.'),
|
||||
|
||||
cfg.StrOpt('sf_template_account_name',
|
||||
default='openstack-vtemplate',
|
||||
help='Account name on the SolidFire Cluster to use as owner of '
|
||||
'template/cache volumes (created if does not exist).'),
|
||||
|
||||
cfg.BoolOpt('sf_allow_template_caching',
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason='The Cinder caching feature should be '
|
||||
'used rather than this driver specific '
|
||||
'implementation.',
|
||||
default=False,
|
||||
help='This option is deprecated and will be removed in '
|
||||
'the next OpenStack release. Please use the general '
|
||||
'cinder image-caching feature instead.'),
|
||||
|
||||
cfg.StrOpt('sf_svip',
|
||||
help='Overrides default cluster SVIP with the one specified. '
|
||||
'This is required or deployments that have implemented '
|
||||
@@ -311,10 +295,6 @@ class SolidFireDriver(san.SanISCSIDriver):
|
||||
except SolidFireAPIException:
|
||||
pass
|
||||
|
||||
if self.configuration.sf_allow_template_caching:
|
||||
account = self.configuration.sf_template_account_name
|
||||
self.template_account_id = self._create_template_account(account)
|
||||
|
||||
self._set_cluster_pairs()
|
||||
|
||||
@staticmethod
|
||||
@@ -497,27 +477,6 @@ class SolidFireDriver(san.SanISCSIDriver):
|
||||
snapshot_updates = self._init_snapshot_mappings(snaprefs)
|
||||
return (volume_updates, snapshot_updates)
|
||||
|
||||
def _create_template_account(self, account_name):
|
||||
# We raise an API exception if the account doesn't exist
|
||||
|
||||
# We need to take account_prefix settings into consideration
|
||||
# This just uses the same method to do template account create
|
||||
# as we use for any other OpenStack account
|
||||
account_name = self._get_sf_account_name(account_name)
|
||||
try:
|
||||
id = self._issue_api_request(
|
||||
'GetAccountByName',
|
||||
{'username': account_name})['result']['account']['accountID']
|
||||
except SolidFireAPIException:
|
||||
chap_secret = self._generate_random_string(12)
|
||||
params = {'username': account_name,
|
||||
'initiatorSecret': chap_secret,
|
||||
'targetSecret': chap_secret,
|
||||
'attributes': {}}
|
||||
id = self._issue_api_request('AddAccount',
|
||||
params)['result']['accountID']
|
||||
return id
|
||||
|
||||
def _build_endpoint_info(self, **kwargs):
|
||||
endpoint = {}
|
||||
|
||||
@@ -1001,122 +960,6 @@ class SolidFireDriver(san.SanISCSIDriver):
|
||||
return self._issue_api_request(
|
||||
'ListSnapshots', params, version='6.0')['result']['snapshots']
|
||||
|
||||
def _create_image_volume(self, context,
|
||||
image_meta, image_service,
|
||||
image_id):
|
||||
with image_utils.TemporaryImages.fetch(image_service,
|
||||
context,
|
||||
image_id) as tmp_image:
|
||||
data = image_utils.qemu_img_info(tmp_image)
|
||||
fmt = data.file_format
|
||||
if fmt is None:
|
||||
raise exception.ImageUnacceptable(
|
||||
reason=_("'qemu-img info' parsing failed."),
|
||||
image_id=image_id)
|
||||
|
||||
backing_file = data.backing_file
|
||||
if backing_file is not None:
|
||||
raise exception.ImageUnacceptable(
|
||||
image_id=image_id,
|
||||
reason=_("fmt=%(fmt)s backed by:%(backing_file)s")
|
||||
% {'fmt': fmt, 'backing_file': backing_file, })
|
||||
|
||||
virtual_size = int(math.ceil(float(data.virtual_size) / units.Gi))
|
||||
attributes = {}
|
||||
attributes['image_info'] = {}
|
||||
attributes['image_info']['image_updated_at'] = (
|
||||
image_meta['updated_at'].isoformat())
|
||||
attributes['image_info']['image_name'] = (
|
||||
image_meta['name'])
|
||||
attributes['image_info']['image_created_at'] = (
|
||||
image_meta['created_at'].isoformat())
|
||||
attributes['image_info']['image_id'] = image_meta['id']
|
||||
params = {'name': 'OpenStackIMG-%s' % image_id,
|
||||
'accountID': self.template_account_id,
|
||||
'sliceCount': 1,
|
||||
'totalSize': int(virtual_size * units.Gi),
|
||||
'enable512e': self.configuration.sf_emulate_512,
|
||||
'attributes': attributes,
|
||||
'qos': {}}
|
||||
|
||||
sf_account = self._issue_api_request(
|
||||
'GetAccountByID',
|
||||
{'accountID': self.template_account_id})['result']['account']
|
||||
template_vol = self._do_volume_create(sf_account, params)
|
||||
|
||||
tvol = {}
|
||||
tvol['id'] = image_id
|
||||
tvol['provider_location'] = template_vol['provider_location']
|
||||
tvol['provider_auth'] = template_vol['provider_auth']
|
||||
|
||||
attach_info = None
|
||||
|
||||
try:
|
||||
connector = {'multipath': False}
|
||||
conn = self.initialize_connection(tvol, connector)
|
||||
attach_info = super(SolidFireDriver, self)._connect_device(
|
||||
conn)
|
||||
properties = 'na'
|
||||
image_utils.convert_image(tmp_image,
|
||||
attach_info['device']['path'],
|
||||
'raw',
|
||||
run_as_root=True)
|
||||
data = image_utils.qemu_img_info(attach_info['device']['path'],
|
||||
run_as_root=True)
|
||||
if data.file_format != 'raw':
|
||||
raise exception.ImageUnacceptable(
|
||||
image_id=image_id,
|
||||
reason=_("Converted to %(vol_format)s, but format is "
|
||||
"now %(file_format)s") % {'vol_format': 'raw',
|
||||
'file_format': data.
|
||||
file_format})
|
||||
except Exception as exc:
|
||||
vol = self._get_sf_volume(image_id)
|
||||
LOG.error('Failed image conversion during '
|
||||
'cache creation: %s',
|
||||
exc)
|
||||
LOG.debug('Removing SolidFire Cache Volume (SF ID): %s',
|
||||
vol['volumeID'])
|
||||
if attach_info is not None:
|
||||
self._detach_volume(context, attach_info, tvol, properties)
|
||||
self._issue_api_request('DeleteVolume', params)
|
||||
self._issue_api_request('PurgeDeletedVolume', params)
|
||||
return
|
||||
|
||||
self._detach_volume(context, attach_info, tvol, properties)
|
||||
sf_vol = self._get_sf_volume(image_id, params)
|
||||
LOG.debug('Successfully created SolidFire Image Template '
|
||||
'for image-id: %s', image_id)
|
||||
return sf_vol
|
||||
|
||||
def _verify_image_volume(self, context, image_meta, image_service):
|
||||
# This method just verifies that IF we have a cache volume that
|
||||
# it's still up to date and current WRT the image in Glance
|
||||
# ie an image-update hasn't occurred since we grabbed it
|
||||
|
||||
# If it's out of date, just delete it and we'll create a new one
|
||||
# Any other case we don't care and just return without doing anything
|
||||
|
||||
params = {'accountID': self.template_account_id}
|
||||
sf_vol = self._get_sf_volume(image_meta['id'], params)
|
||||
if not sf_vol:
|
||||
self._create_image_volume(context,
|
||||
image_meta,
|
||||
image_service,
|
||||
image_meta['id'])
|
||||
return
|
||||
|
||||
if sf_vol['attributes']['image_info']['image_updated_at'] != (
|
||||
image_meta['updated_at'].isoformat()):
|
||||
params = {'accountID': self.template_account_id}
|
||||
params['volumeID'] = sf_vol['volumeID']
|
||||
self._issue_api_request('DeleteVolume', params)
|
||||
self._issue_api_request('PurgeDeletedVolume', params)
|
||||
self._create_image_volume(context,
|
||||
image_meta,
|
||||
image_service,
|
||||
image_meta['id'])
|
||||
|
||||
def _get_sfaccounts_for_tenant(self, cinder_project_id):
|
||||
accounts = self._issue_api_request(
|
||||
'ListAccounts', {})['result']['accounts']
|
||||
@@ -1341,11 +1184,6 @@ class SolidFireDriver(san.SanISCSIDriver):
|
||||
image_meta, image_service):
|
||||
"""Clone an existing image volume."""
|
||||
public = False
|
||||
# Check out pre-requisites:
|
||||
# Is template caching enabled?
|
||||
if not self.configuration.sf_allow_template_caching:
|
||||
return None, False
|
||||
|
||||
# NOTE(jdg): Glance V2 moved from is_public to visibility
|
||||
# so we check both, as we don't necessarily know or want
|
||||
# to care which we're using. Will need to look at
|
||||
@@ -1363,17 +1201,14 @@ class SolidFireDriver(san.SanISCSIDriver):
|
||||
LOG.warning("Requested image is not "
|
||||
"accessible by current Tenant.")
|
||||
return None, False
|
||||
|
||||
# If we don't have the image-volume to clone from return failure
|
||||
# cinder driver will then create source for clone first
|
||||
try:
|
||||
self._verify_image_volume(context,
|
||||
image_meta,
|
||||
image_service)
|
||||
except SolidFireAPIException:
|
||||
(data, sfaccount, model) = self._do_clone_volume(image_meta['id'],
|
||||
volume)
|
||||
except exception.VolumeNotFound:
|
||||
return None, False
|
||||
|
||||
# Ok, should be good to go now, try it again
|
||||
(data, sfaccount, model) = self._do_clone_volume(image_meta['id'],
|
||||
volume)
|
||||
return model, True
|
||||
|
||||
# extended_size > 0 when we are extending a volume
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
prelude: >
|
||||
SolidFire cinder driver deprecate sf_allow_template_caching
|
||||
deprecations:
|
||||
- |
|
||||
The configuration option sf_allow_template_caching for the
|
||||
SolidFire cinder driver has been removed. Use image_volume_cache_enabled
|
||||
equals True for a better template image cache that is managed from
|
||||
cinder.
|
||||
Reference in New Issue
Block a user