Merge "Update get/delete_volume API to use versionedobjects"
This commit is contained in:
commit
fb256b24d8
@ -143,7 +143,6 @@ class VolumeManageController(wsgi.Controller):
|
||||
msg = _("Service not found.")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
new_volume = dict(new_volume)
|
||||
utils.add_visible_admin_metadata(new_volume)
|
||||
|
||||
return self._view_builder.detail(req, new_volume)
|
||||
|
@ -49,7 +49,7 @@ def _translate_attachment_detail_view(_context, vol):
|
||||
def _translate_attachment_summary_view(_context, vol):
|
||||
"""Maps keys for attachment summary view."""
|
||||
d = []
|
||||
attachments = vol.get('volume_attachment', [])
|
||||
attachments = vol.volume_attachment
|
||||
for attachment in attachments:
|
||||
if attachment.get('attach_status') == 'attached':
|
||||
a = {'id': attachment.get('volume_id'),
|
||||
@ -118,12 +118,8 @@ def _translate_volume_summary_view(context, vol, image_id=None):
|
||||
|
||||
LOG.info(_LI("vol=%s"), vol, context=context)
|
||||
|
||||
if vol.get('volume_metadata'):
|
||||
metadata = vol.get('volume_metadata')
|
||||
d['metadata'] = {item['key']: item['value'] for item in metadata}
|
||||
# avoid circular ref when vol is a Volume instance
|
||||
elif vol.get('metadata') and isinstance(vol.get('metadata'), dict):
|
||||
d['metadata'] = vol['metadata']
|
||||
if vol.metadata:
|
||||
d['metadata'] = vol.metadata
|
||||
else:
|
||||
d['metadata'] = {}
|
||||
|
||||
@ -292,12 +288,10 @@ class VolumeController(wsgi.Controller):
|
||||
filters=search_opts,
|
||||
viewable_admin_meta=True)
|
||||
|
||||
volumes = [dict(vol) for vol in volumes]
|
||||
|
||||
for volume in volumes:
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
|
||||
limited_list = common.limited(volumes, req)
|
||||
limited_list = common.limited(volumes.objects, req)
|
||||
req.cache_db_volumes(limited_list)
|
||||
|
||||
res = [entity_maker(context, vol) for vol in limited_list]
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from cinder.api import common
|
||||
|
||||
@ -71,7 +72,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
'metadata': self._get_volume_metadata(volume),
|
||||
'links': self._get_links(request, volume['id']),
|
||||
'user_id': volume.get('user_id'),
|
||||
'bootable': str(volume.get('bootable')).lower(),
|
||||
'bootable': six.text_type(volume.get('bootable')).lower(),
|
||||
'encrypted': self._is_volume_encrypted(volume),
|
||||
'replication_status': volume.get('replication_status'),
|
||||
'consistencygroup_id': volume.get('consistencygroup_id'),
|
||||
@ -92,7 +93,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
attachments = []
|
||||
|
||||
if volume['attach_status'] == 'attached':
|
||||
attaches = volume.get('volume_attachment', [])
|
||||
attaches = volume.volume_attachment
|
||||
for attachment in attaches:
|
||||
if attachment.get('attach_status') == 'attached':
|
||||
a = {'id': attachment.get('volume_id'),
|
||||
@ -109,14 +110,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
def _get_volume_metadata(self, volume):
|
||||
"""Retrieve the metadata of the volume object."""
|
||||
if volume.get('volume_metadata'):
|
||||
metadata = volume.get('volume_metadata')
|
||||
return {item['key']: item['value'] for item in metadata}
|
||||
# avoid circular ref when vol is a Volume instance
|
||||
elif volume.get('metadata') and isinstance(volume.get('metadata'),
|
||||
dict):
|
||||
return volume['metadata']
|
||||
return {}
|
||||
return volume.metadata
|
||||
|
||||
def _get_volume_type(self, volume):
|
||||
"""Retrieve the type the volume object."""
|
||||
|
@ -249,12 +249,10 @@ class VolumeController(wsgi.Controller):
|
||||
viewable_admin_meta=True,
|
||||
offset=offset)
|
||||
|
||||
volumes = [dict(vol) for vol in volumes]
|
||||
|
||||
for volume in volumes:
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
|
||||
req.cache_db_volumes(volumes)
|
||||
req.cache_db_volumes(volumes.objects)
|
||||
|
||||
if is_detail:
|
||||
volumes = self._view_builder.detail_list(req, volumes)
|
||||
|
@ -63,7 +63,6 @@ from oslo_db.sqlalchemy import migration
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from cinder import i18n
|
||||
i18n.enable_lazy()
|
||||
@ -94,23 +93,6 @@ def args(*args, **kwargs):
|
||||
return _decorator
|
||||
|
||||
|
||||
def param2id(object_id):
|
||||
"""Helper function to convert various id types to internal id.
|
||||
|
||||
:param object_id: e.g. 'vol-0000000a' or 'volume-0000000a' or '10'
|
||||
"""
|
||||
if uuidutils.is_uuid_like(object_id):
|
||||
return object_id
|
||||
elif '-' in object_id:
|
||||
# FIXME(ja): mapping occurs in nova?
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
return int(object_id)
|
||||
except ValueError:
|
||||
return object_id
|
||||
|
||||
|
||||
class ShellCommands(object):
|
||||
def bpython(self):
|
||||
"""Runs a bpython shell.
|
||||
@ -283,22 +265,22 @@ class VolumeCommands(object):
|
||||
def delete(self, volume_id):
|
||||
"""Delete a volume, bypassing the check that it must be available."""
|
||||
ctxt = context.get_admin_context()
|
||||
volume = db.volume_get(ctxt, param2id(volume_id))
|
||||
host = vutils.extract_host(volume['host']) if volume['host'] else None
|
||||
volume = objects.Volume.get_by_id(ctxt, volume_id)
|
||||
host = vutils.extract_host(volume.host) if volume.host else None
|
||||
|
||||
if not host:
|
||||
print(_("Volume not yet assigned to host."))
|
||||
print(_("Deleting volume from database and skipping rpc."))
|
||||
db.volume_destroy(ctxt, param2id(volume_id))
|
||||
volume.destroy()
|
||||
return
|
||||
|
||||
if volume['status'] == 'in-use':
|
||||
if volume.status == 'in-use':
|
||||
print(_("Volume is in-use."))
|
||||
print(_("Detach volume from instance and then try again."))
|
||||
return
|
||||
|
||||
cctxt = self._rpc_client().prepare(server=host)
|
||||
cctxt.cast(ctxt, "delete_volume", volume_id=volume['id'])
|
||||
cctxt.cast(ctxt, "delete_volume", volume_id=volume.id, volume=volume)
|
||||
|
||||
@args('--currenthost', required=True, help='Existing volume host name')
|
||||
@args('--newhost', required=True, help='New volume host name')
|
||||
|
@ -99,6 +99,18 @@ class AdminActionsTest(test.TestCase):
|
||||
resp = req.get_response(app())
|
||||
return resp
|
||||
|
||||
def _create_volume(self, context, updates=None):
|
||||
db_volume = {'status': 'available',
|
||||
'host': 'test',
|
||||
'availability_zone': 'fake_zone',
|
||||
'attach_status': 'detached'}
|
||||
if updates:
|
||||
db_volume.update(updates)
|
||||
|
||||
volume = objects.Volume(context=context, **db_volume)
|
||||
volume.create()
|
||||
return volume
|
||||
|
||||
def test_valid_updates(self):
|
||||
vac = admin_actions.VolumeAdminController()
|
||||
|
||||
@ -375,7 +387,7 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is creating
|
||||
volume = db.volume_create(ctx, {'size': 1})
|
||||
volume = self._create_volume(ctx, {'size': 1, 'host': None})
|
||||
req = webob.Request.blank('/v2/fake/volumes/%s/action' % volume['id'])
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
@ -386,7 +398,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# request is accepted
|
||||
self.assertEqual(202, resp.status_int)
|
||||
# volume is deleted
|
||||
self.assertRaises(exception.NotFound, db.volume_get, ctx, volume['id'])
|
||||
self.assertRaises(exception.NotFound, objects.Volume.get_by_id, ctx,
|
||||
volume.id)
|
||||
|
||||
@mock.patch.object(volume_api.API, 'delete_snapshot', return_value=True)
|
||||
@mock.patch('cinder.objects.Snapshot.get_by_id')
|
||||
@ -416,8 +429,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
@ -473,8 +486,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
@ -530,8 +543,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
@ -617,8 +630,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
@ -668,8 +681,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
@ -695,8 +708,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
connector = {'initiator': 'iqn.2012-07.org.fake:01'}
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
@ -723,8 +736,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
connector = {}
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
@ -738,8 +751,8 @@ class AdminActionsTest(test.TestCase):
|
||||
"""Test that attaching volume reserved for another instance fails."""
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
self.volume_api.reserve_volume(ctx, volume)
|
||||
@ -766,8 +779,8 @@ class AdminActionsTest(test.TestCase):
|
||||
# admin context
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx, {'status': 'available', 'host': 'test',
|
||||
'provider_location': '', 'size': 1})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'size': 1})
|
||||
# start service to handle rpc messages for attach requests
|
||||
svc = self.start_service('volume', host='test')
|
||||
values = {'status': 'attaching',
|
||||
@ -799,11 +812,7 @@ class AdminActionsTest(test.TestCase):
|
||||
'topic': CONF.volume_topic,
|
||||
'created_at': timeutils.utcnow()})
|
||||
# current status is available
|
||||
volume = db.volume_create(admin_ctx,
|
||||
{'status': 'available',
|
||||
'host': 'test',
|
||||
'provider_location': '',
|
||||
'attach_status': ''})
|
||||
volume = self._create_volume(admin_ctx)
|
||||
return volume
|
||||
|
||||
def _migrate_volume_exec(self, ctx, volume, host, expected_status,
|
||||
@ -837,12 +846,9 @@ class AdminActionsTest(test.TestCase):
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
volume = self._migrate_volume_prep()
|
||||
# current status is available
|
||||
volume = db.volume_create(ctx,
|
||||
{'status': 'available',
|
||||
'host': 'test',
|
||||
'provider_location': '',
|
||||
'attach_status': '',
|
||||
'replication_status': 'active'})
|
||||
volume = self._create_volume(ctx, {'provider_location': '',
|
||||
'attach_status': '',
|
||||
'replication_status': 'active'})
|
||||
volume = self._migrate_volume_exec(ctx, volume, host, expected_status)
|
||||
|
||||
def test_migrate_volume_as_non_admin(self):
|
||||
@ -943,10 +949,9 @@ class AdminActionsTest(test.TestCase):
|
||||
|
||||
def test_migrate_volume_comp_no_mig_status(self):
|
||||
admin_ctx = context.get_admin_context()
|
||||
volume1 = db.volume_create(admin_ctx, {'id': 'fake1',
|
||||
'migration_status': 'foo'})
|
||||
volume2 = db.volume_create(admin_ctx, {'id': 'fake2',
|
||||
'migration_status': None})
|
||||
volume1 = self._create_volume(admin_ctx, {'migration_status': 'foo'})
|
||||
volume2 = self._create_volume(admin_ctx, {'migration_status': None})
|
||||
|
||||
expected_status = 400
|
||||
expected_id = None
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
@ -957,12 +962,10 @@ class AdminActionsTest(test.TestCase):
|
||||
|
||||
def test_migrate_volume_comp_bad_mig_status(self):
|
||||
admin_ctx = context.get_admin_context()
|
||||
volume1 = db.volume_create(admin_ctx,
|
||||
{'id': 'fake1',
|
||||
'migration_status': 'migrating'})
|
||||
volume2 = db.volume_create(admin_ctx,
|
||||
{'id': 'fake2',
|
||||
'migration_status': 'target:foo'})
|
||||
volume1 = self._create_volume(admin_ctx,
|
||||
{'migration_status': 'migrating'})
|
||||
volume2 = self._create_volume(admin_ctx,
|
||||
{'migration_status': 'target:foo'})
|
||||
expected_status = 400
|
||||
expected_id = None
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
@ -981,20 +984,14 @@ class AdminActionsTest(test.TestCase):
|
||||
|
||||
def test_migrate_volume_comp_from_nova(self):
|
||||
admin_ctx = context.get_admin_context()
|
||||
volume = db.volume_create(admin_ctx,
|
||||
{'id': 'fake1',
|
||||
'status': 'in-use',
|
||||
'host': 'test',
|
||||
'migration_status': None,
|
||||
'attach_status': 'attached'})
|
||||
new_volume = db.volume_create(admin_ctx,
|
||||
{'id': 'fake2',
|
||||
'status': 'available',
|
||||
'host': 'test',
|
||||
'migration_status': None,
|
||||
'attach_status': 'detached'})
|
||||
volume = self._create_volume(admin_ctx, {'status': 'in-use',
|
||||
'migration_status': None,
|
||||
'attach_status': 'attached'})
|
||||
new_volume = self._create_volume(admin_ctx,
|
||||
{'migration_status': None,
|
||||
'attach_status': 'detached'})
|
||||
expected_status = 200
|
||||
expected_id = 'fake2'
|
||||
expected_id = new_volume.id
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
self._migrate_volume_comp_exec(ctx, volume, new_volume, False,
|
||||
expected_status, expected_id)
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import iso8601
|
||||
import json
|
||||
import uuid
|
||||
|
||||
@ -23,11 +24,13 @@ from oslo_serialization import jsonutils
|
||||
import webob
|
||||
|
||||
from cinder.api.contrib import volume_actions
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.image import glance
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit.api.v2 import stubs
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
from cinder.volume import api as volume_api
|
||||
from cinder.volume import rpcapi as volume_rpcapi
|
||||
@ -43,6 +46,7 @@ class VolumeActionsTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(VolumeActionsTest, self).setUp()
|
||||
self.context = context.RequestContext('fake', 'fake', is_admin=False)
|
||||
self.UUID = uuid.uuid4()
|
||||
self.controller = volume_actions.VolumeActionsController()
|
||||
self.api_patchers = {}
|
||||
@ -52,9 +56,10 @@ class VolumeActionsTest(test.TestCase):
|
||||
self.addCleanup(self.api_patchers[_meth].stop)
|
||||
self.api_patchers[_meth].return_value = True
|
||||
|
||||
vol = {'id': 'fake', 'host': 'fake', 'status': 'available', 'size': 1,
|
||||
'migration_status': None, 'volume_type_id': 'fake',
|
||||
'project_id': 'project_id'}
|
||||
db_vol = {'id': 'fake', 'host': 'fake', 'status': 'available',
|
||||
'size': 1, 'migration_status': None,
|
||||
'volume_type_id': 'fake', 'project_id': 'project_id'}
|
||||
vol = fake_volume.fake_volume_obj(self.context, **db_vol)
|
||||
self.get_patcher = mock.patch('cinder.volume.API.get')
|
||||
self.mock_volume_get = self.get_patcher.start()
|
||||
self.addCleanup(self.get_patcher.stop)
|
||||
@ -789,8 +794,9 @@ class VolumeImageActionsTest(test.TestCase):
|
||||
expected_res = {
|
||||
'os-volume_upload_image': {
|
||||
'id': id,
|
||||
'updated_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'updated_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'status': 'uploading',
|
||||
'display_description': 'displaydesc',
|
||||
'size': 1,
|
||||
@ -845,8 +851,9 @@ class VolumeImageActionsTest(test.TestCase):
|
||||
expected_res = {
|
||||
'os-volume_upload_image': {
|
||||
'id': id,
|
||||
'updated_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'updated_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'status': 'uploading',
|
||||
'display_description': 'displaydesc',
|
||||
'size': 1,
|
||||
@ -898,8 +905,9 @@ class VolumeImageActionsTest(test.TestCase):
|
||||
expected_res = {
|
||||
'os-volume_upload_image': {
|
||||
'id': id,
|
||||
'updated_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'updated_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'status': 'uploading',
|
||||
'display_description': 'displaydesc',
|
||||
'size': 1,
|
||||
@ -944,8 +952,9 @@ class VolumeImageActionsTest(test.TestCase):
|
||||
expected_res = {
|
||||
'os-volume_upload_image': {
|
||||
'id': id,
|
||||
'updated_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'updated_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'status': 'uploading',
|
||||
'display_description': 'displaydesc',
|
||||
'size': 1,
|
||||
|
@ -21,12 +21,14 @@ import webob
|
||||
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
from cinder import objects
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
|
||||
|
||||
def fake_volume_get(*args, **kwargs):
|
||||
def fake_db_volume_get(*args, **kwargs):
|
||||
return {
|
||||
'id': 'fake',
|
||||
'host': 'host001',
|
||||
@ -42,11 +44,18 @@ def fake_volume_get(*args, **kwargs):
|
||||
'project_id': 'fake',
|
||||
'migration_status': None,
|
||||
'_name_id': 'fake2',
|
||||
'attach_status': 'detached',
|
||||
}
|
||||
|
||||
|
||||
def fake_volume_api_get(*args, **kwargs):
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
db_volume = fake_db_volume_get()
|
||||
return fake_volume.fake_volume_obj(ctx, **db_volume)
|
||||
|
||||
|
||||
def fake_volume_get_all(*args, **kwargs):
|
||||
return [fake_volume_get()]
|
||||
return objects.VolumeList(objects=[fake_volume_api_get()])
|
||||
|
||||
|
||||
def app():
|
||||
@ -61,9 +70,9 @@ class VolumeHostAttributeTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(VolumeHostAttributeTest, self).setUp()
|
||||
self.stubs.Set(volume.API, 'get', fake_volume_get)
|
||||
self.stubs.Set(volume.API, 'get', fake_volume_api_get)
|
||||
self.stubs.Set(volume.API, 'get_all', fake_volume_get_all)
|
||||
self.stubs.Set(db, 'volume_get', fake_volume_get)
|
||||
self.stubs.Set(db, 'volume_get', fake_db_volume_get)
|
||||
|
||||
self.UUID = uuid.uuid4()
|
||||
|
||||
|
@ -26,12 +26,14 @@ from cinder.api.openstack import wsgi
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
from cinder import objects
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
|
||||
|
||||
def fake_volume_get(*args, **kwargs):
|
||||
def fake_db_volume_get(*args, **kwargs):
|
||||
return {
|
||||
'id': 'fake',
|
||||
'host': 'host001',
|
||||
@ -45,11 +47,20 @@ def fake_volume_get(*args, **kwargs):
|
||||
'volume_type_id': None,
|
||||
'snapshot_id': None,
|
||||
'project_id': 'fake',
|
||||
'migration_status': None,
|
||||
'_name_id': 'fake2',
|
||||
'attach_status': 'detached',
|
||||
}
|
||||
|
||||
|
||||
def fake_volume_api_get(*args, **kwargs):
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
db_volume = fake_db_volume_get()
|
||||
return fake_volume.fake_volume_obj(ctx, **db_volume)
|
||||
|
||||
|
||||
def fake_volume_get_all(*args, **kwargs):
|
||||
return [fake_volume_get()]
|
||||
return objects.VolumeList(objects=[fake_volume_api_get()])
|
||||
|
||||
|
||||
fake_image_metadata = {
|
||||
@ -90,13 +101,12 @@ class VolumeImageMetadataTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(VolumeImageMetadataTest, self).setUp()
|
||||
self.stubs.Set(volume.API, 'get', fake_volume_get)
|
||||
self.stubs.Set(volume.API, 'get', fake_volume_api_get)
|
||||
self.stubs.Set(volume.API, 'get_all', fake_volume_get_all)
|
||||
self.stubs.Set(volume.API, 'get_volume_image_metadata',
|
||||
fake_get_volume_image_metadata)
|
||||
self.stubs.Set(volume.API, 'get_volumes_image_metadata',
|
||||
fake_get_volumes_image_metadata)
|
||||
self.stubs.Set(db, 'volume_get', fake_volume_get)
|
||||
self.UUID = uuid.uuid4()
|
||||
self.controller = (volume_image_metadata.
|
||||
VolumeImageMetadataController())
|
||||
|
@ -20,6 +20,7 @@ from cinder import context
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_volume
|
||||
|
||||
|
||||
def app():
|
||||
@ -82,21 +83,20 @@ def api_manage(*args, **kwargs):
|
||||
Note that we don't try to replicate any passed-in information (e.g. name,
|
||||
volume type) in the returned structure.
|
||||
"""
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
vol = {
|
||||
'status': 'creating',
|
||||
'display_name': 'fake_name',
|
||||
'availability_zone': 'nova',
|
||||
'tenant_id': 'fake',
|
||||
'created_at': 'DONTCARE',
|
||||
'id': 'ffffffff-0000-ffff-0000-ffffffffffff',
|
||||
'volume_type': None,
|
||||
'snapshot_id': None,
|
||||
'user_id': 'fake',
|
||||
'launched_at': 'DONTCARE',
|
||||
'size': 0,
|
||||
'attach_status': 'detached',
|
||||
'volume_type_id': None}
|
||||
return vol
|
||||
return fake_volume.fake_volume_obj(ctx, **vol)
|
||||
|
||||
|
||||
@mock.patch('cinder.db.service_get_by_host_and_topic',
|
||||
|
@ -20,12 +20,14 @@ from oslo_utils import timeutils
|
||||
import webob
|
||||
|
||||
from cinder import context
|
||||
from cinder import objects
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
|
||||
|
||||
def fake_volume_get(*args, **kwargs):
|
||||
def fake_db_volume_get(*args, **kwargs):
|
||||
return {
|
||||
'id': 'fake',
|
||||
'host': 'host001',
|
||||
@ -33,7 +35,7 @@ def fake_volume_get(*args, **kwargs):
|
||||
'size': 5,
|
||||
'availability_zone': 'somewhere',
|
||||
'created_at': timeutils.utcnow(),
|
||||
'attach_status': None,
|
||||
'attach_status': 'detached',
|
||||
'display_name': 'anothervolume',
|
||||
'display_description': 'Just another volume!',
|
||||
'volume_type_id': None,
|
||||
@ -44,8 +46,14 @@ def fake_volume_get(*args, **kwargs):
|
||||
}
|
||||
|
||||
|
||||
def fake_volume_api_get(*args, **kwargs):
|
||||
ctx = context.RequestContext('admin', 'fake', True)
|
||||
db_volume = fake_db_volume_get()
|
||||
return fake_volume.fake_volume_obj(ctx, **db_volume)
|
||||
|
||||
|
||||
def fake_volume_get_all(*args, **kwargs):
|
||||
return [fake_volume_get()]
|
||||
return objects.VolumeList(objects=[fake_volume_api_get()])
|
||||
|
||||
|
||||
def app():
|
||||
@ -60,7 +68,7 @@ class VolumeMigStatusAttributeTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(VolumeMigStatusAttributeTest, self).setUp()
|
||||
self.stubs.Set(volume.API, 'get', fake_volume_get)
|
||||
self.stubs.Set(volume.API, 'get', fake_volume_api_get)
|
||||
self.stubs.Set(volume.API, 'get_all', fake_volume_get_all)
|
||||
self.UUID = uuid.uuid4()
|
||||
|
||||
|
@ -16,12 +16,13 @@ import json
|
||||
import uuid
|
||||
|
||||
from lxml import etree
|
||||
from oslo_utils import timeutils
|
||||
import webob
|
||||
|
||||
from cinder import context
|
||||
from cinder import objects
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
|
||||
|
||||
@ -29,26 +30,16 @@ PROJECT_ID = '88fd1da4-f464-4a87-9ce5-26f2f40743b9'
|
||||
|
||||
|
||||
def fake_volume_get(*args, **kwargs):
|
||||
return {
|
||||
ctx = context.RequestContext('non-admin', 'fake', False)
|
||||
vol = {
|
||||
'id': 'fake',
|
||||
'host': 'host001',
|
||||
'status': 'available',
|
||||
'size': 5,
|
||||
'availability_zone': 'somewhere',
|
||||
'created_at': timeutils.utcnow(),
|
||||
'attach_status': None,
|
||||
'display_name': 'anothervolume',
|
||||
'display_description': 'Just another volume!',
|
||||
'volume_type_id': None,
|
||||
'snapshot_id': None,
|
||||
'project_id': PROJECT_ID,
|
||||
'migration_status': None,
|
||||
'_name_id': 'fake2',
|
||||
}
|
||||
return fake_volume.fake_volume_obj(ctx, **vol)
|
||||
|
||||
|
||||
def fake_volume_get_all(*args, **kwargs):
|
||||
return [fake_volume_get()]
|
||||
return objects.VolumeList(objects=[fake_volume_get()])
|
||||
|
||||
|
||||
def app():
|
||||
|
@ -63,6 +63,7 @@ class VolumeTransferAPITestCase(test.TestCase):
|
||||
vol['display_name'] = display_name
|
||||
vol['display_description'] = display_description
|
||||
vol['attach_status'] = status
|
||||
vol['availability_zone'] = 'fake_zone'
|
||||
return db.volume_create(context.get_admin_context(), vol)['id']
|
||||
|
||||
def test_show_transfer(self):
|
||||
|
@ -21,6 +21,7 @@ from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
|
||||
|
||||
# This list of fake volumes is used by our tests. Each is configured in a
|
||||
@ -78,7 +79,7 @@ def api_get(self, context, volume_id):
|
||||
if not vol:
|
||||
raise exception.VolumeNotFound(volume_id)
|
||||
|
||||
return vol
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
|
||||
def db_snapshot_get_all_for_volume(context, volume_id):
|
||||
|
@ -30,6 +30,7 @@ from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -87,17 +88,18 @@ def return_snapshot(context, snapshot_id):
|
||||
'metadata': {}}
|
||||
|
||||
|
||||
def return_volume(context, volume_id):
|
||||
return {'id': 'fake-vol-id',
|
||||
'size': 100,
|
||||
'name': 'fake',
|
||||
'host': 'fake-host',
|
||||
'status': 'available',
|
||||
'encryption_key_id': None,
|
||||
'volume_type_id': None,
|
||||
'migration_status': None,
|
||||
'metadata': {},
|
||||
'project_id': context.project_id}
|
||||
def stub_get(context, volume_id, *args, **kwargs):
|
||||
vol = {'id': volume_id,
|
||||
'size': 100,
|
||||
'name': 'fake',
|
||||
'host': 'fake-host',
|
||||
'status': 'available',
|
||||
'encryption_key_id': None,
|
||||
'volume_type_id': None,
|
||||
'migration_status': None,
|
||||
'availability_zone': 'zone1:host1',
|
||||
'attach_status': 'detached'}
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
|
||||
def return_snapshot_nonexistent(context, snapshot_id):
|
||||
@ -113,7 +115,7 @@ class SnapshotMetaDataTest(test.TestCase):
|
||||
def setUp(self):
|
||||
super(SnapshotMetaDataTest, self).setUp()
|
||||
self.volume_api = cinder.volume.api.API()
|
||||
self.stubs.Set(cinder.db, 'volume_get', return_volume)
|
||||
self.stubs.Set(volume.API, 'get', stub_get)
|
||||
self.stubs.Set(cinder.db, 'snapshot_get', return_snapshot)
|
||||
|
||||
self.stubs.Set(self.volume_api, 'update_snapshot_metadata',
|
||||
|
@ -28,6 +28,8 @@ from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit.api.v1 import stubs
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -54,9 +56,6 @@ def return_create_volume_metadata_insensitive(context, snapshot_id,
|
||||
|
||||
|
||||
def return_volume_metadata(context, volume_id):
|
||||
if not isinstance(volume_id, str) or not len(volume_id) == 36:
|
||||
msg = 'id %s must be a uuid in return volume metadata' % volume_id
|
||||
raise Exception(msg)
|
||||
return stub_volume_metadata()
|
||||
|
||||
|
||||
@ -108,11 +107,18 @@ def stub_max_volume_metadata():
|
||||
return metadata
|
||||
|
||||
|
||||
def return_volume(context, volume_id):
|
||||
return {'id': '0cc3346e-9fef-4445-abe6-5d2b2690ec64',
|
||||
'name': 'fake',
|
||||
'metadata': {},
|
||||
'project_id': context.project_id}
|
||||
def get_volume(*args, **kwargs):
|
||||
vol = {'id': args[1],
|
||||
'size': 100,
|
||||
'name': 'fake',
|
||||
'host': 'fake-host',
|
||||
'status': 'available',
|
||||
'encryption_key_id': None,
|
||||
'volume_type_id': None,
|
||||
'migration_status': None,
|
||||
'availability_zone': 'zone1:host1',
|
||||
'attach_status': 'detached'}
|
||||
return fake_volume.fake_volume_obj(args[0], **vol)
|
||||
|
||||
|
||||
def return_volume_nonexistent(*args, **kwargs):
|
||||
@ -128,7 +134,7 @@ class volumeMetaDataTest(test.TestCase):
|
||||
def setUp(self):
|
||||
super(volumeMetaDataTest, self).setUp()
|
||||
self.volume_api = cinder.volume.api.API()
|
||||
self.stubs.Set(cinder.db, 'volume_get', return_volume)
|
||||
self.stubs.Set(volume.API, 'get', get_volume)
|
||||
self.stubs.Set(cinder.db, 'volume_metadata_get',
|
||||
return_volume_metadata)
|
||||
self.stubs.Set(cinder.db, 'service_get_all_by_topic',
|
||||
@ -337,8 +343,7 @@ class volumeMetaDataTest(test.TestCase):
|
||||
req, self.req_id, body)
|
||||
|
||||
def test_create_nonexistent_volume(self):
|
||||
self.stubs.Set(cinder.db, 'volume_get',
|
||||
return_volume_nonexistent)
|
||||
self.stubs.Set(volume.API, 'get', return_volume_nonexistent)
|
||||
self.stubs.Set(cinder.db, 'volume_metadata_get',
|
||||
return_volume_metadata)
|
||||
self.stubs.Set(cinder.db, 'volume_metadata_update',
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import iso8601
|
||||
|
||||
from lxml import etree
|
||||
import mock
|
||||
@ -30,6 +31,7 @@ from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit.api.v2 import stubs
|
||||
from cinder.tests.unit import fake_notifier
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit.image import fake as fake_image
|
||||
from cinder.volume import api as volume_api
|
||||
|
||||
@ -70,8 +72,8 @@ class VolumeApiTest(test.TestCase):
|
||||
self.stubs.Set(volume_api.API, 'delete', stubs.stub_volume_delete)
|
||||
|
||||
def test_volume_create(self):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_api_create)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
vol = {"size": 100,
|
||||
"display_name": "Volume Test Name",
|
||||
@ -92,8 +94,9 @@ class VolumeApiTest(test.TestCase):
|
||||
'source_volid': None,
|
||||
'metadata': {},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 100,
|
||||
'encrypted': False}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
@ -157,9 +160,9 @@ class VolumeApiTest(test.TestCase):
|
||||
req, body)
|
||||
|
||||
def test_volume_create_with_image_id(self):
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_api_create)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
|
||||
self.ext_mgr.extensions = {'os-image-create': 'fake'}
|
||||
test_id = "c905cedb-7281-47e4-8a62-f26bc5fc4c77"
|
||||
vol = {"size": '1',
|
||||
@ -181,9 +184,10 @@ class VolumeApiTest(test.TestCase):
|
||||
'source_volid': None,
|
||||
'metadata': {},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'size': '1'}}
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}}
|
||||
body = {"volume": vol}
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes')
|
||||
res_dict = self.controller.create(req, body)
|
||||
@ -237,9 +241,12 @@ class VolumeApiTest(test.TestCase):
|
||||
@mock.patch.object(db, 'volume_admin_metadata_get',
|
||||
return_value={'attached_mode': 'rw',
|
||||
'readonly': 'False'})
|
||||
@mock.patch.object(db, 'volume_get', side_effect=stubs.stub_volume_get_db)
|
||||
@mock.patch.object(db, 'volume_type_get',
|
||||
side_effect=stubs.stub_volume_type_get)
|
||||
@mock.patch.object(volume_api.API, 'get',
|
||||
side_effect=stubs.stub_volume_api_get, autospec=True)
|
||||
@mock.patch.object(volume_api.API, 'update',
|
||||
side_effect=stubs.stub_volume_update)
|
||||
side_effect=stubs.stub_volume_update, autospec=True)
|
||||
def test_volume_update(self, *args):
|
||||
updates = {
|
||||
"display_name": "Updated Test Name",
|
||||
@ -263,7 +270,8 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
self.assertEqual(2, len(self.notifier.notifications))
|
||||
@ -272,9 +280,12 @@ class VolumeApiTest(test.TestCase):
|
||||
return_value={"qos_max_iops": 2000,
|
||||
"readonly": "False",
|
||||
"attached_mode": "rw"})
|
||||
@mock.patch.object(db, 'volume_get', side_effect=stubs.stub_volume_get_db)
|
||||
@mock.patch.object(db, 'volume_type_get',
|
||||
side_effect=stubs.stub_volume_type_get)
|
||||
@mock.patch.object(volume_api.API, 'get',
|
||||
side_effect=stubs.stub_volume_api_get, autospec=True)
|
||||
@mock.patch.object(volume_api.API, 'update',
|
||||
side_effect=stubs.stub_volume_update)
|
||||
side_effect=stubs.stub_volume_update, autospec=True)
|
||||
def test_volume_update_metadata(self, *args):
|
||||
updates = {
|
||||
"metadata": {"qos_max_iops": 2000}
|
||||
@ -295,11 +306,12 @@ class VolumeApiTest(test.TestCase):
|
||||
'volume_type': 'vol_type_name',
|
||||
'snapshot_id': None,
|
||||
'source_volid': None,
|
||||
'metadata': {"qos_max_iops": 2000,
|
||||
'metadata': {"qos_max_iops": '2000',
|
||||
"readonly": "False",
|
||||
"attached_mode": "rw"},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1
|
||||
}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
@ -359,7 +371,8 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'key': 'value',
|
||||
'readonly': 'True'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
self.assertEqual(2, len(self.notifier.notifications))
|
||||
@ -397,7 +410,8 @@ class VolumeApiTest(test.TestCase):
|
||||
stubs_volume_admin_metadata_get)
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
self.stubs.Set(volume_api.API, 'get_all',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
stubs.stub_volume_api_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes')
|
||||
res_dict = self.controller.index(req)
|
||||
@ -415,8 +429,9 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}]}
|
||||
self.assertEqual(expected, res_dict)
|
||||
# Finally test that we cached the returned volumes
|
||||
@ -462,15 +477,19 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'key': 'value',
|
||||
'readonly': 'True'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}]}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
def test_volume_list_detail(self):
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
@mock.patch.object(db, 'volume_admin_metadata_get',
|
||||
return_value={'attached_mode': 'rw',
|
||||
'readonly': 'False'})
|
||||
def test_volume_list_detail(self, *args):
|
||||
self.stubs.Set(volume_api.API, 'get_all',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
stubs.stub_volume_api_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/detail')
|
||||
res_dict = self.controller.index(req)
|
||||
@ -488,8 +507,9 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}]}
|
||||
self.assertEqual(expected, res_dict)
|
||||
# Finally test that we cached the returned volumes
|
||||
@ -535,15 +555,19 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'key': 'value',
|
||||
'readonly': 'True'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}]}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
@mock.patch.object(db, 'volume_admin_metadata_get',
|
||||
return_value={'attached_mode': 'rw',
|
||||
'readonly': 'False'})
|
||||
@mock.patch.object(db, 'volume_get', side_effect=stubs.stub_volume_get_db)
|
||||
@mock.patch.object(volume_api.API, 'get',
|
||||
side_effect=stubs.stub_volume_api_get, autospec=True)
|
||||
@mock.patch.object(db, 'volume_type_get',
|
||||
side_effect=stubs.stub_volume_type_get, autospec=True)
|
||||
def test_volume_show(self, *args):
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/1')
|
||||
res_dict = self.controller.show(req, '1')
|
||||
@ -561,8 +585,9 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
# Finally test that we cached the returned volume
|
||||
@ -570,9 +595,11 @@ class VolumeApiTest(test.TestCase):
|
||||
|
||||
def test_volume_show_no_attachments(self):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, attach_status='detached')
|
||||
vol = stubs.stub_volume(volume_id, attach_status='detached')
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/1')
|
||||
res_dict = self.controller.show(req, '1')
|
||||
@ -589,17 +616,20 @@ class VolumeApiTest(test.TestCase):
|
||||
'source_volid': None,
|
||||
'metadata': {'readonly': 'False'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
def test_volume_show_bootable(self):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return (stubs.stub_volume(volume_id,
|
||||
volume_glance_metadata=dict(foo='bar')))
|
||||
vol = (stubs.stub_volume(volume_id,
|
||||
volume_glance_metadata=dict(foo='bar')))
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/1')
|
||||
res_dict = self.controller.show(req, '1')
|
||||
@ -617,8 +647,9 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
@ -648,6 +679,7 @@ class VolumeApiTest(test.TestCase):
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stub_volume_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/detail?limit=2\
|
||||
&offset=1',
|
||||
@ -655,7 +687,7 @@ class VolumeApiTest(test.TestCase):
|
||||
res_dict = self.controller.index(req)
|
||||
volumes = res_dict['volumes']
|
||||
self.assertEqual(1, len(volumes))
|
||||
self.assertEqual(2, volumes[0]['id'])
|
||||
self.assertEqual('2', volumes[0]['id'])
|
||||
|
||||
# admin case
|
||||
volume_detail_limit_offset(is_admin=True)
|
||||
@ -702,26 +734,27 @@ class VolumeApiTest(test.TestCase):
|
||||
'metadata': {'key': 'value',
|
||||
'readonly': 'True'},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1900, 1, 1,
|
||||
1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'size': 1}}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
def test_volume_show_with_encrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
vol = stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
self.assertEqual(True, res_dict['volume']['encrypted'])
|
||||
|
||||
def test_volume_show_with_unencrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id=None)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_api_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
@ -746,6 +779,7 @@ class VolumeApiTest(test.TestCase):
|
||||
def test_admin_list_volumes_limited_to_project(self):
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/volumes',
|
||||
use_admin_context=True)
|
||||
@ -755,6 +789,7 @@ class VolumeApiTest(test.TestCase):
|
||||
self.assertEqual(1, len(res['volumes']))
|
||||
|
||||
def test_admin_list_volumes_all_tenants(self):
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/volumes?all_tenants=1',
|
||||
use_admin_context=True)
|
||||
res = self.controller.index(req)
|
||||
@ -765,6 +800,7 @@ class VolumeApiTest(test.TestCase):
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/volumes?all_tenants=1')
|
||||
res = self.controller.index(req)
|
||||
@ -775,6 +811,7 @@ class VolumeApiTest(test.TestCase):
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/volumes')
|
||||
res = self.controller.index(req)
|
||||
|
@ -14,8 +14,11 @@
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import iso8601
|
||||
|
||||
from cinder import exception as exc
|
||||
from cinder import objects
|
||||
from cinder.tests.unit import fake_volume
|
||||
|
||||
|
||||
FAKE_UUID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||
@ -49,8 +52,10 @@ def stub_volume(id, **kwargs):
|
||||
'name': 'vol name',
|
||||
'display_name': DEFAULT_VOL_NAME,
|
||||
'display_description': DEFAULT_VOL_DESCRIPTION,
|
||||
'updated_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'updated_at': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'snapshot_id': None,
|
||||
'source_volid': None,
|
||||
'volume_type_id': '3e196c20-3c06-11e2-81c1-0800200c9a66',
|
||||
@ -58,7 +63,8 @@ def stub_volume(id, **kwargs):
|
||||
'volume_admin_metadata': [{'key': 'attached_mode', 'value': 'rw'},
|
||||
{'key': 'readonly', 'value': 'False'}],
|
||||
'bootable': False,
|
||||
'launched_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'launched_at': datetime.datetime(1900, 1, 1, 1, 1, 1,
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
'volume_type': {'name': DEFAULT_VOL_TYPE},
|
||||
'replication_status': 'disabled',
|
||||
'replication_extended_status': None,
|
||||
@ -84,6 +90,7 @@ def stub_volume_create(self, context, size, name, description, snapshot=None,
|
||||
source_volume = param.get('source_volume') or {}
|
||||
vol['source_volid'] = source_volume.get('id')
|
||||
vol['bootable'] = False
|
||||
vol['volume_attachment'] = []
|
||||
try:
|
||||
vol['snapshot_id'] = snapshot['id']
|
||||
except (KeyError, TypeError):
|
||||
@ -92,6 +99,11 @@ def stub_volume_create(self, context, size, name, description, snapshot=None,
|
||||
return vol
|
||||
|
||||
|
||||
def stub_volume_api_create(self, context, *args, **kwargs):
|
||||
vol = stub_volume_create(self, context, *args, **kwargs)
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
|
||||
def stub_image_service_detail(self, context, **kwargs):
|
||||
filters = kwargs.get('filters', {'name': ''})
|
||||
if filters['name'] == "Fedora-x86_64-20-20140618-sda":
|
||||
@ -146,6 +158,11 @@ def stub_volume_get_db(context, volume_id):
|
||||
return volume
|
||||
|
||||
|
||||
def stub_volume_api_get(self, context, volume_id, viewable_admin_meta=False):
|
||||
vol = stub_volume(volume_id)
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
|
||||
def stub_volume_get_all(context, search_opts=None, marker=None, limit=None,
|
||||
sort_keys=None, sort_dirs=None, filters=None,
|
||||
viewable_admin_meta=False, offset=None):
|
||||
@ -162,6 +179,18 @@ def stub_volume_get_all_by_project(self, context, marker, limit,
|
||||
return [stub_volume_get(self, context, '1', viewable_admin_meta=True)]
|
||||
|
||||
|
||||
def stub_volume_api_get_all_by_project(self, context, marker, limit,
|
||||
sort_keys=None, sort_dirs=None,
|
||||
filters=None,
|
||||
viewable_admin_meta=False,
|
||||
offset=None):
|
||||
filters = filters or {}
|
||||
vol = stub_volume_get(self, context, '1',
|
||||
viewable_admin_meta=viewable_admin_meta)
|
||||
vol_obj = fake_volume.fake_volume_obj(context, **vol)
|
||||
return objects.VolumeList(objects=[vol_obj])
|
||||
|
||||
|
||||
def stub_snapshot(id, **kwargs):
|
||||
snapshot = {'id': id,
|
||||
'volume_id': 12,
|
||||
@ -207,3 +236,24 @@ def stub_snapshot_get(self, context, snapshot_id):
|
||||
|
||||
def stub_consistencygroup_get_notfound(self, context, cg_id):
|
||||
raise exc.ConsistencyGroupNotFound(consistencygroup_id=cg_id)
|
||||
|
||||
|
||||
def stub_volume_type_get(context, id, *args, **kwargs):
|
||||
return {'id': id,
|
||||
'name': 'vol_type_name',
|
||||
'description': 'A fake volume type',
|
||||
'is_public': True,
|
||||
'projects': [],
|
||||
'extra_specs': {},
|
||||
'created_at': None,
|
||||
'deleted_at': None,
|
||||
'updated_at': None,
|
||||
'deleted': False}
|
||||
|
||||
|
||||
def stub_volume_admin_metadata_get(context, volume_id, **kwargs):
|
||||
admin_meta = {'attached_mode': 'rw', 'readonly': 'False'}
|
||||
if kwargs.get('attach_status') == 'detached':
|
||||
del admin_meta['attached_mode']
|
||||
|
||||
return admin_meta
|
||||
|
@ -30,6 +30,7 @@ from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -87,17 +88,19 @@ def return_snapshot(context, snapshot_id):
|
||||
'metadata': {}}
|
||||
|
||||
|
||||
def return_volume(context, volume_id):
|
||||
return {'id': 'fake-vol-id',
|
||||
'size': 100,
|
||||
'name': 'fake',
|
||||
'host': 'fake-host',
|
||||
'status': 'available',
|
||||
'encryption_key_id': None,
|
||||
'volume_type_id': None,
|
||||
'migration_status': None,
|
||||
'metadata': {},
|
||||
'project_id': context.project_id}
|
||||
def stub_get(context, *args, **kwargs):
|
||||
vol = {'id': 'fake-vol-id',
|
||||
'size': 100,
|
||||
'name': 'fake',
|
||||
'host': 'fake-host',
|
||||
'status': 'available',
|
||||
'encryption_key_id': None,
|
||||
'volume_type_id': None,
|
||||
'migration_status': None,
|
||||
'availability_zone': 'fake-zone',
|
||||
'attach_status': 'detached',
|
||||
'metadata': {}}
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
|
||||
def return_snapshot_nonexistent(context, snapshot_id):
|
||||
@ -113,7 +116,7 @@ class SnapshotMetaDataTest(test.TestCase):
|
||||
def setUp(self):
|
||||
super(SnapshotMetaDataTest, self).setUp()
|
||||
self.volume_api = cinder.volume.api.API()
|
||||
self.stubs.Set(cinder.db, 'volume_get', return_volume)
|
||||
self.stubs.Set(volume.API, 'get', stub_get)
|
||||
self.stubs.Set(cinder.db, 'snapshot_get', return_snapshot)
|
||||
|
||||
self.stubs.Set(self.volume_api, 'update_snapshot_metadata',
|
||||
|
@ -28,6 +28,8 @@ from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit.api.v2 import stubs
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import volume
|
||||
from cinder.volume import api as volume_api
|
||||
|
||||
|
||||
@ -55,9 +57,6 @@ def return_create_volume_metadata_insensitive(context, snapshot_id,
|
||||
|
||||
|
||||
def return_volume_metadata(context, volume_id):
|
||||
if not isinstance(volume_id, str) or not len(volume_id) == 36:
|
||||
msg = 'id %s must be a uuid in return volume metadata' % volume_id
|
||||
raise Exception(msg)
|
||||
return stub_volume_metadata()
|
||||
|
||||
|
||||
@ -109,11 +108,10 @@ def stub_max_volume_metadata():
|
||||
return metadata
|
||||
|
||||
|
||||
def return_volume(context, volume_id):
|
||||
return {'id': '0cc3346e-9fef-4445-abe6-5d2b2690ec64',
|
||||
'name': 'fake',
|
||||
'metadata': {},
|
||||
'project_id': context.project_id}
|
||||
def get_volume(*args, **kwargs):
|
||||
vol = {'name': 'fake',
|
||||
'metadata': {}}
|
||||
return fake_volume.fake_volume_obj(args[0], **vol)
|
||||
|
||||
|
||||
def return_volume_nonexistent(*args, **kwargs):
|
||||
@ -129,7 +127,7 @@ class volumeMetaDataTest(test.TestCase):
|
||||
def setUp(self):
|
||||
super(volumeMetaDataTest, self).setUp()
|
||||
self.volume_api = volume_api.API()
|
||||
self.stubs.Set(db, 'volume_get', return_volume)
|
||||
self.stubs.Set(volume.API, 'get', get_volume)
|
||||
self.stubs.Set(db, 'volume_metadata_get',
|
||||
return_volume_metadata)
|
||||
self.stubs.Set(db, 'service_get_all_by_topic',
|
||||
@ -380,8 +378,7 @@ class volumeMetaDataTest(test.TestCase):
|
||||
req, self.req_id, body)
|
||||
|
||||
def test_create_nonexistent_volume(self):
|
||||
self.stubs.Set(db, 'volume_get',
|
||||
return_volume_nonexistent)
|
||||
self.stubs.Set(volume.API, 'get', return_volume_nonexistent)
|
||||
self.stubs.Set(db, 'volume_metadata_get',
|
||||
return_volume_metadata)
|
||||
self.stubs.Set(db, 'volume_metadata_update',
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
|
||||
import datetime
|
||||
import functools
|
||||
import iso8601
|
||||
|
||||
from lxml import etree
|
||||
import mock
|
||||
@ -33,10 +33,12 @@ from cinder import consistencygroup as consistencygroupAPI
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
from cinder import objects
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
from cinder.tests.unit.api.v2 import stubs
|
||||
from cinder.tests.unit import fake_notifier
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit.image import fake as fake_image
|
||||
from cinder.tests.unit import utils
|
||||
from cinder.volume import api as volume_api
|
||||
@ -69,7 +71,8 @@ class VolumeApiTest(test.TestCase):
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_create(self, mock_validate):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_api_create)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
vol = self._vol_in_request_body()
|
||||
body = {"volume": vol}
|
||||
@ -111,10 +114,13 @@ class VolumeApiTest(test.TestCase):
|
||||
volume_id = res_dict['volume']['id']
|
||||
self.assertEqual(1, len(res_dict))
|
||||
|
||||
vol_db = stubs.stub_volume(volume_id, volume_type={'name': vol_type})
|
||||
vol_obj = fake_volume.fake_volume_obj(context.get_admin_context(),
|
||||
**vol_db)
|
||||
self.stubs.Set(volume_api.API, 'get_all',
|
||||
lambda *args, **kwargs:
|
||||
[stubs.stub_volume(volume_id,
|
||||
volume_type={'name': vol_type})])
|
||||
objects.VolumeList(objects=[vol_obj]))
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/detail')
|
||||
res_dict = self.controller.detail(req)
|
||||
self.assertTrue(mock_validate.called)
|
||||
@ -170,8 +176,10 @@ class VolumeApiTest(test.TestCase):
|
||||
'availability_zone': availability_zone,
|
||||
'bootable': 'false',
|
||||
'consistencygroup_id': consistencygroup_id,
|
||||
'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'updated_at': datetime.datetime(1900, 1, 1, 1, 1, 1),
|
||||
'created_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1, tzinfo=iso8601.iso8601.Utc()),
|
||||
'updated_at': datetime.datetime(
|
||||
1900, 1, 1, 1, 1, 1, tzinfo=iso8601.iso8601.Utc()),
|
||||
'description': description,
|
||||
'id': stubs.DEFAULT_VOL_ID,
|
||||
'links':
|
||||
@ -209,12 +217,14 @@ class VolumeApiTest(test.TestCase):
|
||||
'multiattach': False,
|
||||
}
|
||||
|
||||
@mock.patch.object(db, 'volume_type_get', autospec=True)
|
||||
@mock.patch.object(volume_api.API, 'get_snapshot', autospec=True)
|
||||
@mock.patch.object(volume_api.API, 'create', autospec=True)
|
||||
def test_volume_creation_from_snapshot(self, create, get_snapshot):
|
||||
|
||||
create.side_effect = stubs.stub_volume_create
|
||||
def test_volume_creation_from_snapshot(self, create, get_snapshot,
|
||||
volume_type_get):
|
||||
create.side_effect = stubs.stub_volume_api_create
|
||||
get_snapshot.side_effect = stubs.stub_snapshot_get
|
||||
volume_type_get.side_effect = stubs.stub_volume_type_get
|
||||
|
||||
snapshot_id = stubs.TEST_SNAPSHOT_UUID
|
||||
vol = self._vol_in_request_body(snapshot_id=stubs.TEST_SNAPSHOT_UUID)
|
||||
@ -252,13 +262,14 @@ class VolumeApiTest(test.TestCase):
|
||||
get_snapshot.assert_called_once_with(self.controller.volume_api,
|
||||
context, snapshot_id)
|
||||
|
||||
@mock.patch.object(db, 'volume_type_get', autospec=True)
|
||||
@mock.patch.object(volume_api.API, 'get_volume', autospec=True)
|
||||
@mock.patch.object(volume_api.API, 'create', autospec=True)
|
||||
def test_volume_creation_from_source_volume(self, create, get_volume):
|
||||
|
||||
get_volume.side_effect = functools.partial(stubs.stub_volume_get,
|
||||
viewable_admin_meta=True)
|
||||
create.side_effect = stubs.stub_volume_create
|
||||
def test_volume_creation_from_source_volume(self, create, get_volume,
|
||||
volume_type_get):
|
||||
get_volume.side_effect = stubs.stub_volume_api_get
|
||||
create.side_effect = stubs.stub_volume_api_create
|
||||
volume_type_get.side_effect = stubs.stub_volume_type_get
|
||||
|
||||
source_volid = '2f49aa3a-6aae-488d-8b99-a43271605af6'
|
||||
vol = self._vol_in_request_body(source_volid=source_volid)
|
||||
@ -273,8 +284,10 @@ class VolumeApiTest(test.TestCase):
|
||||
get_volume.assert_called_once_with(self.controller.volume_api,
|
||||
context, source_volid)
|
||||
|
||||
db_vol = stubs.stub_volume(source_volid)
|
||||
vol_obj = fake_volume.fake_volume_obj(context, **db_vol)
|
||||
kwargs = self._expected_volume_api_create_kwargs(
|
||||
source_volume=stubs.stub_volume(source_volid))
|
||||
source_volume=vol_obj)
|
||||
create.assert_called_once_with(self.controller.volume_api, context,
|
||||
vol['size'], stubs.DEFAULT_VOL_NAME,
|
||||
stubs.DEFAULT_VOL_DESCRIPTION, **kwargs)
|
||||
@ -372,8 +385,8 @@ class VolumeApiTest(test.TestCase):
|
||||
@mock.patch(
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_create_with_image_ref(self, mock_validate):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_api_create)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
self.ext_mgr.extensions = {'os-image-create': 'fake'}
|
||||
vol = self._vol_in_request_body(
|
||||
@ -425,8 +438,8 @@ class VolumeApiTest(test.TestCase):
|
||||
@mock.patch(
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_create_with_image_id(self, mock_validate):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_api_create)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
self.ext_mgr.extensions = {'os-image-create': 'fake'}
|
||||
vol = self._vol_in_request_body(
|
||||
@ -478,8 +491,8 @@ class VolumeApiTest(test.TestCase):
|
||||
@mock.patch(
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_create_with_image_name(self, mock_validate):
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_create)
|
||||
self.stubs.Set(volume_api.API, "create", stubs.stub_volume_api_create)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
self.stubs.Set(fake_image._FakeImageService,
|
||||
"detail",
|
||||
stubs.stub_image_service_detail)
|
||||
@ -534,8 +547,9 @@ class VolumeApiTest(test.TestCase):
|
||||
@mock.patch(
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_update(self, mock_validate):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_api_get)
|
||||
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
updates = {
|
||||
"name": "Updated Test Name",
|
||||
@ -554,8 +568,9 @@ class VolumeApiTest(test.TestCase):
|
||||
@mock.patch(
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_update_deprecation(self, mock_validate):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_api_get)
|
||||
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
updates = {
|
||||
"display_name": "Updated Test Name",
|
||||
@ -577,8 +592,9 @@ class VolumeApiTest(test.TestCase):
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_update_deprecation_key_priority(self, mock_validate):
|
||||
"""Test current update keys have priority over deprecated keys."""
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_api_get)
|
||||
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
updates = {
|
||||
"name": "New Name",
|
||||
@ -601,8 +617,9 @@ class VolumeApiTest(test.TestCase):
|
||||
@mock.patch(
|
||||
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
|
||||
def test_volume_update_metadata(self, mock_validate):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_api_get)
|
||||
self.stubs.Set(volume_api.API, "update", stubs.stub_volume_update)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
updates = {
|
||||
"metadata": {"qos_max_iops": 2000}
|
||||
@ -614,7 +631,7 @@ class VolumeApiTest(test.TestCase):
|
||||
expected = self._expected_vol_from_controller(
|
||||
availability_zone=stubs.DEFAULT_AZ,
|
||||
metadata={'attached_mode': 'rw', 'readonly': 'False',
|
||||
'qos_max_iops': 2000})
|
||||
'qos_max_iops': '2000'})
|
||||
self.assertEqual(expected, res_dict)
|
||||
self.assertEqual(2, len(self.notifier.notifications))
|
||||
self.assertTrue(mock_validate.called)
|
||||
@ -659,11 +676,13 @@ class VolumeApiTest(test.TestCase):
|
||||
'server_id': stubs.FAKE_UUID,
|
||||
'host_name': None,
|
||||
'device': '/',
|
||||
'attached_at': attach_tmp['attach_time'],
|
||||
'attached_at': attach_tmp['attach_time'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
}],
|
||||
metadata={'key': 'value', 'readonly': 'True'},
|
||||
with_migration_status=True)
|
||||
expected['volume']['updated_at'] = volume_tmp['updated_at']
|
||||
expected['volume']['updated_at'] = volume_tmp['updated_at'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc())
|
||||
self.assertEqual(expected, res_dict)
|
||||
self.assertEqual(2, len(self.notifier.notifications))
|
||||
self.assertTrue(mock_validate.called)
|
||||
@ -697,8 +716,8 @@ class VolumeApiTest(test.TestCase):
|
||||
|
||||
def test_volume_list_summary(self):
|
||||
self.stubs.Set(volume_api.API, 'get_all',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
stubs.stub_volume_api_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes')
|
||||
res_dict = self.controller.index(req)
|
||||
@ -727,8 +746,8 @@ class VolumeApiTest(test.TestCase):
|
||||
|
||||
def test_volume_list_detail(self):
|
||||
self.stubs.Set(volume_api.API, 'get_all',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
stubs.stub_volume_api_get_all_by_project)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/detail')
|
||||
res_dict = self.controller.detail(req)
|
||||
@ -772,11 +791,13 @@ class VolumeApiTest(test.TestCase):
|
||||
'host_name': None,
|
||||
'id': '1',
|
||||
'volume_id': stubs.DEFAULT_VOL_ID,
|
||||
'attached_at': attach_tmp['attach_time'],
|
||||
'attached_at': attach_tmp['attach_time'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
}],
|
||||
metadata={'key': 'value', 'readonly': 'True'},
|
||||
with_migration_status=True)
|
||||
exp_vol['volume']['updated_at'] = volume_tmp['updated_at']
|
||||
exp_vol['volume']['updated_at'] = volume_tmp['updated_at'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc())
|
||||
expected = {'volumes': [exp_vol['volume']]}
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
@ -798,8 +819,8 @@ class VolumeApiTest(test.TestCase):
|
||||
res_dict = self.controller.index(req)
|
||||
volumes = res_dict['volumes']
|
||||
self.assertEqual(2, len(volumes))
|
||||
self.assertEqual(1, volumes[0]['id'])
|
||||
self.assertEqual(2, volumes[1]['id'])
|
||||
self.assertEqual('1', volumes[0]['id'])
|
||||
self.assertEqual('2', volumes[1]['id'])
|
||||
|
||||
def test_volume_index_limit(self):
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
@ -889,19 +910,19 @@ class VolumeApiTest(test.TestCase):
|
||||
]
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stub_volume_get_all_by_project)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/detail?marker=1')
|
||||
res_dict = self.controller.detail(req)
|
||||
volumes = res_dict['volumes']
|
||||
self.assertEqual(2, len(volumes))
|
||||
self.assertEqual(1, volumes[0]['id'])
|
||||
self.assertEqual(2, volumes[1]['id'])
|
||||
self.assertEqual('1', volumes[0]['id'])
|
||||
self.assertEqual('2', volumes[1]['id'])
|
||||
|
||||
def test_volume_detail_limit(self):
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/detail?limit=1')
|
||||
res_dict = self.controller.detail(req)
|
||||
@ -932,7 +953,7 @@ class VolumeApiTest(test.TestCase):
|
||||
def test_volume_detail_limit_marker(self):
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stubs.stub_volume_get_all_by_project)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/detail?marker=1&limit=1')
|
||||
res_dict = self.controller.detail(req)
|
||||
@ -1128,7 +1149,8 @@ class VolumeApiTest(test.TestCase):
|
||||
self.assertEqual('vol3', resp['volumes'][0]['name'])
|
||||
|
||||
def test_volume_show(self):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_api_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/1')
|
||||
res_dict = self.controller.show(req, '1')
|
||||
@ -1141,9 +1163,17 @@ class VolumeApiTest(test.TestCase):
|
||||
|
||||
def test_volume_show_no_attachments(self):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, attach_status='detached')
|
||||
vol = stubs.stub_volume(volume_id, attach_status='detached')
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
def stub_volume_admin_metadata_get(context, volume_id, **kwargs):
|
||||
return stubs.stub_volume_admin_metadata_get(
|
||||
context, volume_id, attach_status='detached')
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_admin_metadata_get',
|
||||
stub_volume_admin_metadata_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/1')
|
||||
res_dict = self.controller.show(req, '1')
|
||||
@ -1193,28 +1223,30 @@ class VolumeApiTest(test.TestCase):
|
||||
'server_id': stubs.FAKE_UUID,
|
||||
'host_name': None,
|
||||
'device': '/',
|
||||
'attached_at': attach_tmp['attach_time'],
|
||||
'attached_at': attach_tmp['attach_time'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc()),
|
||||
}],
|
||||
metadata={'key': 'value', 'readonly': 'True'},
|
||||
with_migration_status=True)
|
||||
expected['volume']['updated_at'] = volume_tmp['updated_at']
|
||||
expected['volume']['updated_at'] = volume_tmp['updated_at'].replace(
|
||||
tzinfo=iso8601.iso8601.Utc())
|
||||
self.assertEqual(expected, res_dict)
|
||||
|
||||
def test_volume_show_with_encrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
vol = stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
return fake_volume.fake_volume_obj(context, **vol)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
self.assertEqual(True, res_dict['volume']['encrypted'])
|
||||
|
||||
def test_volume_show_with_unencrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id=None)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_api_get)
|
||||
self.stubs.Set(db, 'volume_type_get', stubs.stub_volume_type_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
|
@ -36,6 +36,7 @@ from cinder.cmd import volume as cinder_volume
|
||||
from cinder.cmd import volume_usage_audit
|
||||
from cinder import context
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import version
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -369,24 +370,6 @@ class TestCinderManageCmd(test.TestCase):
|
||||
def tearDown(self):
|
||||
super(TestCinderManageCmd, self).tearDown()
|
||||
|
||||
@mock.patch('oslo_utils.uuidutils.is_uuid_like')
|
||||
def test_param2id(self, is_uuid_like):
|
||||
mock_object_id = mock.MagicMock()
|
||||
is_uuid_like.return_value = True
|
||||
|
||||
object_id = cinder_manage.param2id(mock_object_id)
|
||||
self.assertEqual(mock_object_id, object_id)
|
||||
is_uuid_like.assert_called_once_with(mock_object_id)
|
||||
|
||||
@mock.patch('oslo_utils.uuidutils.is_uuid_like')
|
||||
def test_param2id_int_string(self, is_uuid_like):
|
||||
object_id_str = '10'
|
||||
is_uuid_like.return_value = False
|
||||
|
||||
object_id = cinder_manage.param2id(object_id_str)
|
||||
self.assertEqual(10, object_id)
|
||||
is_uuid_like.assert_called_once_with(object_id_str)
|
||||
|
||||
@mock.patch('cinder.db.migration.db_sync')
|
||||
def test_db_commands_sync(self, db_sync):
|
||||
version = mock.MagicMock()
|
||||
@ -485,28 +468,28 @@ class TestCinderManageCmd(test.TestCase):
|
||||
@mock.patch('cinder.rpc.init')
|
||||
def test_volume_commands_delete(self, rpc_init, get_client,
|
||||
get_admin_context, volume_get):
|
||||
ctxt = context.RequestContext('fake-user', 'fake-project')
|
||||
ctxt = context.RequestContext('admin', 'fake', True)
|
||||
get_admin_context.return_value = ctxt
|
||||
mock_client = mock.MagicMock()
|
||||
cctxt = mock.MagicMock()
|
||||
mock_client.prepare.return_value = cctxt
|
||||
get_client.return_value = mock_client
|
||||
volume_id = '123'
|
||||
host = 'fake@host'
|
||||
volume = {'id': volume_id,
|
||||
'host': host + '#pool1',
|
||||
'status': 'available'}
|
||||
db_volume = {'host': host + '#pool1'}
|
||||
volume = fake_volume.fake_db_volume(**db_volume)
|
||||
volume_obj = fake_volume.fake_volume_obj(ctxt, **volume)
|
||||
volume_id = volume['id']
|
||||
volume_get.return_value = volume
|
||||
|
||||
volume_cmds = cinder_manage.VolumeCommands()
|
||||
volume_cmds._client = mock_client
|
||||
volume_cmds.delete(volume_id)
|
||||
|
||||
volume_get.assert_called_once_with(ctxt, 123)
|
||||
# NOTE prepare called w/o pool part in host
|
||||
volume_get.assert_called_once_with(ctxt, volume_id)
|
||||
mock_client.prepare.assert_called_once_with(server=host)
|
||||
cctxt.cast.assert_called_once_with(ctxt, 'delete_volume',
|
||||
volume_id=volume['id'])
|
||||
volume_id=volume['id'],
|
||||
volume=volume_obj)
|
||||
|
||||
@mock.patch('cinder.db.volume_destroy')
|
||||
@mock.patch('cinder.db.volume_get')
|
||||
@ -514,10 +497,11 @@ class TestCinderManageCmd(test.TestCase):
|
||||
@mock.patch('cinder.rpc.init')
|
||||
def test_volume_commands_delete_no_host(self, rpc_init, get_admin_context,
|
||||
volume_get, volume_destroy):
|
||||
ctxt = context.RequestContext('fake-user', 'fake-project')
|
||||
ctxt = context.RequestContext('fake-user', 'fake-project',
|
||||
is_admin=True)
|
||||
get_admin_context.return_value = ctxt
|
||||
volume_id = '123'
|
||||
volume = {'id': volume_id, 'host': None, 'status': 'available'}
|
||||
volume = fake_volume.fake_db_volume()
|
||||
volume_id = volume['id']
|
||||
volume_get.return_value = volume
|
||||
|
||||
with mock.patch('sys.stdout', new=six.StringIO()) as fake_out:
|
||||
@ -528,8 +512,10 @@ class TestCinderManageCmd(test.TestCase):
|
||||
volume_cmds.delete(volume_id)
|
||||
|
||||
get_admin_context.assert_called_once_with()
|
||||
volume_get.assert_called_once_with(ctxt, 123)
|
||||
volume_destroy.assert_called_once_with(ctxt, 123)
|
||||
volume_get.assert_called_once_with(ctxt, volume_id)
|
||||
self.assertTrue(volume_destroy.called)
|
||||
admin_context = volume_destroy.call_args[0][0]
|
||||
self.assertTrue(admin_context.is_admin)
|
||||
self.assertEqual(expected_out, fake_out.getvalue())
|
||||
|
||||
@mock.patch('cinder.db.volume_destroy')
|
||||
@ -541,8 +527,9 @@ class TestCinderManageCmd(test.TestCase):
|
||||
volume_get, volume_destroy):
|
||||
ctxt = context.RequestContext('fake-user', 'fake-project')
|
||||
get_admin_context.return_value = ctxt
|
||||
volume_id = '123'
|
||||
volume = {'id': volume_id, 'host': 'fake-host', 'status': 'in-use'}
|
||||
db_volume = {'status': 'in-use', 'host': 'fake-host'}
|
||||
volume = fake_volume.fake_db_volume(**db_volume)
|
||||
volume_id = volume['id']
|
||||
volume_get.return_value = volume
|
||||
|
||||
with mock.patch('sys.stdout', new=six.StringIO()) as fake_out:
|
||||
@ -552,7 +539,7 @@ class TestCinderManageCmd(test.TestCase):
|
||||
volume_cmds = cinder_manage.VolumeCommands()
|
||||
volume_cmds.delete(volume_id)
|
||||
|
||||
volume_get.assert_called_once_with(ctxt, 123)
|
||||
volume_get.assert_called_once_with(ctxt, volume_id)
|
||||
self.assertEqual(expected_out, fake_out.getvalue())
|
||||
|
||||
def test_config_commands_list(self):
|
||||
|
@ -79,7 +79,11 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
vol['status'] = 'available'
|
||||
vol['volume_type_id'] = self.volume_type['id']
|
||||
vol['host'] = 'fake_host'
|
||||
return db.volume_create(self.context, vol)
|
||||
vol['availability_zone'] = 'fake_zone'
|
||||
vol['attach_status'] = 'detached'
|
||||
volume = objects.Volume(context=self.context, **vol)
|
||||
volume.create()
|
||||
return volume
|
||||
|
||||
def _create_snapshot(self, volume):
|
||||
snapshot = objects.Snapshot(self.context)
|
||||
@ -145,7 +149,7 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
msg = ("Maximum number of volumes allowed (1) exceeded for"
|
||||
" quota '%s'." % resource)
|
||||
self.assertEqual(msg, six.text_type(ex))
|
||||
db.volume_destroy(self.context, vol_ref['id'])
|
||||
vol_ref.destroy()
|
||||
|
||||
def test_too_many_snapshots_of_type(self):
|
||||
resource = 'snapshots_%s' % self.volume_type_name
|
||||
@ -161,7 +165,7 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
volume.API().create_snapshot,
|
||||
self.context, vol_ref, '', '')
|
||||
snap_ref.destroy()
|
||||
db.volume_destroy(self.context, vol_ref['id'])
|
||||
vol_ref.destroy()
|
||||
|
||||
def test_too_many_backups(self):
|
||||
resource = 'backups'
|
||||
@ -211,7 +215,7 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
self.project_id)
|
||||
self.assertEqual(20, usages['gigabytes']['in_use'])
|
||||
snap_ref.destroy()
|
||||
db.volume_destroy(self.context, vol_ref['id'])
|
||||
vol_ref.destroy()
|
||||
|
||||
def test_too_many_combined_backup_gigabytes(self):
|
||||
vol_ref = self._create_volume(size=10000)
|
||||
@ -229,7 +233,7 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
container='container',
|
||||
incremental=False)
|
||||
db.backup_destroy(self.context, backup_ref['id'])
|
||||
db.volume_destroy(self.context, vol_ref['id'])
|
||||
vol_ref.destroy()
|
||||
|
||||
def test_no_snapshot_gb_quota_flag(self):
|
||||
self.flags(quota_volumes=2,
|
||||
@ -250,8 +254,8 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
|
||||
snap_ref.destroy()
|
||||
snap_ref2.destroy()
|
||||
db.volume_destroy(self.context, vol_ref['id'])
|
||||
db.volume_destroy(self.context, vol_ref2['id'])
|
||||
vol_ref.destroy()
|
||||
vol_ref2.destroy()
|
||||
|
||||
def test_backup_gb_quota_flag(self):
|
||||
self.flags(quota_volumes=2,
|
||||
@ -281,8 +285,8 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
|
||||
db.backup_destroy(self.context, backup_ref['id'])
|
||||
db.backup_destroy(self.context, backup_ref2['id'])
|
||||
db.volume_destroy(self.context, vol_ref['id'])
|
||||
db.volume_destroy(self.context, vol_ref2['id'])
|
||||
vol_ref.destroy()
|
||||
vol_ref2.destroy()
|
||||
|
||||
def test_too_many_gigabytes_of_type(self):
|
||||
resource = 'gigabytes_%s' % self.volume_type_name
|
||||
@ -299,7 +303,7 @@ class QuotaIntegrationTestCase(test.TestCase):
|
||||
expected = exception.VolumeSizeExceedsAvailableQuota(
|
||||
requested=1, quota=10, consumed=10, name=resource)
|
||||
self.assertEqual(str(expected), str(raised_exc))
|
||||
db.volume_destroy(self.context, vol_ref['id'])
|
||||
vol_ref.destroy()
|
||||
|
||||
|
||||
class FakeContext(object):
|
||||
|
@ -580,7 +580,6 @@ class VolumeTestCase(BaseVolumeTestCase):
|
||||
self.assertEqual(4, len(self.notifier.notifications),
|
||||
self.notifier.notifications)
|
||||
msg = self.notifier.notifications[2]
|
||||
expected['metadata'] = []
|
||||
self.assertEqual('volume.delete.start', msg['event_type'])
|
||||
self.assertDictMatch(expected, msg['payload'])
|
||||
msg = self.notifier.notifications[3]
|
||||
@ -1086,15 +1085,14 @@ class VolumeTestCase(BaseVolumeTestCase):
|
||||
'volume_get_all_by_project') as by_project:
|
||||
with mock.patch.object(volume_api.db,
|
||||
'volume_get_all') as get_all:
|
||||
fake_volume = {'volume_type_id': 'fake_type_id',
|
||||
'name': 'fake_name',
|
||||
'host': 'fake_host',
|
||||
'id': 'fake_volume_id'}
|
||||
db_volume = {'volume_type_id': 'fake_type_id',
|
||||
'name': 'fake_name',
|
||||
'host': 'fake_host',
|
||||
'id': 'fake_volume_id'}
|
||||
|
||||
fake_volume_list = []
|
||||
fake_volume_list.append([fake_volume])
|
||||
by_project.return_value = fake_volume_list
|
||||
get_all.return_value = fake_volume_list
|
||||
volume = fake_volume.fake_db_volume(**db_volume)
|
||||
by_project.return_value = [volume]
|
||||
get_all.return_value = [volume]
|
||||
|
||||
volume_api.get_all(self.context, filters={'all_tenants': '0'})
|
||||
self.assertTrue(by_project.called)
|
||||
@ -3205,7 +3203,6 @@ class VolumeTestCase(BaseVolumeTestCase):
|
||||
volume = tests_utils.create_volume(self.context, **self.volume_params)
|
||||
self.volume.create_volume(self.context, volume['id'])
|
||||
volume['status'] = 'error_deleting'
|
||||
volume['host'] = 'fakehost'
|
||||
|
||||
volume_api = cinder.volume.api.API()
|
||||
|
||||
@ -3219,11 +3216,12 @@ class VolumeTestCase(BaseVolumeTestCase):
|
||||
volume_api.delete(self.context, volume, force=True)
|
||||
|
||||
# status is deleting
|
||||
volume = db.volume_get(context.get_admin_context(), volume['id'])
|
||||
self.assertEqual('deleting', volume['status'])
|
||||
volume = objects.Volume.get_by_id(context.get_admin_context(),
|
||||
volume.id)
|
||||
self.assertEqual('deleting', volume.status)
|
||||
|
||||
# clean up
|
||||
self.volume.delete_volume(self.context, volume['id'])
|
||||
self.volume.delete_volume(self.context, volume.id)
|
||||
|
||||
def test_cannot_force_delete_attached_volume(self):
|
||||
"""Test volume can't be force delete in attached state."""
|
||||
@ -7664,8 +7662,8 @@ class ImageVolumeCacheTestCase(BaseVolumeTestCase):
|
||||
}
|
||||
volume_api = cinder.volume.api.API()
|
||||
volume = tests_utils.create_volume(self.context, **volume_params)
|
||||
volume = db.volume_update(self.context, volume['id'],
|
||||
{'status': 'available'})
|
||||
volume.status = 'available'
|
||||
volume.save()
|
||||
image_id = '70a599e0-31e7-49b7-b260-868f441e862b'
|
||||
db.image_volume_cache_create(self.context,
|
||||
volume['host'],
|
||||
|
@ -271,12 +271,25 @@ class VolumeRpcAPITestCase(test.TestCase):
|
||||
version='1.32')
|
||||
can_send_version.assert_called_once_with('1.32')
|
||||
|
||||
def test_delete_volume(self):
|
||||
@mock.patch('oslo_messaging.RPCClient.can_send_version',
|
||||
return_value=True)
|
||||
def test_delete_volume(self, can_send_version):
|
||||
self._test_volume_api('delete_volume',
|
||||
rpc_method='cast',
|
||||
volume=self.fake_volume,
|
||||
volume=self.fake_volume_obj,
|
||||
unmanage_only=False,
|
||||
version='1.33')
|
||||
can_send_version.assert_called_once_with('1.33')
|
||||
|
||||
@mock.patch('oslo_messaging.RPCClient.can_send_version',
|
||||
return_value=False)
|
||||
def test_delete_volume_old(self, can_send_version):
|
||||
self._test_volume_api('delete_volume',
|
||||
rpc_method='cast',
|
||||
volume=self.fake_volume_obj,
|
||||
unmanage_only=False,
|
||||
version='1.15')
|
||||
can_send_version.assert_called_once_with('1.33')
|
||||
|
||||
def test_create_snapshot(self):
|
||||
self._test_volume_api('create_snapshot',
|
||||
|
@ -372,7 +372,7 @@ class API(base.Base):
|
||||
reservations = None
|
||||
LOG.exception(_LE("Failed to update quota while "
|
||||
"deleting volume."))
|
||||
self.db.volume_destroy(context.elevated(), volume_id)
|
||||
volume.destroy()
|
||||
|
||||
if reservations:
|
||||
QUOTAS.commit(context, reservations, project_id=project_id)
|
||||
@ -440,15 +440,13 @@ class API(base.Base):
|
||||
msg = _("Unable to delete encrypted volume: %s.") % e.msg
|
||||
raise exception.InvalidVolume(reason=msg)
|
||||
|
||||
now = timeutils.utcnow()
|
||||
vref = self.db.volume_update(context,
|
||||
volume_id,
|
||||
{'status': 'deleting',
|
||||
'terminated_at': now})
|
||||
volume.status = 'deleting'
|
||||
volume.terminated_at = timeutils.utcnow()
|
||||
volume.save()
|
||||
|
||||
self.volume_rpcapi.delete_volume(context, volume, unmanage_only)
|
||||
LOG.info(_LI("Delete volume request issued successfully."),
|
||||
resource=vref)
|
||||
resource=volume)
|
||||
|
||||
@wrap_check_policy
|
||||
def update(self, context, volume, fields):
|
||||
@ -462,15 +460,14 @@ class API(base.Base):
|
||||
LOG.info(_LI("Volume updated successfully."), resource=vref)
|
||||
|
||||
def get(self, context, volume_id, viewable_admin_meta=False):
|
||||
rv = self.db.volume_get(context, volume_id)
|
||||
|
||||
volume = dict(rv)
|
||||
volume = objects.Volume.get_by_id(context, volume_id)
|
||||
|
||||
if viewable_admin_meta:
|
||||
ctxt = context.elevated()
|
||||
admin_metadata = self.db.volume_admin_metadata_get(ctxt,
|
||||
volume_id)
|
||||
volume['volume_admin_metadata'] = admin_metadata
|
||||
volume.admin_metadata = admin_metadata
|
||||
volume.obj_reset_changes()
|
||||
|
||||
try:
|
||||
check_policy(context, 'get', volume)
|
||||
@ -478,7 +475,7 @@ class API(base.Base):
|
||||
# raise VolumeNotFound instead to make sure Cinder behaves
|
||||
# as it used to
|
||||
raise exception.VolumeNotFound(volume_id=volume_id)
|
||||
LOG.info(_LI("Volume info retrieved successfully."), resource=rv)
|
||||
LOG.info(_LI("Volume info retrieved successfully."), resource=volume)
|
||||
return volume
|
||||
|
||||
def get_all(self, context, marker=None, limit=None, sort_keys=None,
|
||||
@ -514,21 +511,18 @@ class API(base.Base):
|
||||
if context.is_admin and allTenants:
|
||||
# Need to remove all_tenants to pass the filtering below.
|
||||
del filters['all_tenants']
|
||||
volumes = self.db.volume_get_all(context, marker, limit,
|
||||
sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs,
|
||||
filters=filters,
|
||||
offset=offset)
|
||||
volumes = objects.VolumeList.get_all(context, marker, limit,
|
||||
sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs,
|
||||
filters=filters,
|
||||
offset=offset)
|
||||
else:
|
||||
if viewable_admin_meta:
|
||||
context = context.elevated()
|
||||
volumes = self.db.volume_get_all_by_project(context,
|
||||
context.project_id,
|
||||
marker, limit,
|
||||
sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs,
|
||||
filters=filters,
|
||||
offset=offset)
|
||||
volumes = objects.VolumeList.get_all_by_project(
|
||||
context, context.project_id, marker, limit,
|
||||
sort_keys=sort_keys, sort_dirs=sort_dirs, filters=filters,
|
||||
offset=offset)
|
||||
|
||||
LOG.info(_LI("Get all volumes completed successfully."))
|
||||
return volumes
|
||||
@ -545,9 +539,9 @@ class API(base.Base):
|
||||
|
||||
def get_volume(self, context, volume_id):
|
||||
check_policy(context, 'get_volume')
|
||||
vref = self.db.volume_get(context, volume_id)
|
||||
LOG.info(_LI("Volume retrieved successfully."), resource=vref)
|
||||
return dict(vref)
|
||||
volume = objects.Volume.get_by_id(context, volume_id)
|
||||
LOG.info(_LI("Volume retrieved successfully."), resource=volume)
|
||||
return volume
|
||||
|
||||
def get_all_snapshots(self, context, search_opts=None, marker=None,
|
||||
limit=None, sort_keys=None, sort_dirs=None,
|
||||
|
@ -190,7 +190,7 @@ def locked_snapshot_operation(f):
|
||||
class VolumeManager(manager.SchedulerDependentManager):
|
||||
"""Manages attachable block storage devices."""
|
||||
|
||||
RPC_API_VERSION = '1.32'
|
||||
RPC_API_VERSION = '1.33'
|
||||
|
||||
target = messaging.Target(version=RPC_API_VERSION)
|
||||
|
||||
@ -376,7 +376,7 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
# Initialize backend capabilities list
|
||||
self.driver.init_capabilities()
|
||||
|
||||
volumes = self.db.volume_get_all_by_host(ctxt, self.host)
|
||||
volumes = objects.VolumeList.get_all_by_host(ctxt, self.host)
|
||||
snapshots = self.db.snapshot_get_by_host(ctxt, self.host)
|
||||
self._sync_provider_info(ctxt, volumes, snapshots)
|
||||
# FIXME volume count for exporting is wrong
|
||||
@ -397,9 +397,8 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
LOG.exception(_LE("Failed to re-export volume, "
|
||||
"setting to ERROR."),
|
||||
resource=volume)
|
||||
self.db.volume_update(ctxt,
|
||||
volume['id'],
|
||||
{'status': 'error'})
|
||||
volume.status = 'error'
|
||||
volume.save()
|
||||
elif volume['status'] in ('downloading', 'creating'):
|
||||
LOG.warning(_LW("Detected volume stuck "
|
||||
"in %(curr_status)s "
|
||||
@ -409,9 +408,8 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
|
||||
if volume['status'] == 'downloading':
|
||||
self.driver.clear_download(ctxt, volume)
|
||||
self.db.volume_update(ctxt,
|
||||
volume['id'],
|
||||
{'status': 'error'})
|
||||
volume.status = 'error'
|
||||
volume.save()
|
||||
else:
|
||||
pass
|
||||
snapshots = objects.SnapshotList.get_by_host(
|
||||
@ -579,7 +577,8 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
return vol_ref.id
|
||||
|
||||
@locked_volume_operation
|
||||
def delete_volume(self, context, volume_id, unmanage_only=False):
|
||||
def delete_volume(self, context, volume_id, unmanage_only=False,
|
||||
volume=None):
|
||||
"""Deletes and unexports volume.
|
||||
|
||||
1. Delete a volume(normal case)
|
||||
@ -592,8 +591,13 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
|
||||
context = context.elevated()
|
||||
|
||||
# FIXME(thangp): Remove this in v2.0 of RPC API.
|
||||
if volume is not None:
|
||||
volume_id = volume.id
|
||||
|
||||
try:
|
||||
volume_ref = self.db.volume_get(context, volume_id)
|
||||
# TODO(thangp): Replace with volume.refresh() when it is available
|
||||
volume = objects.Volume.get_by_id(context, volume_id)
|
||||
except exception.VolumeNotFound:
|
||||
# NOTE(thingee): It could be possible for a volume to
|
||||
# be deleted when resuming deletes from init_host().
|
||||
@ -601,51 +605,51 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
volume_id)
|
||||
return True
|
||||
|
||||
if context.project_id != volume_ref['project_id']:
|
||||
project_id = volume_ref['project_id']
|
||||
if context.project_id != volume.project_id:
|
||||
project_id = volume.project_id
|
||||
else:
|
||||
project_id = context.project_id
|
||||
|
||||
if volume_ref['attach_status'] == "attached":
|
||||
if volume['attach_status'] == "attached":
|
||||
# Volume is still attached, need to detach first
|
||||
raise exception.VolumeAttached(volume_id=volume_id)
|
||||
if vol_utils.extract_host(volume_ref['host']) != self.host:
|
||||
if vol_utils.extract_host(volume.host) != self.host:
|
||||
raise exception.InvalidVolume(
|
||||
reason=_("volume is not local to this node"))
|
||||
|
||||
# The status 'deleting' is not included, because it only applies to
|
||||
# the source volume to be deleted after a migration. No quota
|
||||
# needs to be handled for it.
|
||||
is_migrating = volume_ref['migration_status'] not in (None, 'error',
|
||||
'success')
|
||||
is_migrating = volume.migration_status not in (None, 'error',
|
||||
'success')
|
||||
is_migrating_dest = (is_migrating and
|
||||
volume_ref['migration_status'].startswith(
|
||||
volume.migration_status.startswith(
|
||||
'target:'))
|
||||
self._notify_about_volume_usage(context, volume_ref, "delete.start")
|
||||
self._notify_about_volume_usage(context, volume, "delete.start")
|
||||
try:
|
||||
# NOTE(flaper87): Verify the driver is enabled
|
||||
# before going forward. The exception will be caught
|
||||
# and the volume status updated.
|
||||
utils.require_driver_initialized(self.driver)
|
||||
|
||||
self.driver.remove_export(context, volume_ref)
|
||||
self.driver.remove_export(context, volume)
|
||||
if unmanage_only:
|
||||
self.driver.unmanage(volume_ref)
|
||||
self.driver.unmanage(volume)
|
||||
else:
|
||||
self.driver.delete_volume(volume_ref)
|
||||
self.driver.delete_volume(volume)
|
||||
except exception.VolumeIsBusy:
|
||||
LOG.error(_LE("Unable to delete busy volume."),
|
||||
resource=volume_ref)
|
||||
resource=volume)
|
||||
# If this is a destination volume, we have to clear the database
|
||||
# record to avoid user confusion.
|
||||
self._clear_db(context, is_migrating_dest, volume_ref,
|
||||
self._clear_db(context, is_migrating_dest, volume,
|
||||
'available')
|
||||
return True
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
# If this is a destination volume, we have to clear the
|
||||
# database record to avoid user confusion.
|
||||
self._clear_db(context, is_migrating_dest, volume_ref,
|
||||
self._clear_db(context, is_migrating_dest, volume,
|
||||
'error_deleting')
|
||||
|
||||
# If deleting source/destination volume in a migration, we should
|
||||
@ -654,39 +658,39 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
# Get reservations
|
||||
try:
|
||||
reserve_opts = {'volumes': -1,
|
||||
'gigabytes': -volume_ref['size']}
|
||||
'gigabytes': -volume.size}
|
||||
QUOTAS.add_volume_type_opts(context,
|
||||
reserve_opts,
|
||||
volume_ref.get('volume_type_id'))
|
||||
volume.volume_type_id)
|
||||
reservations = QUOTAS.reserve(context,
|
||||
project_id=project_id,
|
||||
**reserve_opts)
|
||||
except Exception:
|
||||
reservations = None
|
||||
LOG.exception(_LE("Failed to update usages deleting volume."),
|
||||
resource=volume_ref)
|
||||
resource=volume)
|
||||
|
||||
# Delete glance metadata if it exists
|
||||
self.db.volume_glance_metadata_delete_by_volume(context, volume_id)
|
||||
|
||||
self.db.volume_destroy(context, volume_id)
|
||||
volume.destroy()
|
||||
|
||||
# If deleting source/destination volume in a migration, we should
|
||||
# skip quotas.
|
||||
if not is_migrating:
|
||||
self._notify_about_volume_usage(context, volume_ref, "delete.end")
|
||||
self._notify_about_volume_usage(context, volume, "delete.end")
|
||||
|
||||
# Commit the reservations
|
||||
if reservations:
|
||||
QUOTAS.commit(context, reservations, project_id=project_id)
|
||||
|
||||
pool = vol_utils.extract_host(volume_ref['host'], 'pool')
|
||||
pool = vol_utils.extract_host(volume.host, 'pool')
|
||||
if pool is None:
|
||||
# Legacy volume, put them into default pool
|
||||
pool = self.driver.configuration.safe_get(
|
||||
'volume_backend_name') or vol_utils.extract_host(
|
||||
volume_ref['host'], 'pool', True)
|
||||
size = volume_ref['size']
|
||||
volume.host, 'pool', True)
|
||||
size = volume.size
|
||||
|
||||
try:
|
||||
self.stats['pools'][pool]['allocated_capacity_gb'] -= size
|
||||
@ -696,7 +700,7 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
|
||||
self.publish_service_capabilities(context)
|
||||
|
||||
LOG.info(_LI("Deleted volume successfully."), resource=volume_ref)
|
||||
LOG.info(_LI("Deleted volume successfully."), resource=volume)
|
||||
return True
|
||||
|
||||
def _clear_db(self, context, is_migrating_dest, volume_ref, status):
|
||||
@ -704,14 +708,13 @@ class VolumeManager(manager.SchedulerDependentManager):
|
||||
# driver.delete_volume() fails in delete_volume(), so it is already
|
||||
# in the exception handling part.
|
||||
if is_migrating_dest:
|
||||
self.db.volume_destroy(context, volume_ref['id'])
|
||||
volume_ref.destroy()
|
||||
LOG.error(_LE("Unable to delete the destination volume "
|
||||
"during volume migration, (NOTE: database "
|
||||
"record needs to be deleted)."), resource=volume_ref)
|
||||
else:
|
||||
self.db.volume_update(context,
|
||||
volume_ref['id'],
|
||||
{'status': status})
|
||||
volume_ref.status = status
|
||||
volume_ref.save()
|
||||
|
||||
def create_snapshot(self, context, volume_id, snapshot):
|
||||
"""Creates and exports the snapshot."""
|
||||
|
@ -80,6 +80,7 @@ class VolumeAPI(object):
|
||||
and delete_cgsnapshot() to cast method only with necessary
|
||||
args. Forwarding CGSnapshot object instead of CGSnapshot_id.
|
||||
1.32 - Adds support for sending objects over RPC in create_volume().
|
||||
1.33 - Adds support for sending objects over RPC in delete_volume().
|
||||
"""
|
||||
|
||||
BASE_RPC_API_VERSION = '1.0'
|
||||
@ -153,11 +154,16 @@ class VolumeAPI(object):
|
||||
cctxt.cast(ctxt, 'create_volume', **msg_args)
|
||||
|
||||
def delete_volume(self, ctxt, volume, unmanage_only=False):
|
||||
new_host = utils.extract_host(volume['host'])
|
||||
cctxt = self.client.prepare(server=new_host, version='1.15')
|
||||
cctxt.cast(ctxt, 'delete_volume',
|
||||
volume_id=volume['id'],
|
||||
unmanage_only=unmanage_only)
|
||||
msg_args = {'volume_id': volume.id, 'unmanage_only': unmanage_only}
|
||||
if self.client.can_send_version('1.33'):
|
||||
version = '1.33'
|
||||
msg_args['volume'] = volume
|
||||
else:
|
||||
version = '1.15'
|
||||
|
||||
new_host = utils.extract_host(volume.host)
|
||||
cctxt = self.client.prepare(server=new_host, version=version)
|
||||
cctxt.cast(ctxt, 'delete_volume', **msg_args)
|
||||
|
||||
def create_snapshot(self, ctxt, volume, snapshot):
|
||||
new_host = utils.extract_host(volume['host'])
|
||||
|
Loading…
x
Reference in New Issue
Block a user