diff options
author | Unmesh Gurjar <unmesh.gurjar@vertex.co.in> | 2012-08-11 10:31:51 -0700 |
---|---|---|
committer | Josh Durgin <josh.durgin@inktank.com> | 2012-09-18 08:54:25 -0700 |
commit | de09c1866b9138610914ddaaebb9b030884d1e28 (patch) | |
tree | 3a26edadd5d7a794b7c46dd2f30d08285878f3c1 /nova/tests | |
parent | f615e9c22c4c003ac1cd3d01ec8f7cbabd76b96d (diff) | |
download | nova-de09c1866b9138610914ddaaebb9b030884d1e28.tar.gz nova-de09c1866b9138610914ddaaebb9b030884d1e28.tar.xz nova-de09c1866b9138610914ddaaebb9b030884d1e28.zip |
Adds new volume API extensions
Adds following extensions:
1. Create volume from image
2. Copy volume to image
Added unit tests.
Implements: blueprint create-volume-from-image
Conflicts:
cinder/api/openstack/volume/contrib/volume_actions.py
cinder/tests/api/openstack/fakes.py
cinder/tests/api/openstack/volume/contrib/test_volume_actions.py
cinder/tests/policy.json
nova/api/openstack/volume/volumes.py
nova/flags.py
nova/tests/api/openstack/volume/test_volumes.py
nova/tests/test_volume.py
nova/utils.py
nova/volume/api.py
nova/volume/manager.py
This is based on a cherry-pick of cinder commit
2f5360753308eb8b10581fc3c026c1b66f42ebdc with bug fixes
8c30edff982042d2533a810709308b586267c0e9 and
ffe5036fa0e63ccde2d19aa0f425ec43de338dd7 squashed in.
Change-Id: I9c73bd3fa2fa2e0648c01ff3f4fc66f757d7bc3f
Diffstat (limited to 'nova/tests')
-rw-r--r-- | nova/tests/api/openstack/fakes.py | 12 | ||||
-rw-r--r-- | nova/tests/api/openstack/volume/contrib/test_volume_actions.py | 162 | ||||
-rw-r--r-- | nova/tests/api/openstack/volume/test_router.py | 6 | ||||
-rw-r--r-- | nova/tests/api/openstack/volume/test_volumes.py | 108 | ||||
-rw-r--r-- | nova/tests/policy.json | 1 | ||||
-rw-r--r-- | nova/tests/scheduler/test_rpcapi.py | 3 | ||||
-rw-r--r-- | nova/tests/test_volume.py | 241 |
7 files changed, 526 insertions, 7 deletions
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index 6a6f85f68..18407b6a7 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -542,6 +542,18 @@ def stub_volume_create(self, context, size, name, description, snapshot, return vol +def stub_volume_create_from_image(self, context, size, name, description, + snapshot, volume_type, metadata, + availability_zone): + vol = stub_volume('1') + vol['status'] = 'creating' + vol['size'] = size + vol['display_name'] = name + vol['display_description'] = description + vol['availability_zone'] = 'nova' + return vol + + def stub_volume_update(self, context, *args, **param): pass diff --git a/nova/tests/api/openstack/volume/contrib/test_volume_actions.py b/nova/tests/api/openstack/volume/contrib/test_volume_actions.py new file mode 100644 index 000000000..4dd79d366 --- /dev/null +++ b/nova/tests/api/openstack/volume/contrib/test_volume_actions.py @@ -0,0 +1,162 @@ +# Copyright 2012 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import datetime +import webob + +from nova.api.openstack.volume.contrib import volume_actions +from nova import exception +from nova.openstack.common.rpc import common as rpc_common +from nova import test +from nova.tests.api.openstack import fakes +from nova.volume import api as volume_api + + +def stub_volume_get(self, context, volume_id): + volume = fakes.stub_volume(volume_id) + if volume_id == 5: + volume['status'] = 'in-use' + else: + volume['status'] = 'available' + return volume + + +def stub_upload_volume_to_image_service(self, context, volume, metadata, + force): + ret = {"id": volume['id'], + "updated_at": datetime.datetime(1, 1, 1, 1, 1, 1), + "status": 'uploading', + "display_description": volume['display_description'], + "size": volume['size'], + "volume_type": volume['volume_type'], + "image_id": 1, + "container_format": 'bare', + "disk_format": 'raw', + "image_name": 'image_name'} + return ret + + +class VolumeImageActionsTest(test.TestCase): + def setUp(self): + super(VolumeImageActionsTest, self).setUp() + self.controller = volume_actions.VolumeActionsController() + + self.stubs.Set(volume_api.API, 'get', stub_volume_get) + + def test_copy_volume_to_image(self): + self.stubs.Set(volume_api.API, + "copy_volume_to_image", + stub_upload_volume_to_image_service) + + id = 1 + vol = {"container_format": 'bare', + "disk_format": 'raw', + "image_name": 'image_name', + "force": True} + body = {"os-volume_upload_image": vol} + req = fakes.HTTPRequest.blank('/v1/tenant1/volumes/%s/action' % id) + res_dict = self.controller._volume_upload_image(req, id, body) + expected = {'os-volume_upload_image': {'id': id, + 'updated_at': datetime.datetime(1, 1, 1, 1, 1, 1), + 'status': 'uploading', + 'display_description': 'displaydesc', + 'size': 1, + 'volume_type': {'name': 'vol_type_name'}, + 'image_id': 1, + 'container_format': 'bare', + 'disk_format': 'raw', + 'image_name': 'image_name'}} + self.assertDictMatch(res_dict, expected) + + def test_copy_volume_to_image_volumenotfound(self): + def stub_volume_get_raise_exc(self, context, volume_id): + raise exception.VolumeNotFound(volume_id=volume_id) + + self.stubs.Set(volume_api.API, 'get', stub_volume_get_raise_exc) + + id = 1 + vol = {"container_format": 'bare', + "disk_format": 'raw', + "image_name": 'image_name', + "force": True} + body = {"os-volume_upload_image": vol} + req = fakes.HTTPRequest.blank('/v1/tenant1/volumes/%s/action' % id) + self.assertRaises(webob.exc.HTTPNotFound, + self.controller._volume_upload_image, + req, + id, + body) + + def test_copy_volume_to_image_invalidvolume(self): + def stub_upload_volume_to_image_service_raise(self, context, volume, + metadata, force): + raise exception.InvalidVolume + self.stubs.Set(volume_api.API, + "copy_volume_to_image", + stub_upload_volume_to_image_service_raise) + + id = 1 + vol = {"container_format": 'bare', + "disk_format": 'raw', + "image_name": 'image_name', + "force": True} + body = {"os-volume_upload_image": vol} + req = fakes.HTTPRequest.blank('/v1/tenant1/volumes/%s/action' % id) + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller._volume_upload_image, + req, + id, + body) + + def test_copy_volume_to_image_valueerror(self): + def stub_upload_volume_to_image_service_raise(self, context, volume, + metadata, force): + raise ValueError + self.stubs.Set(volume_api.API, + "copy_volume_to_image", + stub_upload_volume_to_image_service_raise) + + id = 1 + vol = {"container_format": 'bare', + "disk_format": 'raw', + "image_name": 'image_name', + "force": True} + body = {"os-volume_upload_image": vol} + req = fakes.HTTPRequest.blank('/v1/tenant1/volumes/%s/action' % id) + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller._volume_upload_image, + req, + id, + body) + + def test_copy_volume_to_image_remoteerror(self): + def stub_upload_volume_to_image_service_raise(self, context, volume, + metadata, force): + raise rpc_common.RemoteError + self.stubs.Set(volume_api.API, + "copy_volume_to_image", + stub_upload_volume_to_image_service_raise) + + id = 1 + vol = {"container_format": 'bare', + "disk_format": 'raw', + "image_name": 'image_name', + "force": True} + body = {"os-volume_upload_image": vol} + req = fakes.HTTPRequest.blank('/v1/tenant1/volumes/%s/action' % id) + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller._volume_upload_image, + req, + id, + body) diff --git a/nova/tests/api/openstack/volume/test_router.py b/nova/tests/api/openstack/volume/test_router.py index 97900bd6d..5934a21e5 100644 --- a/nova/tests/api/openstack/volume/test_router.py +++ b/nova/tests/api/openstack/volume/test_router.py @@ -44,12 +44,16 @@ def create_resource(ext_mgr): return wsgi.Resource(FakeController(ext_mgr)) +def create_volume_resource(ext_mgr): + return wsgi.Resource(FakeController(ext_mgr)) + + class VolumeRouterTestCase(test.TestCase): def setUp(self): super(VolumeRouterTestCase, self).setUp() # NOTE(vish): versions is just returning text so, no need to stub. self.stubs.Set(snapshots, 'create_resource', create_resource) - self.stubs.Set(volumes, 'create_resource', create_resource) + self.stubs.Set(volumes, 'create_resource', create_volume_resource) self.app = volume.APIRouter() def test_versions(self): diff --git a/nova/tests/api/openstack/volume/test_volumes.py b/nova/tests/api/openstack/volume/test_volumes.py index ddd5d0d2d..e7a0e66f3 100644 --- a/nova/tests/api/openstack/volume/test_volumes.py +++ b/nova/tests/api/openstack/volume/test_volumes.py @@ -26,11 +26,29 @@ from nova import flags from nova.openstack.common import timeutils from nova import test from nova.tests.api.openstack import fakes +from nova.tests.image import fake as fake_image from nova.volume import api as volume_api FLAGS = flags.FLAGS +TEST_SNAPSHOT_UUID = '00000000-0000-0000-0000-000000000001' + + +def stub_snapshot_get(self, context, snapshot_id): + if snapshot_id != TEST_SNAPSHOT_UUID: + raise exception.NotFound + + return { + 'id': snapshot_id, + 'volume_id': 12, + 'status': 'available', + 'volume_size': 100, + 'created_at': None, + 'display_name': 'Default name', + 'display_description': 'Default description', + } + class VolumeApiTest(test.TestCase): def setUp(self): @@ -86,6 +104,92 @@ class VolumeApiTest(test.TestCase): req, body) + def test_volume_create_no_body(self): + body = {} + req = fakes.HTTPRequest.blank('/v1/volumes') + self.assertRaises(webob.exc.HTTPUnprocessableEntity, + self.controller.create, + req, + body) + + def test_volume_create_with_image_id(self): + self.stubs.Set(volume_api.API, "create", fakes.stub_volume_create) + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = {"size": '1', + "display_name": "Volume Test Name", + "display_description": "Volume Test Desc", + "availability_zone": "nova", + "imageRef": 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'} + expected = {'volume': {'status': 'fakestatus', + 'display_description': 'Volume Test Desc', + 'availability_zone': 'nova', + 'display_name': 'Volume Test Name', + 'attachments': [{'device': '/', + 'server_id': 'fakeuuid', + 'id': '1', + 'volume_id': '1'}], + 'volume_type': 'vol_type_name', + 'image_id': 'c905cedb-7281-47e4-8a62-f26bc5fc4c77', + 'snapshot_id': None, + 'metadata': {}, + 'id': '1', + 'created_at': datetime.datetime(1999, 1, 1, + 1, 1, 1), + 'size': '1'} + } + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v1/volumes') + res = self.controller.create(req, body) + self.maxDiff = 4096 + self.assertEqual(res.obj, expected) + + def test_volume_create_with_image_id_and_snapshot_id(self): + self.stubs.Set(volume_api.API, "create", fakes.stub_volume_create) + self.stubs.Set(volume_api.API, "get_snapshot", stub_snapshot_get) + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = {"size": '1', + "display_name": "Volume Test Name", + "display_description": "Volume Test Desc", + "availability_zone": "nova", + "imageRef": 'c905cedb-7281-47e4-8a62-f26bc5fc4c77', + "snapshot_id": TEST_SNAPSHOT_UUID} + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v1/volumes') + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, + req, + body) + + def test_volume_create_with_image_id_is_integer(self): + self.stubs.Set(volume_api.API, "create", fakes.stub_volume_create) + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = {"size": '1', + "display_name": "Volume Test Name", + "display_description": "Volume Test Desc", + "availability_zone": "nova", + "imageRef": 1234} + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v1/volumes') + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, + req, + body) + + def test_volume_create_with_image_id_not_uuid_format(self): + self.stubs.Set(volume_api.API, "create", fakes.stub_volume_create) + self.ext_mgr.extensions = {'os-image-create': 'fake'} + vol = {"size": '1', + "display_name": "Volume Test Name", + "display_description": "Volume Test Desc", + "availability_zone": "nova", + "imageRef": '12345'} + body = {"volume": vol} + req = fakes.HTTPRequest.blank('/v1/volumes') + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, + req, + body) + def test_volume_list(self): self.stubs.Set(volume_api.API, 'get_all', fakes.stub_volume_get_all_by_project) @@ -475,7 +579,9 @@ class VolumesUnprocessableEntityTestCase(test.TestCase): def setUp(self): super(VolumesUnprocessableEntityTestCase, self).setUp() - self.controller = volumes.VolumeController() + self.ext_mgr = extensions.ExtensionManager() + self.ext_mgr.extensions = {} + self.controller = volumes.VolumeController(self.ext_mgr) def _unprocessable_volume_create(self, body): req = fakes.HTTPRequest.blank('/v2/fake/volumes') diff --git a/nova/tests/policy.json b/nova/tests/policy.json index a6330c9e5..b856da58a 100644 --- a/nova/tests/policy.json +++ b/nova/tests/policy.json @@ -154,6 +154,7 @@ "volume_extension:volume_admin_actions:reset_status": [["rule:admin_api"]], "volume_extension:snapshot_admin_actions:reset_status": [["rule:admin_api"]], "volume_extension:volume_admin_actions:force_delete": [["rule:admin_api"]], + "volume_extension:volume_actions:upload_image": [], "volume_extension:types_manage": [], "volume_extension:types_extra_specs": [], diff --git a/nova/tests/scheduler/test_rpcapi.py b/nova/tests/scheduler/test_rpcapi.py index 1ff278a20..62147ce25 100644 --- a/nova/tests/scheduler/test_rpcapi.py +++ b/nova/tests/scheduler/test_rpcapi.py @@ -94,4 +94,5 @@ class SchedulerRpcAPITestCase(test.TestCase): def test_create_volume(self): self._test_scheduler_api('create_volume', rpc_method='cast', volume_id="fake_volume", - snapshot_id="fake_snapshots", reservations=list('fake_res')) + snapshot_id="fake_snapshots", image_id="fake_image", + reservations=list('fake_res')) diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py index 6de3d380e..0c5328456 100644 --- a/nova/tests/test_volume.py +++ b/nova/tests/test_volume.py @@ -21,8 +21,10 @@ Tests for Volume Code. """ import cStringIO +import datetime import mox +import os import shutil import tempfile @@ -37,9 +39,13 @@ from nova.openstack.common import rpc import nova.policy from nova import quota from nova import test +from nova.tests.image import fake as fake_image +import nova.volume.api from nova.volume import iscsi QUOTAS = quota.QUOTAS + + FLAGS = flags.FLAGS @@ -60,11 +66,12 @@ class VolumeTestCase(test.TestCase): self.instance_id = instance['id'] self.instance_uuid = instance['uuid'] test_notifier.NOTIFICATIONS = [] + fake_image.stub_out_image_service(self.stubs) def tearDown(self): try: shutil.rmtree(FLAGS.volumes_dir) - except OSError, e: + except OSError: pass db.instance_destroy(self.context, self.instance_uuid) notifier_api._reset_drivers() @@ -74,11 +81,12 @@ class VolumeTestCase(test.TestCase): return 1 @staticmethod - def _create_volume(size=0, snapshot_id=None, metadata=None): + def _create_volume(size=0, snapshot_id=None, image_id=None, metadata=None): """Create a volume object.""" vol = {} vol['size'] = size vol['snapshot_id'] = snapshot_id + vol['image_id'] = image_id vol['user_id'] = 'fake' vol['project_id'] = 'fake' vol['availability_zone'] = FLAGS.storage_availability_zone @@ -137,7 +145,7 @@ class VolumeTestCase(test.TestCase): def test_create_delete_volume_with_metadata(self): """Test volume can be created and deleted.""" test_meta = {'fake_key': 'fake_value'} - volume = self._create_volume('0', None, test_meta) + volume = self._create_volume('0', None, metadata=test_meta) volume_id = volume['id'] self.volume.create_volume(self.context, volume_id) result_meta = { @@ -564,6 +572,231 @@ class VolumeTestCase(test.TestCase): volume = db.volume_get(self.context, volume['id']) self.assertEqual(volume['status'], "in-use") + def _create_volume_from_image(self, expected_status, + fakeout_copy_image_to_volume=False): + """Call copy image to volume, Test the status of volume after calling + copying image to volume.""" + def fake_local_path(volume): + return dst_path + + def fake_copy_image_to_volume(context, volume, image_id): + pass + + dst_fd, dst_path = tempfile.mkstemp() + os.close(dst_fd) + self.stubs.Set(self.volume.driver, 'local_path', fake_local_path) + if fakeout_copy_image_to_volume: + self.stubs.Set(self.volume, '_copy_image_to_volume', + fake_copy_image_to_volume) + + image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' + volume_id = 1 + # creating volume testdata + db.volume_create(self.context, {'id': volume_id, + 'updated_at': datetime.datetime(1, 1, 1, 1, 1, 1), + 'display_description': 'Test Desc', + 'size': 20, + 'status': 'creating', + 'instance_uuid': None, + 'host': 'dummy'}) + try: + self.volume.create_volume(self.context, + volume_id, + image_id=image_id) + + volume = db.volume_get(self.context, volume_id) + self.assertEqual(volume['status'], expected_status) + finally: + # cleanup + db.volume_destroy(self.context, volume_id) + os.unlink(dst_path) + + def test_create_volume_from_image_status_downloading(self): + """Verify that before copying image to volume, it is in downloading + state.""" + self._create_volume_from_image('downloading', True) + + def test_create_volume_from_image_status_available(self): + """Verify that before copying image to volume, it is in available + state.""" + self._create_volume_from_image('available') + + def test_create_volume_from_image_exception(self): + """Verify that create volume from image, the volume status is + 'downloading'.""" + dst_fd, dst_path = tempfile.mkstemp() + os.close(dst_fd) + + self.stubs.Set(self.volume.driver, 'local_path', lambda x: dst_path) + + image_id = 'aaaaaaaa-0000-0000-0000-000000000000' + # creating volume testdata + volume_id = 1 + db.volume_create(self.context, {'id': volume_id, + 'updated_at': datetime.datetime(1, 1, 1, 1, 1, 1), + 'display_description': 'Test Desc', + 'size': 20, + 'status': 'creating', + 'host': 'dummy'}) + + self.assertRaises(exception.ImageNotFound, + self.volume.create_volume, + self.context, + volume_id, + None, + image_id) + volume = db.volume_get(self.context, volume_id) + self.assertEqual(volume['status'], "error") + # cleanup + db.volume_destroy(self.context, volume_id) + os.unlink(dst_path) + + def test_copy_volume_to_image_status_available(self): + dst_fd, dst_path = tempfile.mkstemp() + os.close(dst_fd) + + def fake_local_path(volume): + return dst_path + + self.stubs.Set(self.volume.driver, 'local_path', fake_local_path) + + image_id = '70a599e0-31e7-49b7-b260-868f441e862b' + # creating volume testdata + volume_id = 1 + db.volume_create(self.context, {'id': volume_id, + 'updated_at': datetime.datetime(1, 1, 1, 1, 1, 1), + 'display_description': 'Test Desc', + 'size': 20, + 'status': 'uploading', + 'instance_uuid': None, + 'host': 'dummy'}) + + try: + # start test + self.volume.copy_volume_to_image(self.context, + volume_id, + image_id) + + volume = db.volume_get(self.context, volume_id) + self.assertEqual(volume['status'], 'available') + finally: + # cleanup + db.volume_destroy(self.context, volume_id) + os.unlink(dst_path) + + def test_copy_volume_to_image_status_use(self): + dst_fd, dst_path = tempfile.mkstemp() + os.close(dst_fd) + + def fake_local_path(volume): + return dst_path + + self.stubs.Set(self.volume.driver, 'local_path', fake_local_path) + + #image_id = '70a599e0-31e7-49b7-b260-868f441e862b' + image_id = 'a440c04b-79fa-479c-bed1-0b816eaec379' + # creating volume testdata + volume_id = 1 + db.volume_create(self.context, + {'id': volume_id, + 'updated_at': datetime.datetime(1, 1, 1, 1, 1, 1), + 'display_description': 'Test Desc', + 'size': 20, + 'status': 'uploading', + 'instance_uuid': + 'b21f957d-a72f-4b93-b5a5-45b1161abb02', + 'host': 'dummy'}) + + try: + # start test + self.volume.copy_volume_to_image(self.context, + volume_id, + image_id) + + volume = db.volume_get(self.context, volume_id) + self.assertEqual(volume['status'], 'in-use') + finally: + # cleanup + db.volume_destroy(self.context, volume_id) + os.unlink(dst_path) + + def test_copy_volume_to_image_exception(self): + dst_fd, dst_path = tempfile.mkstemp() + os.close(dst_fd) + + def fake_local_path(volume): + return dst_path + + self.stubs.Set(self.volume.driver, 'local_path', fake_local_path) + + image_id = 'aaaaaaaa-0000-0000-0000-000000000000' + # creating volume testdata + volume_id = 1 + db.volume_create(self.context, {'id': volume_id, + 'updated_at': datetime.datetime(1, 1, 1, 1, 1, 1), + 'display_description': 'Test Desc', + 'size': 20, + 'status': 'in-use', + 'host': 'dummy'}) + + try: + # start test + self.assertRaises(exception.ImageNotFound, + self.volume.copy_volume_to_image, + self.context, + volume_id, + image_id) + + volume = db.volume_get(self.context, volume_id) + self.assertEqual(volume['status'], 'available') + finally: + # cleanup + db.volume_destroy(self.context, volume_id) + os.unlink(dst_path) + + def test_create_volume_from_exact_sized_image(self): + """Verify that an image which is exactly the same size as the + volume, will work correctly.""" + class _FakeImageService: + def __init__(self, db_driver=None, image_service=None): + pass + + def show(self, context, image_id): + return {'size': 2 * 1024 * 1024 * 1024} + + image_id = '70a599e0-31e7-49b7-b260-868f441e862b' + + try: + volume_id = None + volume_api = nova.volume.api.API( + image_service=_FakeImageService()) + volume = volume_api.create(self.context, 2, 'name', 'description', + image_id=1) + volume_id = volume['id'] + self.assertEqual(volume['status'], 'creating') + + finally: + # cleanup + db.volume_destroy(self.context, volume_id) + + def test_create_volume_from_oversized_image(self): + """Verify that an image which is too big will fail correctly.""" + class _FakeImageService: + def __init__(self, db_driver=None, image_service=None): + pass + + def show(self, context, image_id): + return {'size': 2 * 1024 * 1024 * 1024 + 1} + + image_id = '70a599e0-31e7-49b7-b260-868f441e862b' + + volume_api = nova.volume.api.API(image_service=_FakeImageService()) + + self.assertRaises(exception.InvalidInput, + volume_api.create, + self.context, 2, + 'name', 'description', image_id=1) + class DriverTestCase(test.TestCase): """Base Test class for Drivers.""" @@ -591,7 +824,7 @@ class DriverTestCase(test.TestCase): def tearDown(self): try: shutil.rmtree(FLAGS.volumes_dir) - except OSError, e: + except OSError: pass super(DriverTestCase, self).tearDown() |