]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Update get/delete_volume API to use versionedobjects
authorThang Pham <thang.g.pham@gmail.com>
Tue, 3 Nov 2015 14:15:37 +0000 (06:15 -0800)
committerThang Pham <thang.g.pham@gmail.com>
Thu, 12 Nov 2015 12:54:16 +0000 (04:54 -0800)
The following patch updates get_volume and delete_volume
API to use volume versionedobjects.  Changes were made to
be backwards compatible with older RPC clients. It only
includes changes to the core cinder code.  Changes in the
drivers are left to each driver maintainer to update.

Note that this patch DOES NOT try to use
object dot notation everywhere, since it would
increase the size of the patch.  Instead, it
will be done in subsequent patches.

Co-Authored-By: Michal Dulko <michal.dulko@intel.com>
Co-Authored-By: Szymon Wroblewski <szymon.wroblewski@intel.com>
Change-Id: Ifb36726f8372e21d1d9825d6ab04a072e5db4a6a
Partial-Implements: blueprint cinder-objects

28 files changed:
cinder/api/contrib/volume_manage.py
cinder/api/v1/volumes.py
cinder/api/v2/views/volumes.py
cinder/api/v2/volumes.py
cinder/cmd/manage.py
cinder/tests/unit/api/contrib/test_admin_actions.py
cinder/tests/unit/api/contrib/test_volume_actions.py
cinder/tests/unit/api/contrib/test_volume_host_attribute.py
cinder/tests/unit/api/contrib/test_volume_image_metadata.py
cinder/tests/unit/api/contrib/test_volume_manage.py
cinder/tests/unit/api/contrib/test_volume_migration_status_attribute.py
cinder/tests/unit/api/contrib/test_volume_tenant_attribute.py
cinder/tests/unit/api/contrib/test_volume_transfer.py
cinder/tests/unit/api/contrib/test_volume_unmanage.py
cinder/tests/unit/api/v1/test_snapshot_metadata.py
cinder/tests/unit/api/v1/test_volume_metadata.py
cinder/tests/unit/api/v1/test_volumes.py
cinder/tests/unit/api/v2/stubs.py
cinder/tests/unit/api/v2/test_snapshot_metadata.py
cinder/tests/unit/api/v2/test_volume_metadata.py
cinder/tests/unit/api/v2/test_volumes.py
cinder/tests/unit/test_cmd.py
cinder/tests/unit/test_quota.py
cinder/tests/unit/test_volume.py
cinder/tests/unit/test_volume_rpcapi.py
cinder/volume/api.py
cinder/volume/manager.py
cinder/volume/rpcapi.py

index 3c4167b6e3915bad01c5aa05a210d331f7ec48f6..819e5fad1da1b986aaf9d133a3e1caf642285077 100644 (file)
@@ -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)
index ce594284bad6d0f0e9a02c08885890c61967875b..9a9de03d909792524c6a3f5b0d2455da061d3bef 100644 (file)
@@ -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]
index cd9cd8913b82939eede3b4a336774cf1c8c1725d..ff9e643422dd27e87f5ca92bd82ab2ed5de9c121 100644 (file)
@@ -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."""
index 9f23290c03fd5a7025ab1428bd38deb7e68bfc6c..24e4b0d94f71955bf7e34ff06b758a3e79fa06c7 100644 (file)
@@ -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)
index f787db589c047caa4befd619c816e1528f4cee46..116e436fca6c6fd6daf10f929a3094783bf13374 100644 (file)
@@ -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')
index 5128cacea76ed25411860d4d4397afbaf2b81c90..a3d47fda71a37c0bb547ec7c467a80a6914f4f14 100644 (file)
@@ -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)
index ea5f76c546ea0918b3717b3bac009ad91041a06f..c2078d597fa10ad9f19a6ba4b2d91bf074f89806 100644 (file)
@@ -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,
index 8660bd19952c287ae8c2616e09ddc1c79757bdb7..f6fe4919cf5ab1f087e1873c19b0a02161ef0405 100644 (file)
@@ -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()
 
index 937d4ca2eee9939998ffd813bfeadb13b0a61385..eaa5f5fd178021b97b144860fe490f5b07d77b34 100644 (file)
@@ -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())
index 2419af1a07b8c7d4a36be41b02e8922c7401ebb3..d6de78a3e32d491c2b37bfb0f61c8aee52914b53 100644 (file)
@@ -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',
index 07817450eea47cd39a1a1f35b8f6c64425176b14..a3cc246d337f87313bc71f0253cbb6b96a426a1f 100644 (file)
@@ -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()
 
index 702634e7490ee3398d697951be12a2aab1d43944..54e2554546e69554edf7c85b6fdef3810d22bf5e 100644 (file)
@@ -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():
index c3e40bbd726556bc640bd42d530c39a2c182dba0..999c157be2cf8f8d64c33d9206d298cb4bb49ec0 100644 (file)
@@ -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):
index 102d786c90b2aa6bee8ad6460c4f8b7b90539c0e..e94d8ad09f3aa288487643add4da35532745fcba 100644 (file)
@@ -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):
index 9d83798dbdeb8b6054e6e097e7fda3d17bd60fbc..3fab2c339b53f66ede1ed823bee63e72c4ecbf14 100644 (file)
@@ -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',
index 9c6a0d4836182b70643990a10760215160c01c57..6ef0d6f7dd0b4114d73987d164c02cb97b2310bb 100644 (file)
@@ -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',
index f4371c2f9c17c15501e89902216a3b5bb53154d3..df2ec828a51ea4c5192756ed7d1f996c91c8cff6 100644 (file)
@@ -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)
index e42ff046d1c03eb5bcc6a66b01167d1c0ff5ff15..e478658c0caf5795f89392b3ed7d408c32668947 100644 (file)
 #    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
index ce5eb5d292d09596c97b109f6df6724cb7b395d6..a5ac43b499ff1968049c47175f52cb886f0866f2 100644 (file)
@@ -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',
index de6fa15c6ad787d56bb27618554e41f661d9062a..27d3a35302c319985dcfd7d41ee66f2184856f6d 100644 (file)
@@ -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',
index 659c4295e9663db40df9387617e8311f2f983dfa..0d1e2be48db964fc046ba5be22b3fe3219bec496 100644 (file)
@@ -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)
index 7499e3fc7e788aaebfb7b4a6be2674a39b9bc3e6..704827bc8ce7d80caec57360c9f4520dac257a62 100644 (file)
@@ -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):
index e35c518d0ae9e3405c8aee5172bdaf5e2036fd96..ca6532df89d55da27190be296ac76b08184fa910 100644 (file)
@@ -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):
index e06ae27d88b14d63fa30c29113f8f6f00e76dcab..8b61939064e204b0b2f15f135fbc774821876913 100644 (file)
@@ -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'],
index 72af1a9c9b7cb87ccdfb260d2bc94e585a3af073..8e5bf1dc4a179fcdba948cbdef30840d43a5579a 100644 (file)
@@ -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',
index 1c84175c8aba111b912dad61dfc25bcdacc53d9c..68af86522ace99780f2125390f155c6cac4a507a 100644 (file)
@@ -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,
index 6a9b7a85ef2ab006ae44c99e43858d64a8559658..b3af10c540cdfaecdc13052000f222189f6e67b9 100644 (file)
@@ -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."""
index 91f1a424549d82370356a6831404203242fd79dc..24798e1c4b01b5948d2291de1bd1863342b0a9b5 100644 (file)
@@ -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'])