diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-10-29 01:57:13 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-10-29 01:57:13 +0000 |
| commit | e8af7fb5d725287362323fe451593665cb5ce593 (patch) | |
| tree | 1eee7b567fed959b95facfeb0b609c1bbaf64fa2 /nova/tests | |
| parent | 580747edd6a7d5fb205bbfddba9eb6a338de1e25 (diff) | |
| parent | 7e2b93acc59dea81d52684f7f659fcff32507e14 (diff) | |
Merge "removes the nova-volume code from nova"
Diffstat (limited to 'nova/tests')
49 files changed, 95 insertions, 9520 deletions
diff --git a/nova/tests/api/ec2/test_cinder_cloud.py b/nova/tests/api/ec2/test_cinder_cloud.py index 389f71b7b..49ee9c152 100644 --- a/nova/tests/api/ec2/test_cinder_cloud.py +++ b/nova/tests/api/ec2/test_cinder_cloud.py @@ -18,7 +18,6 @@ # under the License. import copy -import shutil import tempfile from nova.api.ec2 import cloud @@ -85,8 +84,7 @@ class CinderCloudTestCase(test.TestCase): super(CinderCloudTestCase, self).setUp() vol_tmpdir = tempfile.mkdtemp() self.flags(compute_driver='nova.virt.fake.FakeDriver', - volume_api_class='nova.tests.fake_volume.API', - volumes_dir=vol_tmpdir) + volume_api_class='nova.tests.fake_volume.API') def fake_show(meh, context, id): return {'id': id, @@ -123,7 +121,6 @@ class CinderCloudTestCase(test.TestCase): self.compute = self.start_service('compute') self.scheduler = self.start_service('scheduler') self.network = self.start_service('network') - self.volume = self.start_service('volume') self.user_id = 'fake' self.project_id = 'fake' @@ -143,10 +140,6 @@ class CinderCloudTestCase(test.TestCase): '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6') def tearDown(self): - try: - shutil.rmtree(FLAGS.volumes_dir) - except OSError, e: - pass self.volume_api.reset_fake_api(self.context) super(CinderCloudTestCase, self).tearDown() fake.FakeImageService_reset() @@ -312,7 +305,7 @@ class CinderCloudTestCase(test.TestCase): kwargs = {'name': 'bdmtest-volume', 'description': 'bdm test volume description', 'status': 'available', - 'host': self.volume.host, + 'host': 'fake', 'size': 1, 'attach_status': 'detached', 'volume_id': values['id']} @@ -642,13 +635,12 @@ class CinderCloudTestCase(test.TestCase): kwargs = {'name': 'test-volume', 'description': 'test volume description', 'status': 'available', - 'host': self.volume.host, + 'host': 'fake', 'size': 1, 'attach_status': 'detached'} if volume_id: kwargs['volume_id'] = volume_id return self.volume_api.create_with_kwargs(self.context, **kwargs) - #return db.volume_create(self.context, kwargs) def _assert_volume_attached(self, vol, instance_uuid, mountpoint): self.assertEqual(vol['instance_uuid'], instance_uuid) diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py index d86897dc1..1abde1069 100644 --- a/nova/tests/api/ec2/test_cloud.py +++ b/nova/tests/api/ec2/test_cloud.py @@ -22,7 +22,6 @@ import copy import datetime import functools import os -import shutil import string import tempfile @@ -46,7 +45,7 @@ from nova.tests import fake_network from nova.tests.image import fake from nova import utils from nova.virt import fake as fake_virt -from nova.volume import iscsi +from nova import volume LOG = logging.getLogger(__name__) @@ -97,10 +96,8 @@ class CloudTestCase(test.TestCase): super(CloudTestCase, self).setUp() vol_tmpdir = tempfile.mkdtemp() self.flags(compute_driver='nova.virt.fake.FakeDriver', + volume_api_class='nova.tests.fake_volume.API', volumes_dir=vol_tmpdir) - self.stubs.Set(iscsi.TgtAdm, '_get_target', self.fake_get_target) - self.stubs.Set(iscsi.TgtAdm, 'remove_iscsi_target', - self.fake_remove_iscsi_target) def fake_show(meh, context, id): return {'id': id, @@ -137,13 +134,13 @@ class CloudTestCase(test.TestCase): self.compute = self.start_service('compute') self.scheduler = self.start_service('scheduler') self.network = self.start_service('network') - self.volume = self.start_service('volume') self.user_id = 'fake' self.project_id = 'fake' self.context = context.RequestContext(self.user_id, self.project_id, is_admin=True) + self.volume_api = volume.API() # NOTE(comstud): Make 'cast' behave like a 'call' which will # ensure that operations complete @@ -156,10 +153,7 @@ class CloudTestCase(test.TestCase): '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6') def tearDown(self): - try: - shutil.rmtree(FLAGS.volumes_dir) - except OSError, e: - pass + self.volume_api.reset_fake_api(self.context) super(CloudTestCase, self).tearDown() fake.FakeImageService_reset() @@ -681,63 +675,6 @@ class CloudTestCase(test.TestCase): self.cloud.delete_security_group(self.context, 'testgrp') - def test_describe_volumes(self): - """Makes sure describe_volumes works and filters results.""" - vol1 = db.volume_create(self.context, {'project_id': self.project_id}) - vol2 = db.volume_create(self.context, {'project_id': self.project_id}) - result = self.cloud.describe_volumes(self.context) - self.assertEqual(len(result['volumeSet']), 2) - volume_id = ec2utils.id_to_ec2_vol_id(vol2['id']) - result = self.cloud.describe_volumes(self.context, - volume_id=[volume_id]) - self.assertEqual(len(result['volumeSet']), 1) - self.assertEqual( - ec2utils.ec2_vol_id_to_uuid( - result['volumeSet'][0]['volumeId']), - vol2['id']) - db.volume_destroy(self.context, vol1['id']) - db.volume_destroy(self.context, vol2['id']) - - def test_create_volume_in_availability_zone(self): - """Makes sure create_volume works when we specify an availability - zone - """ - availability_zone = 'zone1:host1' - - result = self.cloud.create_volume(self.context, - size=1, - availability_zone=availability_zone) - volume_id = result['volumeId'] - availabilityZone = result['availabilityZone'] - self.assertEqual(availabilityZone, availability_zone) - result = self.cloud.describe_volumes(self.context) - self.assertEqual(len(result['volumeSet']), 1) - self.assertEqual(result['volumeSet'][0]['volumeId'], volume_id) - self.assertEqual(result['volumeSet'][0]['availabilityZone'], - availabilityZone) - - db.volume_destroy(self.context, ec2utils.ec2_vol_id_to_uuid(volume_id)) - - def test_create_volume_from_snapshot(self): - """Makes sure create_volume works when we specify a snapshot.""" - vol = db.volume_create(self.context, {'size': 1, - 'project_id': self.project_id}) - snap = db.snapshot_create(self.context, {'volume_id': vol['id'], - 'volume_size': vol['size'], - 'status': "available"}) - snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id']) - - result = self.cloud.create_volume(self.context, - snapshot_id=snapshot_id) - volume_id = result['volumeId'] - result = self.cloud.describe_volumes(self.context) - self.assertEqual(len(result['volumeSet']), 2) - self.assertEqual(result['volumeSet'][1]['volumeId'], volume_id) - - db.volume_destroy(self.context, ec2utils.ec2_vol_id_to_uuid(volume_id)) - db.snapshot_destroy(self.context, snap['id']) - db.volume_destroy(self.context, vol['id']) - def test_describe_availability_zones(self): """Makes sure describe_availability_zones works and filters results.""" service1 = db.service_create(self.context, {'host': 'host1_zones', @@ -772,63 +709,10 @@ class CloudTestCase(test.TestCase): result = self.cloud.describe_availability_zones(admin_ctxt, zone_name='verbose') - self.assertEqual(len(result['availabilityZoneInfo']), 15) + self.assertEqual(len(result['availabilityZoneInfo']), 13) db.service_destroy(self.context, service1['id']) db.service_destroy(self.context, service2['id']) - def test_describe_snapshots(self): - """Makes sure describe_snapshots works and filters results.""" - vol = db.volume_create(self.context, {}) - snap1 = db.snapshot_create(self.context, - {'volume_id': vol['id'], 'project_id': self.project_id}) - snap2 = db.snapshot_create(self.context, - {'volume_id': vol['id'], 'project_id': self.project_id}) - result = self.cloud.describe_snapshots(self.context) - self.assertEqual(len(result['snapshotSet']), 2) - snapshot_id = ec2utils.id_to_ec2_snap_id(snap2['id']) - result = self.cloud.describe_snapshots(self.context, - snapshot_id=[snapshot_id]) - self.assertEqual(len(result['snapshotSet']), 1) - self.assertEqual( - ec2utils.ec2_snap_id_to_uuid( - result['snapshotSet'][0]['snapshotId']), - snap2['id']) - db.snapshot_destroy(self.context, snap1['id']) - db.snapshot_destroy(self.context, snap2['id']) - db.volume_destroy(self.context, vol['id']) - - def test_create_snapshot(self): - """Makes sure create_snapshot works.""" - vol = db.volume_create(self.context, - {'status': "available", 'size': 0}) - volume_id = ec2utils.id_to_ec2_vol_id(vol['id']) - - result = self.cloud.create_snapshot(self.context, - volume_id=volume_id) - snapshot_id = result['snapshotId'] - result = self.cloud.describe_snapshots(self.context) - self.assertEqual(len(result['snapshotSet']), 1) - self.assertEqual(result['snapshotSet'][0]['snapshotId'], snapshot_id) - - db.snapshot_destroy(self.context, ec2utils.ec2_id_to_id(snapshot_id)) - db.volume_destroy(self.context, vol['id']) - - def test_delete_snapshot(self): - """Makes sure delete_snapshot works.""" - vol = db.volume_create(self.context, - {'status': "available", 'size': 0}) - snap = db.snapshot_create(self.context, - {'volume_id': vol['id'], - 'status': "available", - 'volume_size': 0}) - snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id']) - - result = self.cloud.delete_snapshot(self.context, - snapshot_id=snapshot_id) - self.assertTrue(result) - - db.volume_destroy(self.context, vol['id']) - def test_describe_instances(self): """Makes sure describe_instances works and filters results.""" self.flags(use_ipv6=True) @@ -1035,189 +919,6 @@ class CloudTestCase(test.TestCase): result = self.cloud.describe_instances(self.context) self.assertEqual(len(result['reservationSet']), 2) - def _block_device_mapping_create(self, instance_uuid, mappings): - volumes = [] - for bdm in mappings: - db.block_device_mapping_create(self.context, bdm) - if 'volume_id' in bdm: - values = {'id': bdm['volume_id']} - for bdm_key, vol_key in [('snapshot_id', 'snapshot_id'), - ('snapshot_size', 'volume_size'), - ('delete_on_termination', - 'delete_on_termination')]: - if bdm_key in bdm: - values[vol_key] = bdm[bdm_key] - vol = db.volume_create(self.context, values) - db.volume_attached(self.context, vol['id'], - instance_uuid, bdm['device_name']) - volumes.append(vol) - return volumes - - def _setUpBlockDeviceMapping(self): - image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175' - inst1 = db.instance_create(self.context, - {'image_ref': image_uuid, - 'instance_type_id': 1, - 'root_device_name': '/dev/sdb1'}) - inst2 = db.instance_create(self.context, - {'image_ref': image_uuid, - 'instance_type_id': 1, - 'root_device_name': '/dev/sdc1'}) - - instance_id = inst1['id'] - instance_uuid = inst1['uuid'] - mappings0 = [ - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb1', - 'snapshot_id': '1', - 'volume_id': '2'}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb2', - 'volume_id': '3', - 'volume_size': 1}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb3', - 'delete_on_termination': True, - 'snapshot_id': '4', - 'volume_id': '5'}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb4', - 'delete_on_termination': False, - 'snapshot_id': '6', - 'volume_id': '7'}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb5', - 'snapshot_id': '8', - 'volume_id': '9', - 'volume_size': 0}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb6', - 'snapshot_id': '10', - 'volume_id': '11', - 'volume_size': 1}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb7', - 'no_device': True}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb8', - 'virtual_name': 'swap'}, - {'instance_uuid': instance_uuid, - 'device_name': '/dev/sdb9', - 'virtual_name': 'ephemeral3'}] - - volumes = self._block_device_mapping_create(instance_uuid, mappings0) - return (inst1, inst2, volumes) - - def _tearDownBlockDeviceMapping(self, inst1, inst2, volumes): - for vol in volumes: - db.volume_destroy(self.context, vol['id']) - for uuid in (inst1['uuid'], inst2['uuid']): - for bdm in db.block_device_mapping_get_all_by_instance( - self.context, uuid): - db.block_device_mapping_destroy(self.context, bdm['id']) - db.instance_destroy(self.context, inst2['uuid']) - db.instance_destroy(self.context, inst1['uuid']) - - _expected_instance_bdm1 = { - 'instanceId': 'i-00000001', - 'rootDeviceName': '/dev/sdb1', - 'rootDeviceType': 'ebs'} - - _expected_block_device_mapping0 = [ - {'deviceName': '/dev/sdb1', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': '2', - }}, - {'deviceName': '/dev/sdb2', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': '3', - }}, - {'deviceName': '/dev/sdb3', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': True, - 'volumeId': '5', - }}, - {'deviceName': '/dev/sdb4', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': '7', - }}, - {'deviceName': '/dev/sdb5', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': '9', - }}, - {'deviceName': '/dev/sdb6', - 'ebs': {'status': 'in-use', - 'deleteOnTermination': False, - 'volumeId': '11', }}] - # NOTE(yamahata): swap/ephemeral device case isn't supported yet. - - _expected_instance_bdm2 = { - 'instanceId': 'i-00000002', - 'rootDeviceName': '/dev/sdc1', - 'rootDeviceType': 'instance-store'} - - def test_format_instance_bdm(self): - (inst1, inst2, volumes) = self._setUpBlockDeviceMapping() - - result = {} - self.cloud._format_instance_bdm(self.context, inst1['uuid'], - '/dev/sdb1', result) - self.assertSubDictMatch( - {'rootDeviceType': self._expected_instance_bdm1['rootDeviceType']}, - result) - self._assertEqualBlockDeviceMapping( - self._expected_block_device_mapping0, result['blockDeviceMapping']) - - result = {} - self.cloud._format_instance_bdm(self.context, inst2['uuid'], - '/dev/sdc1', result) - self.assertSubDictMatch( - {'rootDeviceType': self._expected_instance_bdm2['rootDeviceType']}, - result) - - self._tearDownBlockDeviceMapping(inst1, inst2, volumes) - - def _assertInstance(self, instance_id): - ec2_instance_id = ec2utils.id_to_ec2_inst_id(instance_id) - result = self.cloud.describe_instances(self.context, - instance_id=[ec2_instance_id]) - result = result['reservationSet'][0] - self.assertEqual(len(result['instancesSet']), 1) - result = result['instancesSet'][0] - self.assertEqual(result['instanceId'], ec2_instance_id) - return result - - def _assertEqualBlockDeviceMapping(self, expected, result): - self.assertEqual(len(expected), len(result)) - for x in expected: - found = False - for y in result: - if x['deviceName'] == y['deviceName']: - self.assertSubDictMatch(x, y) - found = True - break - self.assertTrue(found) - - def test_describe_instances_bdm(self): - """Make sure describe_instances works with root_device_name and - block device mappings - """ - (inst1, inst2, volumes) = self._setUpBlockDeviceMapping() - - result = self._assertInstance(inst1['uuid']) - self.assertSubDictMatch(self._expected_instance_bdm1, result) - self._assertEqualBlockDeviceMapping( - self._expected_block_device_mapping0, result['blockDeviceMapping']) - - result = self._assertInstance(inst2['uuid']) - self.assertSubDictMatch(self._expected_instance_bdm2, result) - - self._tearDownBlockDeviceMapping(inst1, inst2, volumes) - def test_describe_images(self): describe_images = self.cloud.describe_images @@ -1281,13 +982,17 @@ class CloudTestCase(test.TestCase): {'device': 'sdc3', 'virtual': 'swap'}, {'device': 'sdc4', 'virtual': 'swap'}] block_device_mapping1 = [ - {'device_name': '/dev/sdb1', 'snapshot_id': 01234567}, - {'device_name': '/dev/sdb2', 'volume_id': 01234567}, + {'device_name': '/dev/sdb1', + 'snapshot_id': 'ccec42a2-c220-4806-b762-6b12fbb592e3'}, + {'device_name': '/dev/sdb2', + 'volume_id': 'ccec42a2-c220-4806-b762-6b12fbb592e4'}, {'device_name': '/dev/sdb3', 'virtual_name': 'ephemeral5'}, {'device_name': '/dev/sdb4', 'no_device': True}, - {'device_name': '/dev/sdc1', 'snapshot_id': 12345678}, - {'device_name': '/dev/sdc2', 'volume_id': 12345678}, + {'device_name': '/dev/sdc1', + 'snapshot_id': 'ccec42a2-c220-4806-b762-6b12fbb592e5'}, + {'device_name': '/dev/sdc2', + 'volume_id': 'ccec42a2-c220-4806-b762-6b12fbb592e6'}, {'device_name': '/dev/sdc3', 'virtual_name': 'ephemeral6'}, {'device_name': '/dev/sdc4', 'no_device': True}] image1 = { @@ -1305,7 +1010,7 @@ class CloudTestCase(test.TestCase): mappings2 = [{'device': '/dev/sda1', 'virtual': 'root'}] block_device_mapping2 = [{'device_name': '/dev/sdb1', - 'snapshot_id': 01234567}] + 'snapshot_id': 'ccec42a2-c220-4806-b762-6b12fbb592e7'}] image2 = { 'id': '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6', 'name': 'fake_name', @@ -1338,11 +1043,7 @@ class CloudTestCase(test.TestCase): vol = self._volume_create(bdm['volume_id']) volumes.append(vol['id']) if 'snapshot_id' in bdm: - snap = db.snapshot_create(self.context, - {'id': bdm['snapshot_id'], - 'volume_id': 01234567, - 'status': "available", - 'volume_size': 1}) + snap = self._snapshot_create(bdm['snapshot_id']) snapshots.append(snap['id']) return (volumes, snapshots) @@ -1364,24 +1065,24 @@ class CloudTestCase(test.TestCase): _expected_bdms1 = [ {'deviceName': '/dev/sdb0', 'virtualName': 'ephemeral0'}, {'deviceName': '/dev/sdb1', 'ebs': {'snapshotId': - 'snap-00053977'}}, + 'snap-00000001'}}, {'deviceName': '/dev/sdb2', 'ebs': {'snapshotId': - 'vol-00053977'}}, + 'vol-00000001'}}, {'deviceName': '/dev/sdb3', 'virtualName': 'ephemeral5'}, # {'deviceName': '/dev/sdb4', 'noDevice': True}, {'deviceName': '/dev/sdc0', 'virtualName': 'swap'}, {'deviceName': '/dev/sdc1', 'ebs': {'snapshotId': - 'snap-00bc614e'}}, + 'snap-00000002'}}, {'deviceName': '/dev/sdc2', 'ebs': {'snapshotId': - 'vol-00bc614e'}}, + 'vol-00000002'}}, {'deviceName': '/dev/sdc3', 'virtualName': 'ephemeral6'}, # {'deviceName': '/dev/sdc4', 'noDevice': True} ] _expected_root_device_name2 = '/dev/sdb1' _expected_bdms2 = [{'deviceName': '/dev/sdb1', - 'ebs': {'snapshotId': 'snap-00053977'}}] + 'ebs': {'snapshotId': 'snap-00000003'}}] # NOTE(yamahata): # InstanceBlockDeviceMappingItemType @@ -2066,228 +1767,30 @@ class CloudTestCase(test.TestCase): self.assertTrue(result) def _volume_create(self, volume_id=None): - location = '10.0.2.15:3260' - iqn = 'iqn.2010-10.org.openstack:%s' % volume_id - kwargs = {'status': 'available', - 'host': self.volume.host, + kwargs = {'name': 'test-volume', + 'description': 'test volume description', + 'status': 'available', + 'host': 'fake', 'size': 1, - 'provider_location': '1 %s,fake %s' % (location, iqn), - 'attach_status': 'detached', } + 'attach_status': 'detached'} if volume_id: - kwargs['id'] = volume_id - return db.volume_create(self.context, kwargs) - - def _assert_volume_attached(self, vol, instance_uuid, mountpoint): - self.assertEqual(vol['instance_uuid'], instance_uuid) - self.assertEqual(vol['mountpoint'], mountpoint) - self.assertEqual(vol['status'], "in-use") - self.assertEqual(vol['attach_status'], "attached") - self.assertNotEqual(vol['attach_time'], None) - - def _assert_volume_detached(self, vol): - self.assertEqual(vol['instance_uuid'], None) - self.assertEqual(vol['mountpoint'], None) - self.assertEqual(vol['status'], "available") - self.assertEqual(vol['attach_status'], "detached") - self.assertEqual(vol['attach_time'], None) - - def test_stop_start_with_volume(self): - """Make sure run instance with block device mapping works""" - - # enforce periodic tasks run in short time to avoid wait for 60s. - self._restart_compute_service(periodic_interval=0.3) - - vol1 = self._volume_create() - vol2 = self._volume_create() - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1, - 'block_device_mapping': [{'device_name': '/dev/vdb', - 'volume_id': vol1['id'], - 'delete_on_termination': False}, - {'device_name': '/dev/vdc', - 'volume_id': vol2['id'], - 'delete_on_termination': True}, - ]} - ec2_instance_id = self._run_instance(**kwargs) - instance_uuid = ec2utils.ec2_instance_id_to_uuid(self.context, - ec2_instance_id) - instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) - - vols = db.volume_get_all_by_instance_uuid(self.context, instance_uuid) - self.assertEqual(len(vols), 2) - for vol in vols: - self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) - - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/vdb') - - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/vdc') - - result = self.cloud.stop_instances(self.context, [ec2_instance_id]) - self.assertTrue(result) - - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/vdb') - - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/vdc') - - self.cloud.start_instances(self.context, [ec2_instance_id]) - vols = db.volume_get_all_by_instance_uuid(self.context, instance_uuid) - self.assertEqual(len(vols), 2) - for vol in vols: - self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) - self.assertTrue(vol['mountpoint'] == '/dev/vdb' or - vol['mountpoint'] == '/dev/vdc') - self.assertEqual(vol['instance_uuid'], instance_uuid) - self.assertEqual(vol['status'], "in-use") - self.assertEqual(vol['attach_status'], "attached") - - self.cloud.terminate_instances(self.context, [ec2_instance_id]) - - admin_ctxt = context.get_admin_context(read_deleted="no") - vol = db.volume_get(admin_ctxt, vol1['id']) - self.assertFalse(vol['deleted']) - db.volume_destroy(self.context, vol1['id']) - - admin_ctxt = context.get_admin_context(read_deleted="only") - vol = db.volume_get(admin_ctxt, vol2['id']) - self.assertTrue(vol['deleted']) - - self._restart_compute_service() - - def test_stop_with_attached_volume(self): - """Make sure attach info is reflected to block device mapping""" - # enforce periodic tasks run in short time to avoid wait for 60s. - self._restart_compute_service(periodic_interval=0.3) - - vol1 = self._volume_create() - vol2 = self._volume_create() - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1, - 'block_device_mapping': [{'device_name': '/dev/sdb', - 'volume_id': vol1['id'], - 'delete_on_termination': True}]} - ec2_instance_id = self._run_instance(**kwargs) - instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) - instance_uuid = ec2utils.ec2_instance_id_to_uuid(self.context, - ec2_instance_id) - - vols = db.volume_get_all_by_instance_uuid(self.context, instance_uuid) - self.assertEqual(len(vols), 1) - for vol in vols: - self.assertEqual(vol['id'], vol1['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/sdb') - - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_detached(vol) - - instance = db.instance_get(self.context, instance_id) - self.cloud.compute_api.attach_volume(self.context, - instance, - volume_id=vol2['id'], - device='/dev/vdc') - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/sdc') - - self.cloud.compute_api.detach_volume(self.context, - volume_id=vol1['id']) - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_detached(vol) - - result = self.cloud.stop_instances(self.context, [ec2_instance_id]) - self.assertTrue(result) - - vol = db.volume_get(self.context, vol2['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/sdc') - - self.cloud.start_instances(self.context, [ec2_instance_id]) - vols = db.volume_get_all_by_instance_uuid(self.context, instance_uuid) - self.assertEqual(len(vols), 1) - for vol in vols: - self.assertEqual(vol['id'], vol2['id']) - self._assert_volume_attached(vol, instance_uuid, '/dev/sdc') - - vol = db.volume_get(self.context, vol1['id']) - self._assert_volume_detached(vol) - - self.cloud.terminate_instances(self.context, [ec2_instance_id]) - - for vol_id in (vol1['id'], vol2['id']): - vol = db.volume_get(self.context, vol_id) - self.assertEqual(vol['id'], vol_id) - self._assert_volume_detached(vol) - db.volume_destroy(self.context, vol_id) - - self._restart_compute_service() + kwargs['volume_id'] = volume_id + return self.volume_api.create_with_kwargs(self.context, **kwargs) + + def _snapshot_create(self, snapshot_id=None): + kwargs = {'volume_id': 'ccec42a2-c220-4806-b762-6b12fbb592e4', + 'status': "available", + 'volume_size': 1} + if snapshot_id: + kwargs['snap_id'] = snapshot_id + return self.volume_api.create_snapshot_with_kwargs(self.context, + **kwargs) def _create_snapshot(self, ec2_volume_id): result = self.cloud.create_snapshot(self.context, volume_id=ec2_volume_id) return result['snapshotId'] - def test_run_with_snapshot(self): - """Makes sure run/stop/start instance with snapshot works.""" - vol = self._volume_create() - ec2_volume_id = ec2utils.id_to_ec2_vol_id(vol['id']) - - ec2_snapshot1_id = self._create_snapshot(ec2_volume_id) - snapshot1_id = ec2utils.ec2_snap_id_to_uuid(ec2_snapshot1_id) - ec2_snapshot2_id = self._create_snapshot(ec2_volume_id) - snapshot2_id = ec2utils.ec2_snap_id_to_uuid(ec2_snapshot2_id) - - kwargs = {'image_id': 'ami-1', - 'instance_type': FLAGS.default_instance_type, - 'max_count': 1, - 'block_device_mapping': [{'device_name': '/dev/vdb', - 'snapshot_id': snapshot1_id, - 'delete_on_termination': False, }, - {'device_name': '/dev/vdc', - 'snapshot_id': snapshot2_id, - 'delete_on_termination': True}]} - ec2_instance_id = self._run_instance(**kwargs) - instance_id = ec2utils.ec2_vol_id_to_uuid(ec2_instance_id) - instance_uuid = ec2utils.ec2_instance_id_to_uuid(self.context, - ec2_instance_id) - - vols = db.volume_get_all_by_instance_uuid(self.context, instance_uuid) - self.assertEqual(len(vols), 2) - vol1_id = None - vol2_id = None - for vol in vols: - snapshot_id = vol['snapshot_id'] - if snapshot_id == snapshot1_id: - vol1_id = vol['id'] - mountpoint = '/dev/vdb' - elif snapshot_id == snapshot2_id: - vol2_id = vol['id'] - mountpoint = '/dev/vdc' - else: - self.fail() - - self._assert_volume_attached(vol, instance_uuid, mountpoint) - - self.assertTrue(vol1_id) - self.assertTrue(vol2_id) - - self.cloud.terminate_instances(self.context, [ec2_instance_id]) - - admin_ctxt = context.get_admin_context(read_deleted="no") - vol = db.volume_get(admin_ctxt, vol1_id) - self._assert_volume_detached(vol) - self.assertFalse(vol['deleted']) - db.volume_destroy(self.context, vol1_id) - - admin_ctxt = context.get_admin_context(read_deleted="only") - vol = db.volume_get(admin_ctxt, vol2_id) - self.assertTrue(vol['deleted']) - - for snapshot_id in (ec2_snapshot1_id, ec2_snapshot2_id): - self.cloud.delete_snapshot(self.context, snapshot_id) - def _do_test_create_image(self, no_reboot): """Make sure that CreateImage works""" # enforce periodic tasks run in short time to avoid wait for 60s. @@ -2363,7 +1866,7 @@ class CloudTestCase(test.TestCase): self.assertEquals(bdm.get('deviceName'), 'sda1') self.assertTrue('ebs' in bdm) self.assertEquals(bdm['ebs'].get('snapshotId'), - 'snap-%08x' % snapshots[0]) + ec2utils.id_to_ec2_snap_id(snapshots[0])) self.assertEquals(created_image.get('kernelId'), 'aki-00000001') self.assertEquals(created_image.get('ramdiskId'), 'ari-00000002') self.assertEquals(created_image.get('rootDeviceType'), 'ebs') @@ -2371,11 +1874,6 @@ class CloudTestCase(test.TestCase): self.assertNotEqual(virt_driver.get('powered_off'), no_reboot) self.cloud.terminate_instances(self.context, [ec2_instance_id]) - for vol in volumes: - db.volume_destroy(self.context, vol) - for snap in snapshots: - db.snapshot_destroy(self.context, snap) - # TODO(yamahata): clean up snapshot created by CreateImage. self._restart_compute_service() diff --git a/nova/tests/api/ec2/test_ec2_validate.py b/nova/tests/api/ec2/test_ec2_validate.py index 9a14a7d7c..f46262c35 100644 --- a/nova/tests/api/ec2/test_ec2_validate.py +++ b/nova/tests/api/ec2/test_ec2_validate.py @@ -50,7 +50,6 @@ class EC2ValidateTestCase(test.TestCase): self.compute = self.start_service('compute') self.scheduter = self.start_service('scheduler') self.network = self.start_service('network') - self.volume = self.start_service('volume') self.image_service = fake.FakeImageService() self.user_id = 'fake' diff --git a/nova/tests/api/openstack/compute/contrib/test_snapshots.py b/nova/tests/api/openstack/compute/contrib/test_snapshots.py index ad259c302..6e76fc04a 100644 --- a/nova/tests/api/openstack/compute/contrib/test_snapshots.py +++ b/nova/tests/api/openstack/compute/contrib/test_snapshots.py @@ -25,7 +25,7 @@ from nova.openstack.common import log as logging from nova.openstack.common import timeutils from nova import test from nova.tests.api.openstack import fakes -from nova import volume +from nova.volume import cinder FLAGS = flags.FLAGS @@ -92,14 +92,16 @@ class SnapshotApiTest(test.TestCase): super(SnapshotApiTest, self).setUp() fakes.stub_out_networking(self.stubs) fakes.stub_out_rate_limiting(self.stubs) - self.stubs.Set(volume.api.API, "create_snapshot", stub_snapshot_create) - self.stubs.Set(volume.api.API, "create_snapshot_force", + self.stubs.Set(cinder.API, "create_snapshot", + stub_snapshot_create) + self.stubs.Set(cinder.API, "create_snapshot_force", stub_snapshot_create) - self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete) - self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get) - self.stubs.Set(volume.api.API, "get_all_snapshots", + self.stubs.Set(cinder.API, "delete_snapshot", + stub_snapshot_delete) + self.stubs.Set(cinder.API, "get_snapshot", stub_snapshot_get) + self.stubs.Set(cinder.API, "get_all_snapshots", stub_snapshot_get_all) - self.stubs.Set(volume.api.API, "get", fakes.stub_volume_get) + self.stubs.Set(cinder.API, "get", fakes.stub_volume_get) self.flags( osapi_compute_extension=[ 'nova.api.openstack.compute.contrib.select_extensions'], diff --git a/nova/tests/api/openstack/compute/contrib/test_volume_types.py b/nova/tests/api/openstack/compute/contrib/test_volume_types.py deleted file mode 100644 index af88cf601..000000000 --- a/nova/tests/api/openstack/compute/contrib/test_volume_types.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from lxml import etree -import webob - -from nova.api.openstack.compute.contrib import volumetypes -from nova import exception -from nova.openstack.common import log as logging -from nova import test -from nova.tests.api.openstack import fakes -from nova.volume import volume_types - - -LOG = logging.getLogger(__name__) -last_param = {} - - -def stub_volume_type(id): - specs = { - "key1": "value1", - "key2": "value2", - "key3": "value3", - "key4": "value4", - "key5": "value5"} - return dict(id=id, name='vol_type_%s' % str(id), extra_specs=specs) - - -def return_volume_types_get_all_types(context): - return dict(vol_type_1=stub_volume_type(1), - vol_type_2=stub_volume_type(2), - vol_type_3=stub_volume_type(3)) - - -def return_empty_volume_types_get_all_types(context): - return {} - - -def return_volume_types_get_volume_type(context, id): - if id == "777": - raise exception.VolumeTypeNotFound(volume_type_id=id) - return stub_volume_type(int(id)) - - -def return_volume_types_destroy(context, name): - if name == "777": - raise exception.VolumeTypeNotFoundByName(volume_type_name=name) - pass - - -def return_volume_types_create(context, name, specs): - pass - - -def return_volume_types_get_by_name(context, name): - if name == "777": - raise exception.VolumeTypeNotFoundByName(volume_type_name=name) - return stub_volume_type(int(name.split("_")[2])) - - -class VolumeTypesApiTest(test.TestCase): - def setUp(self): - super(VolumeTypesApiTest, self).setUp() - fakes.stub_out_key_pair_funcs(self.stubs) - self.controller = volumetypes.VolumeTypesController() - - def test_volume_types_index(self): - self.stubs.Set(volume_types, 'get_all_types', - return_volume_types_get_all_types) - - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types') - res_dict = self.controller.index(req) - - self.assertEqual(3, len(res_dict['volume_types'])) - - expected_names = ['vol_type_1', 'vol_type_2', 'vol_type_3'] - actual_names = map(lambda e: e['name'], res_dict['volume_types']) - self.assertEqual(set(actual_names), set(expected_names)) - for entry in res_dict['volume_types']: - self.assertEqual('value1', entry['extra_specs']['key1']) - - def test_volume_types_index_no_data(self): - self.stubs.Set(volume_types, 'get_all_types', - return_empty_volume_types_get_all_types) - - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types') - res_dict = self.controller.index(req) - - self.assertEqual(0, len(res_dict['volume_types'])) - - def test_volume_types_show(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types/1') - res_dict = self.controller.show(req, 1) - - self.assertEqual(1, len(res_dict)) - self.assertEqual('vol_type_1', res_dict['volume_type']['name']) - - def test_volume_types_show_not_found(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types/777') - self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, - req, '777') - - def test_volume_types_delete(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - self.stubs.Set(volume_types, 'destroy', - return_volume_types_destroy) - - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types/1') - self.controller.delete(req, 1) - - def test_volume_types_delete_not_found(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - self.stubs.Set(volume_types, 'destroy', - return_volume_types_destroy) - - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types/777') - self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, - req, '777') - - def test_create(self): - self.stubs.Set(volume_types, 'create', - return_volume_types_create) - self.stubs.Set(volume_types, 'get_volume_type_by_name', - return_volume_types_get_by_name) - - body = {"volume_type": {"name": "vol_type_1", - "extra_specs": {"key1": "value1"}}} - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types') - res_dict = self.controller.create(req, body) - - self.assertEqual(1, len(res_dict)) - self.assertEqual('vol_type_1', res_dict['volume_type']['name']) - - -class VolumeTypesSerializerTest(test.TestCase): - def _verify_volume_type(self, vtype, tree): - self.assertEqual('volume_type', tree.tag) - self.assertEqual(vtype['name'], tree.get('name')) - self.assertEqual(str(vtype['id']), tree.get('id')) - self.assertEqual(1, len(tree)) - extra_specs = tree[0] - self.assertEqual('extra_specs', extra_specs.tag) - seen = set(vtype['extra_specs'].keys()) - for child in extra_specs: - self.assertTrue(child.tag in seen) - self.assertEqual(vtype['extra_specs'][child.tag], child.text) - seen.remove(child.tag) - self.assertEqual(len(seen), 0) - - def test_index_serializer(self): - serializer = volumetypes.VolumeTypesTemplate() - - # Just getting some input data - vtypes = return_volume_types_get_all_types(None) - text = serializer.serialize({'volume_types': vtypes.values()}) - - print text - tree = etree.fromstring(text) - - self.assertEqual('volume_types', tree.tag) - self.assertEqual(len(vtypes), len(tree)) - for child in tree: - name = child.get('name') - self.assertTrue(name in vtypes) - self._verify_volume_type(vtypes[name], child) - - def test_voltype_serializer(self): - serializer = volumetypes.VolumeTypeTemplate() - - vtype = stub_volume_type(1) - text = serializer.serialize(dict(volume_type=vtype)) - - print text - tree = etree.fromstring(text) - - self._verify_volume_type(vtype, tree) - - -class VolumeTypesUnprocessableEntityTestCase(test.TestCase): - """ - Tests of places we throw 422 Unprocessable Entity from - """ - - def setUp(self): - super(VolumeTypesUnprocessableEntityTestCase, self).setUp() - self.controller = volumetypes.VolumeTypesController() - - def _unprocessable_volume_type_create(self, body): - req = fakes.HTTPRequest.blank('/v2/fake/os-volume-types') - req.method = 'POST' - - self.assertRaises(webob.exc.HTTPUnprocessableEntity, - self.controller.create, req, body) - - def test_create_volume_type_no_body(self): - self._unprocessable_volume_type_create(body=None) - - def test_create_volume_type_missing_volume_type(self): - body = {'foo': {'a': 'b'}} - self._unprocessable_volume_type_create(body=body) - - def test_create_volume_type_malformed_entity(self): - body = {'volume_type': 'string'} - self._unprocessable_volume_type_create(body=body) diff --git a/nova/tests/api/openstack/compute/contrib/test_volume_types_extra_specs.py b/nova/tests/api/openstack/compute/contrib/test_volume_types_extra_specs.py deleted file mode 100644 index e9c4034f0..000000000 --- a/nova/tests/api/openstack/compute/contrib/test_volume_types_extra_specs.py +++ /dev/null @@ -1,198 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 Zadara Storage Inc. -# Copyright (c) 2011 OpenStack LLC. -# Copyright 2011 University of Southern California -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from lxml import etree -import webob - -from nova.api.openstack.compute.contrib import volumetypes -from nova import test -from nova.tests.api.openstack import fakes -import nova.wsgi - - -def return_create_volume_type_extra_specs(context, volume_type_id, - extra_specs): - return stub_volume_type_extra_specs() - - -def return_volume_type_extra_specs(context, volume_type_id): - return stub_volume_type_extra_specs() - - -def return_empty_volume_type_extra_specs(context, volume_type_id): - return {} - - -def delete_volume_type_extra_specs(context, volume_type_id, key): - pass - - -def stub_volume_type_extra_specs(): - specs = { - "key1": "value1", - "key2": "value2", - "key3": "value3", - "key4": "value4", - "key5": "value5"} - return specs - - -class VolumeTypesExtraSpecsTest(test.TestCase): - - def setUp(self): - super(VolumeTypesExtraSpecsTest, self).setUp() - fakes.stub_out_key_pair_funcs(self.stubs) - self.api_path = '/v2/fake/os-volume-types/1/extra_specs' - self.controller = volumetypes.VolumeTypeExtraSpecsController() - - def test_index(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path) - res_dict = self.controller.index(req, 1) - - self.assertEqual('value1', res_dict['extra_specs']['key1']) - - def test_index_no_data(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_empty_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path) - res_dict = self.controller.index(req, 1) - - self.assertEqual(0, len(res_dict['extra_specs'])) - - def test_show(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path + '/key5') - res_dict = self.controller.show(req, 1, 'key5') - - self.assertEqual('value5', res_dict['key5']) - - def test_show_spec_not_found(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_empty_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path + '/key6') - self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, - req, 1, 'key6') - - def test_delete(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_delete', - delete_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path + '/key5') - self.controller.delete(req, 1, 'key5') - - def test_create(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"extra_specs": {"key1": "value1"}} - - req = fakes.HTTPRequest.blank(self.api_path) - res_dict = self.controller.create(req, 1, body) - - self.assertEqual('value1', res_dict['extra_specs']['key1']) - - def test_create_empty_body(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path) - self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, - req, 1, '') - - def test_update_item(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"key1": "value1"} - - req = fakes.HTTPRequest.blank(self.api_path + '/key1') - res_dict = self.controller.update(req, 1, 'key1', body) - - self.assertEqual('value1', res_dict['key1']) - - def test_update_item_empty_body(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path + '/key1') - self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update, - req, 1, 'key1', '') - - def test_update_item_too_many_keys(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"key1": "value1", "key2": "value2"} - - req = fakes.HTTPRequest.blank(self.api_path + '/key1') - self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update, - req, 1, 'key1', body) - - def test_update_item_body_uri_mismatch(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"key1": "value1"} - - req = fakes.HTTPRequest.blank(self.api_path + '/bad') - self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update, - req, 1, 'bad', body) - - -class VolumeTypeExtraSpecsSerializerTest(test.TestCase): - def test_index_create_serializer(self): - serializer = volumetypes.VolumeTypeExtraSpecsTemplate() - - # Just getting some input data - extra_specs = stub_volume_type_extra_specs() - text = serializer.serialize(dict(extra_specs=extra_specs)) - - print text - tree = etree.fromstring(text) - - self.assertEqual('extra_specs', tree.tag) - self.assertEqual(len(extra_specs), len(tree)) - seen = set(extra_specs.keys()) - for child in tree: - self.assertTrue(child.tag in seen) - self.assertEqual(extra_specs[child.tag], child.text) - seen.remove(child.tag) - self.assertEqual(len(seen), 0) - - def test_update_show_serializer(self): - serializer = volumetypes.VolumeTypeExtraSpecTemplate() - - exemplar = dict(key1='value1') - text = serializer.serialize(exemplar) - - print text - tree = etree.fromstring(text) - - self.assertEqual('key1', tree.tag) - self.assertEqual('value1', tree.text) - self.assertEqual(0, len(tree)) diff --git a/nova/tests/api/openstack/compute/contrib/test_volumes.py b/nova/tests/api/openstack/compute/contrib/test_volumes.py index a07c3fa74..6c092cbd4 100644 --- a/nova/tests/api/openstack/compute/contrib/test_volumes.py +++ b/nova/tests/api/openstack/compute/contrib/test_volumes.py @@ -18,7 +18,6 @@ import datetime from lxml import etree import webob -import nova from nova.api.openstack.compute.contrib import volumes from nova.compute import api as compute_api from nova.compute import instance_types @@ -29,7 +28,7 @@ from nova.openstack.common import jsonutils from nova.openstack.common import timeutils from nova import test from nova.tests.api.openstack import fakes -from nova.volume import api as volume_api +from nova.volume import cinder from webob import exc @@ -148,9 +147,9 @@ class VolumeApiTest(test.TestCase): fakes.stub_out_rate_limiting(self.stubs) self.stubs.Set(db, 'volume_get', return_volume) - self.stubs.Set(volume_api.API, "delete", fakes.stub_volume_delete) - self.stubs.Set(volume_api.API, "get", fakes.stub_volume_get) - self.stubs.Set(volume_api.API, "get_all", fakes.stub_volume_get_all) + self.stubs.Set(cinder.API, "delete", fakes.stub_volume_delete) + self.stubs.Set(cinder.API, "get", fakes.stub_volume_get) + self.stubs.Set(cinder.API, "get_all", fakes.stub_volume_get_all) self.flags( osapi_compute_extension=[ 'nova.api.openstack.compute.contrib.select_extensions'], @@ -160,7 +159,7 @@ class VolumeApiTest(test.TestCase): self.app = fakes.wsgi_app(init_only=('os-volumes',)) def test_volume_create(self): - self.stubs.Set(volume_api.API, "create", fakes.stub_volume_create) + self.stubs.Set(cinder.API, "create", fakes.stub_volume_create) vol = {"size": 100, "display_name": "Volume Test Name", @@ -202,7 +201,7 @@ class VolumeApiTest(test.TestCase): self.assertEqual(resp.status_int, 200) def test_volume_show_no_volume(self): - self.stubs.Set(volume_api.API, "get", fakes.stub_volume_get_notfound) + self.stubs.Set(cinder.API, "get", fakes.stub_volume_get_notfound) req = webob.Request.blank('/v2/fake/os-volumes/456') resp = req.get_response(self.app) @@ -215,7 +214,7 @@ class VolumeApiTest(test.TestCase): self.assertEqual(resp.status_int, 202) def test_volume_delete_no_volume(self): - self.stubs.Set(volume_api.API, "get", fakes.stub_volume_get_notfound) + self.stubs.Set(cinder.API, "get", fakes.stub_volume_get_notfound) req = webob.Request.blank('/v2/fake/os-volumes/456') req.method = 'DELETE' diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py index e07db3519..466fd3636 100644 --- a/nova/tests/api/openstack/compute/test_extensions.py +++ b/nova/tests/api/openstack/compute/test_extensions.py @@ -194,7 +194,6 @@ class ExtensionControllerTest(ExtensionTestCase): "UserData", "VirtualInterfaces", "Volumes", - "VolumeTypes", ] self.ext_list.sort() diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index 58dc2df45..4f39e569e 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -30,7 +30,6 @@ from nova.api.openstack import compute from nova.api.openstack.compute import limits from nova.api.openstack.compute import versions from nova.api.openstack import urlmap -from nova.api.openstack import volume from nova.api.openstack import wsgi as os_wsgi from nova.compute import api as compute_api from nova.compute import instance_types diff --git a/nova/tests/api/openstack/volume/__init__.py b/nova/tests/api/openstack/volume/__init__.py deleted file mode 100644 index 7e04e7c73..000000000 --- a/nova/tests/api/openstack/volume/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# 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. - -# NOTE(vish): this forces the fixtures from tests/__init.py:setup() to work -from nova.tests import * diff --git a/nova/tests/api/openstack/volume/contrib/__init__.py b/nova/tests/api/openstack/volume/contrib/__init__.py deleted file mode 100644 index 7e04e7c73..000000000 --- a/nova/tests/api/openstack/volume/contrib/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# 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. - -# NOTE(vish): this forces the fixtures from tests/__init.py:setup() to work -from nova.tests import * diff --git a/nova/tests/api/openstack/volume/contrib/test_admin_actions.py b/nova/tests/api/openstack/volume/contrib/test_admin_actions.py deleted file mode 100644 index 4ade54779..000000000 --- a/nova/tests/api/openstack/volume/contrib/test_admin_actions.py +++ /dev/null @@ -1,184 +0,0 @@ -import webob - -from nova import context -from nova import db -from nova import exception -from nova.openstack.common import jsonutils -from nova import test -from nova.tests.api.openstack import fakes - - -def app(): - # no auth, just let environ['nova.context'] pass through - api = fakes.volume.APIRouter(init_only=('volumes', 'snapshots')) - mapper = fakes.urlmap.URLMap() - mapper['/v1'] = api - return mapper - - -class AdminActionsTest(test.TestCase): - - def test_reset_status_as_admin(self): - # admin context - ctx = context.RequestContext('admin', 'fake', is_admin=True) - ctx.elevated() # add roles - # current status is available - volume = db.volume_create(ctx, {'status': 'available'}) - req = webob.Request.blank('/v1/fake/volumes/%s/action' % volume['id']) - req.method = 'POST' - req.headers['content-type'] = 'application/json' - # request status of 'error' - req.body = jsonutils.dumps({'os-reset_status': {'status': 'error'}}) - # attach admin context to request - req.environ['nova.context'] = ctx - resp = req.get_response(app()) - # request is accepted - self.assertEquals(resp.status_int, 202) - volume = db.volume_get(ctx, volume['id']) - # status changed to 'error' - self.assertEquals(volume['status'], 'error') - - def test_reset_status_as_non_admin(self): - # current status is 'error' - volume = db.volume_create(context.get_admin_context(), - {'status': 'error'}) - req = webob.Request.blank('/v1/fake/volumes/%s/action' % volume['id']) - req.method = 'POST' - req.headers['content-type'] = 'application/json' - # request changing status to available - req.body = jsonutils.dumps({'os-reset_status': {'status': - 'available'}}) - # non-admin context - req.environ['nova.context'] = context.RequestContext('fake', 'fake') - resp = req.get_response(app()) - # request is not authorized - self.assertEquals(resp.status_int, 403) - volume = db.volume_get(context.get_admin_context(), volume['id']) - # status is still 'error' - self.assertEquals(volume['status'], 'error') - - def test_malformed_reset_status_body(self): - # admin context - ctx = context.RequestContext('admin', 'fake', is_admin=True) - ctx.elevated() # add roles - # current status is available - volume = db.volume_create(ctx, {'status': 'available'}) - req = webob.Request.blank('/v1/fake/volumes/%s/action' % volume['id']) - req.method = 'POST' - req.headers['content-type'] = 'application/json' - # malformed request body - req.body = jsonutils.dumps({'os-reset_status': {'x-status': 'bad'}}) - # attach admin context to request - req.environ['nova.context'] = ctx - resp = req.get_response(app()) - # bad request - self.assertEquals(resp.status_int, 400) - volume = db.volume_get(ctx, volume['id']) - # status is still 'available' - self.assertEquals(volume['status'], 'available') - - def test_invalid_status_for_volume(self): - # admin context - ctx = context.RequestContext('admin', 'fake', is_admin=True) - ctx.elevated() # add roles - # current status is available - volume = db.volume_create(ctx, {'status': 'available'}) - req = webob.Request.blank('/v1/fake/volumes/%s/action' % volume['id']) - req.method = 'POST' - req.headers['content-type'] = 'application/json' - # 'invalid' is not a valid status - req.body = jsonutils.dumps({'os-reset_status': {'status': 'invalid'}}) - # attach admin context to request - req.environ['nova.context'] = ctx - resp = req.get_response(app()) - # bad request - self.assertEquals(resp.status_int, 400) - volume = db.volume_get(ctx, volume['id']) - # status is still 'available' - self.assertEquals(volume['status'], 'available') - - def test_reset_status_for_missing_volume(self): - # admin context - ctx = context.RequestContext('admin', 'fake', is_admin=True) - ctx.elevated() # add roles - # missing-volume-id - req = webob.Request.blank('/v1/fake/volumes/%s/action' % - 'missing-volume-id') - req.method = 'POST' - req.headers['content-type'] = 'application/json' - # malformed request body - req.body = jsonutils.dumps({'os-reset_status': {'status': - 'available'}}) - # attach admin context to request - req.environ['nova.context'] = ctx - resp = req.get_response(app()) - # not found - self.assertEquals(resp.status_int, 404) - self.assertRaises(exception.NotFound, db.volume_get, ctx, - 'missing-volume-id') - - def test_snapshot_reset_status(self): - # admin context - ctx = context.RequestContext('admin', 'fake', is_admin=True) - ctx.elevated() # add roles - # snapshot in 'error_deleting' - volume = db.volume_create(ctx, {}) - snapshot = db.snapshot_create(ctx, {'status': 'error_deleting', - 'volume_id': volume['id']}) - req = webob.Request.blank('/v1/fake/snapshots/%s/action' % - snapshot['id']) - req.method = 'POST' - req.headers['content-type'] = 'application/json' - # request status of 'error' - req.body = jsonutils.dumps({'os-reset_status': {'status': 'error'}}) - # attach admin context to request - req.environ['nova.context'] = ctx - resp = req.get_response(app()) - # request is accepted - self.assertEquals(resp.status_int, 202) - snapshot = db.snapshot_get(ctx, snapshot['id']) - # status changed to 'error' - self.assertEquals(snapshot['status'], 'error') - - def test_invalid_status_for_snapshot(self): - # admin context - ctx = context.RequestContext('admin', 'fake', is_admin=True) - ctx.elevated() # add roles - # snapshot in 'available' - volume = db.volume_create(ctx, {}) - snapshot = db.snapshot_create(ctx, {'status': 'available', - 'volume_id': volume['id']}) - req = webob.Request.blank('/v1/fake/snapshots/%s/action' % - snapshot['id']) - req.method = 'POST' - req.headers['content-type'] = 'application/json' - # 'attaching' is not a valid status for snapshots - req.body = jsonutils.dumps({'os-reset_status': {'status': - 'attaching'}}) - # attach admin context to request - req.environ['nova.context'] = ctx - resp = req.get_response(app()) - # request is accepted - print resp - self.assertEquals(resp.status_int, 400) - snapshot = db.snapshot_get(ctx, snapshot['id']) - # status is still 'available' - self.assertEquals(snapshot['status'], 'available') - - def test_force_delete(self): - # admin context - ctx = context.RequestContext('admin', 'fake', is_admin=True) - ctx.elevated() # add roles - # current status is creating - volume = db.volume_create(ctx, {'status': 'creating'}) - req = webob.Request.blank('/v1/fake/volumes/%s/action' % volume['id']) - req.method = 'POST' - req.headers['content-type'] = 'application/json' - req.body = jsonutils.dumps({'os-force_delete': {}}) - # attach admin context to request - req.environ['nova.context'] = ctx - resp = req.get_response(app()) - # request is accepted - self.assertEquals(resp.status_int, 202) - # volume is deleted - self.assertRaises(exception.NotFound, db.volume_get, ctx, volume['id']) diff --git a/nova/tests/api/openstack/volume/contrib/test_types_extra_specs.py b/nova/tests/api/openstack/volume/contrib/test_types_extra_specs.py deleted file mode 100644 index edc127b8a..000000000 --- a/nova/tests/api/openstack/volume/contrib/test_types_extra_specs.py +++ /dev/null @@ -1,226 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 Zadara Storage Inc. -# Copyright (c) 2011 OpenStack LLC. -# Copyright 2011 University of Southern California -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from lxml import etree -import webob - -from nova.api.openstack.volume.contrib import types_extra_specs -from nova import test -from nova.tests.api.openstack import fakes -import nova.wsgi - - -def return_create_volume_type_extra_specs(context, volume_type_id, - extra_specs): - return stub_volume_type_extra_specs() - - -def return_volume_type_extra_specs(context, volume_type_id): - return stub_volume_type_extra_specs() - - -def return_empty_volume_type_extra_specs(context, volume_type_id): - return {} - - -def delete_volume_type_extra_specs(context, volume_type_id, key): - pass - - -def stub_volume_type_extra_specs(): - specs = { - "key1": "value1", - "key2": "value2", - "key3": "value3", - "key4": "value4", - "key5": "value5"} - return specs - - -def volume_type_get(context, volume_type_id): - pass - - -class VolumeTypesExtraSpecsTest(test.TestCase): - - def setUp(self): - super(VolumeTypesExtraSpecsTest, self).setUp() - self.stubs.Set(nova.db, 'volume_type_get', volume_type_get) - self.api_path = '/v1/fake/os-volume-types/1/extra_specs' - self.controller = types_extra_specs.VolumeTypeExtraSpecsController() - - def test_index(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path) - res_dict = self.controller.index(req, 1) - - self.assertEqual('value1', res_dict['extra_specs']['key1']) - - def test_index_no_data(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_empty_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path) - res_dict = self.controller.index(req, 1) - - self.assertEqual(0, len(res_dict['extra_specs'])) - - def test_show(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path + '/key5') - res_dict = self.controller.show(req, 1, 'key5') - - self.assertEqual('value5', res_dict['key5']) - - def test_show_spec_not_found(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_get', - return_empty_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path + '/key6') - self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, - req, 1, 'key6') - - def test_delete(self): - self.stubs.Set(nova.db, 'volume_type_extra_specs_delete', - delete_volume_type_extra_specs) - - req = fakes.HTTPRequest.blank(self.api_path + '/key5') - self.controller.delete(req, 1, 'key5') - - def test_create(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"extra_specs": {"key1": "value1"}} - - req = fakes.HTTPRequest.blank(self.api_path) - res_dict = self.controller.create(req, 1, body) - - self.assertEqual('value1', res_dict['extra_specs']['key1']) - - def test_update_item(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"key1": "value1"} - - req = fakes.HTTPRequest.blank(self.api_path + '/key1') - res_dict = self.controller.update(req, 1, 'key1', body) - - self.assertEqual('value1', res_dict['key1']) - - def test_update_item_too_many_keys(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"key1": "value1", "key2": "value2"} - - req = fakes.HTTPRequest.blank(self.api_path + '/key1') - self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update, - req, 1, 'key1', body) - - def test_update_item_body_uri_mismatch(self): - self.stubs.Set(nova.db, - 'volume_type_extra_specs_update_or_create', - return_create_volume_type_extra_specs) - body = {"key1": "value1"} - - req = fakes.HTTPRequest.blank(self.api_path + '/bad') - self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update, - req, 1, 'bad', body) - - -class VolumeTypeExtraSpecsSerializerTest(test.TestCase): - def test_index_create_serializer(self): - serializer = types_extra_specs.VolumeTypeExtraSpecsTemplate() - - # Just getting some input data - extra_specs = stub_volume_type_extra_specs() - text = serializer.serialize(dict(extra_specs=extra_specs)) - - print text - tree = etree.fromstring(text) - - self.assertEqual('extra_specs', tree.tag) - self.assertEqual(len(extra_specs), len(tree)) - seen = set(extra_specs.keys()) - for child in tree: - self.assertTrue(child.tag in seen) - self.assertEqual(extra_specs[child.tag], child.text) - seen.remove(child.tag) - self.assertEqual(len(seen), 0) - - def test_update_show_serializer(self): - serializer = types_extra_specs.VolumeTypeExtraSpecTemplate() - - exemplar = dict(key1='value1') - text = serializer.serialize(exemplar) - - print text - tree = etree.fromstring(text) - - self.assertEqual('key1', tree.tag) - self.assertEqual('value1', tree.text) - self.assertEqual(0, len(tree)) - - -class VolumeTypeExtraSpecsUnprocessableEntityTestCase(test.TestCase): - - """ - Tests of places we throw 422 Unprocessable Entity from - """ - - def setUp(self): - super(VolumeTypeExtraSpecsUnprocessableEntityTestCase, self).setUp() - self.controller = types_extra_specs.VolumeTypeExtraSpecsController() - - def _unprocessable_extra_specs_create(self, body): - req = fakes.HTTPRequest.blank('/v2/fake/types/1/extra_specs') - req.method = 'POST' - - self.assertRaises(webob.exc.HTTPUnprocessableEntity, - self.controller.create, req, '1', body) - - def test_create_no_body(self): - self._unprocessable_extra_specs_create(body=None) - - def test_create_missing_volume(self): - body = {'foo': {'a': 'b'}} - self._unprocessable_extra_specs_create(body=body) - - def test_create_malformed_entity(self): - body = {'extra_specs': 'string'} - self._unprocessable_extra_specs_create(body=body) - - def _unprocessable_extra_specs_update(self, body): - req = fakes.HTTPRequest.blank('/v2/fake/types/1/extra_specs') - req.method = 'POST' - - self.assertRaises(webob.exc.HTTPUnprocessableEntity, - self.controller.update, req, '1', body) - - def test_update_no_body(self): - self._unprocessable_extra_specs_update(body=None) - - def test_update_empty_body(self): - self._unprocessable_extra_specs_update(body={}) diff --git a/nova/tests/api/openstack/volume/contrib/test_types_manage.py b/nova/tests/api/openstack/volume/contrib/test_types_manage.py deleted file mode 100644 index f69038144..000000000 --- a/nova/tests/api/openstack/volume/contrib/test_types_manage.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# 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 webob - -from nova.api.openstack.volume.contrib import types_manage -from nova import exception -from nova import test -from nova.tests.api.openstack import fakes -from nova.volume import volume_types - - -def stub_volume_type(id): - specs = { - "key1": "value1", - "key2": "value2", - "key3": "value3", - "key4": "value4", - "key5": "value5"} - return dict(id=id, name='vol_type_%s' % str(id), extra_specs=specs) - - -def return_volume_types_get_volume_type(context, id): - if id == "777": - raise exception.VolumeTypeNotFound(volume_type_id=id) - return stub_volume_type(int(id)) - - -def return_volume_types_destroy(context, name): - if name == "777": - raise exception.VolumeTypeNotFoundByName(volume_type_name=name) - pass - - -def return_volume_types_create(context, name, specs): - pass - - -def return_volume_types_get_by_name(context, name): - if name == "777": - raise exception.VolumeTypeNotFoundByName(volume_type_name=name) - return stub_volume_type(int(name.split("_")[2])) - - -class VolumeTypesManageApiTest(test.TestCase): - def setUp(self): - super(VolumeTypesManageApiTest, self).setUp() - self.controller = types_manage.VolumeTypesManageController() - - def test_volume_types_delete(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - self.stubs.Set(volume_types, 'destroy', - return_volume_types_destroy) - - req = fakes.HTTPRequest.blank('/v1/fake/types/1') - self.controller._delete(req, 1) - - def test_volume_types_delete_not_found(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - self.stubs.Set(volume_types, 'destroy', - return_volume_types_destroy) - - req = fakes.HTTPRequest.blank('/v1/fake/types/777') - self.assertRaises(webob.exc.HTTPNotFound, self.controller._delete, - req, '777') - - def test_create(self): - self.stubs.Set(volume_types, 'create', - return_volume_types_create) - self.stubs.Set(volume_types, 'get_volume_type_by_name', - return_volume_types_get_by_name) - - body = {"volume_type": {"name": "vol_type_1", - "extra_specs": {"key1": "value1"}}} - req = fakes.HTTPRequest.blank('/v1/fake/types') - res_dict = self.controller._create(req, body) - - self.assertEqual(1, len(res_dict)) - self.assertEqual('vol_type_1', res_dict['volume_type']['name']) - - -class VolumeTypesUnprocessableEntityTestCase(test.TestCase): - - """ - Tests of places we throw 422 Unprocessable Entity from - """ - - def setUp(self): - super(VolumeTypesUnprocessableEntityTestCase, self).setUp() - self.controller = types_manage.VolumeTypesManageController() - - def _unprocessable_volume_type_create(self, body): - req = fakes.HTTPRequest.blank('/v2/fake/types') - req.method = 'POST' - - self.assertRaises(webob.exc.HTTPUnprocessableEntity, - self.controller._create, req, body) - - def test_create_no_body(self): - self._unprocessable_volume_type_create(body=None) - - def test_create_missing_volume(self): - body = {'foo': {'a': 'b'}} - self._unprocessable_volume_type_create(body=body) - - def test_create_malformed_entity(self): - body = {'volume_type': 'string'} - self._unprocessable_volume_type_create(body=body) diff --git a/nova/tests/api/openstack/volume/contrib/test_volume_actions.py b/nova/tests/api/openstack/volume/contrib/test_volume_actions.py deleted file mode 100644 index 4dd79d366..000000000 --- a/nova/tests/api/openstack/volume/contrib/test_volume_actions.py +++ /dev/null @@ -1,162 +0,0 @@ -# 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/extensions/__init__.py b/nova/tests/api/openstack/volume/extensions/__init__.py deleted file mode 100644 index 848908a95..000000000 --- a/nova/tests/api/openstack/volume/extensions/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 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. diff --git a/nova/tests/api/openstack/volume/extensions/foxinsocks.py b/nova/tests/api/openstack/volume/extensions/foxinsocks.py deleted file mode 100644 index cf901472c..000000000 --- a/nova/tests/api/openstack/volume/extensions/foxinsocks.py +++ /dev/null @@ -1,94 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# 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 webob.exc - -from nova.api.openstack import extensions -from nova.api.openstack import wsgi - - -class FoxInSocksController(object): - - def index(self, req): - return "Try to say this Mr. Knox, sir..." - - -class FoxInSocksServerControllerExtension(wsgi.Controller): - @wsgi.action('add_tweedle') - def _add_tweedle(self, req, id, body): - - return "Tweedle Beetle Added." - - @wsgi.action('delete_tweedle') - def _delete_tweedle(self, req, id, body): - - return "Tweedle Beetle Deleted." - - @wsgi.action('fail') - def _fail(self, req, id, body): - - raise webob.exc.HTTPBadRequest(explanation='Tweedle fail') - - -class FoxInSocksFlavorGooseControllerExtension(wsgi.Controller): - @wsgi.extends - def show(self, req, resp_obj, id): - #NOTE: This only handles JSON responses. - # You can use content type header to test for XML. - resp_obj.obj['flavor']['googoose'] = req.GET.get('chewing') - - -class FoxInSocksFlavorBandsControllerExtension(wsgi.Controller): - @wsgi.extends - def show(self, req, resp_obj, id): - #NOTE: This only handles JSON responses. - # You can use content type header to test for XML. - resp_obj.obj['big_bands'] = 'Pig Bands!' - - -class Foxinsocks(extensions.ExtensionDescriptor): - """The Fox In Socks Extension""" - - name = "Fox In Socks" - alias = "FOXNSOX" - namespace = "http://www.fox.in.socks/api/ext/pie/v1.0" - updated = "2011-01-22T13:25:27-06:00" - - def __init__(self, ext_mgr): - ext_mgr.register(self) - - def get_resources(self): - resources = [] - resource = extensions.ResourceExtension('foxnsocks', - FoxInSocksController()) - resources.append(resource) - return resources - - def get_controller_extensions(self): - extension_list = [] - - extension_set = [ - (FoxInSocksServerControllerExtension, 'servers'), - (FoxInSocksFlavorGooseControllerExtension, 'flavors'), - (FoxInSocksFlavorBandsControllerExtension, 'flavors'), - ] - for klass, collection in extension_set: - controller = klass() - ext = extensions.ControllerExtension(self, collection, controller) - extension_list.append(ext) - - return extension_list diff --git a/nova/tests/api/openstack/volume/test_extensions.py b/nova/tests/api/openstack/volume/test_extensions.py deleted file mode 100644 index e291e74dd..000000000 --- a/nova/tests/api/openstack/volume/test_extensions.py +++ /dev/null @@ -1,155 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# 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 iso8601 -from lxml import etree -import webob - -from nova.api.openstack import volume -from nova.api.openstack import xmlutil -from nova import flags -from nova.openstack.common import jsonutils -from nova import test - -FLAGS = flags.FLAGS -NS = "{http://docs.openstack.org/common/api/v1.0}" - - -class ExtensionTestCase(test.TestCase): - def setUp(self): - super(ExtensionTestCase, self).setUp() - ext_list = FLAGS.osapi_volume_extension[:] - fox = ('nova.tests.api.openstack.volume.extensions.' - 'foxinsocks.Foxinsocks') - if fox not in ext_list: - ext_list.append(fox) - self.flags(osapi_volume_extension=ext_list) - - -class ExtensionControllerTest(ExtensionTestCase): - - def setUp(self): - super(ExtensionControllerTest, self).setUp() - self.ext_list = [ - "TypesManage", - "TypesExtraSpecs", - ] - self.ext_list.sort() - - def test_list_extensions_json(self): - app = volume.APIRouter() - request = webob.Request.blank("/fake/extensions") - response = request.get_response(app) - self.assertEqual(200, response.status_int) - - # Make sure we have all the extensions, extra extensions being OK. - data = jsonutils.loads(response.body) - names = [str(x['name']) for x in data['extensions'] - if str(x['name']) in self.ext_list] - names.sort() - self.assertEqual(names, self.ext_list) - - # Ensure all the timestamps are valid according to iso8601 - for ext in data['extensions']: - iso8601.parse_date(ext['updated']) - - # Make sure that at least Fox in Sox is correct. - (fox_ext, ) = [ - x for x in data['extensions'] if x['alias'] == 'FOXNSOX'] - self.assertEqual(fox_ext, { - 'namespace': 'http://www.fox.in.socks/api/ext/pie/v1.0', - 'name': 'Fox In Socks', - 'updated': '2011-01-22T13:25:27-06:00', - 'description': 'The Fox In Socks Extension', - 'alias': 'FOXNSOX', - 'links': [] - }, - ) - - for ext in data['extensions']: - url = '/fake/extensions/%s' % ext['alias'] - request = webob.Request.blank(url) - response = request.get_response(app) - output = jsonutils.loads(response.body) - self.assertEqual(output['extension']['alias'], ext['alias']) - - def test_get_extension_json(self): - app = volume.APIRouter() - request = webob.Request.blank("/fake/extensions/FOXNSOX") - response = request.get_response(app) - self.assertEqual(200, response.status_int) - - data = jsonutils.loads(response.body) - self.assertEqual(data['extension'], { - "namespace": "http://www.fox.in.socks/api/ext/pie/v1.0", - "name": "Fox In Socks", - "updated": "2011-01-22T13:25:27-06:00", - "description": "The Fox In Socks Extension", - "alias": "FOXNSOX", - "links": []}) - - def test_get_non_existing_extension_json(self): - app = volume.APIRouter() - request = webob.Request.blank("/fake/extensions/4") - response = request.get_response(app) - self.assertEqual(404, response.status_int) - - def test_list_extensions_xml(self): - app = volume.APIRouter() - request = webob.Request.blank("/fake/extensions") - request.accept = "application/xml" - response = request.get_response(app) - self.assertEqual(200, response.status_int) - - root = etree.XML(response.body) - self.assertEqual(root.tag.split('extensions')[0], NS) - - # Make sure we have all the extensions, extras extensions being OK. - exts = root.findall('{0}extension'.format(NS)) - self.assert_(len(exts) >= len(self.ext_list)) - - # Make sure that at least Fox in Sox is correct. - (fox_ext, ) = [x for x in exts if x.get('alias') == 'FOXNSOX'] - self.assertEqual(fox_ext.get('name'), 'Fox In Socks') - self.assertEqual(fox_ext.get('namespace'), - 'http://www.fox.in.socks/api/ext/pie/v1.0') - self.assertEqual(fox_ext.get('updated'), '2011-01-22T13:25:27-06:00') - self.assertEqual(fox_ext.findtext('{0}description'.format(NS)), - 'The Fox In Socks Extension') - - xmlutil.validate_schema(root, 'extensions') - - def test_get_extension_xml(self): - app = volume.APIRouter() - request = webob.Request.blank("/fake/extensions/FOXNSOX") - request.accept = "application/xml" - response = request.get_response(app) - self.assertEqual(200, response.status_int) - xml = response.body - - root = etree.XML(xml) - self.assertEqual(root.tag.split('extension')[0], NS) - self.assertEqual(root.get('alias'), 'FOXNSOX') - self.assertEqual(root.get('name'), 'Fox In Socks') - self.assertEqual(root.get('namespace'), - 'http://www.fox.in.socks/api/ext/pie/v1.0') - self.assertEqual(root.get('updated'), '2011-01-22T13:25:27-06:00') - self.assertEqual(root.findtext('{0}description'.format(NS)), - 'The Fox In Socks Extension') - - xmlutil.validate_schema(root, 'extension') diff --git a/nova/tests/api/openstack/volume/test_router.py b/nova/tests/api/openstack/volume/test_router.py deleted file mode 100644 index 5934a21e5..000000000 --- a/nova/tests/api/openstack/volume/test_router.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2011 Denali Systems, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from nova.api.openstack import volume -from nova.api.openstack.volume import snapshots -from nova.api.openstack.volume import versions -from nova.api.openstack.volume import volumes -from nova.api.openstack import wsgi -from nova import flags -from nova.openstack.common import log as logging -from nova import test -from nova.tests.api.openstack import fakes - -FLAGS = flags.FLAGS - -LOG = logging.getLogger(__name__) - - -class FakeController(object): - def __init__(self, ext_mgr=None): - self.ext_mgr = ext_mgr - - def index(self, req): - return {} - - def detail(self, req): - return {} - - -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_volume_resource) - self.app = volume.APIRouter() - - def test_versions(self): - req = fakes.HTTPRequest.blank('') - req.method = 'GET' - req.content_type = 'application/json' - response = req.get_response(self.app) - self.assertEqual(302, response.status_int) - req = fakes.HTTPRequest.blank('/') - req.method = 'GET' - req.content_type = 'application/json' - response = req.get_response(self.app) - self.assertEqual(200, response.status_int) - - def test_versions_dispatch(self): - req = fakes.HTTPRequest.blank('/') - req.method = 'GET' - req.content_type = 'application/json' - resource = versions.Versions() - result = resource.dispatch(resource.index, req, {}) - self.assertTrue(result) - - def test_volumes(self): - req = fakes.HTTPRequest.blank('/fake/volumes') - req.method = 'GET' - req.content_type = 'application/json' - response = req.get_response(self.app) - self.assertEqual(200, response.status_int) - - def test_volumes_detail(self): - req = fakes.HTTPRequest.blank('/fake/volumes/detail') - req.method = 'GET' - req.content_type = 'application/json' - response = req.get_response(self.app) - self.assertEqual(200, response.status_int) - - def test_types(self): - req = fakes.HTTPRequest.blank('/fake/types') - req.method = 'GET' - req.content_type = 'application/json' - response = req.get_response(self.app) - self.assertEqual(200, response.status_int) - - def test_snapshots(self): - req = fakes.HTTPRequest.blank('/fake/snapshots') - req.method = 'GET' - req.content_type = 'application/json' - response = req.get_response(self.app) - self.assertEqual(200, response.status_int) - - def test_snapshots_detail(self): - req = fakes.HTTPRequest.blank('/fake/snapshots/detail') - req.method = 'GET' - req.content_type = 'application/json' - response = req.get_response(self.app) - self.assertEqual(200, response.status_int) diff --git a/nova/tests/api/openstack/volume/test_snapshots.py b/nova/tests/api/openstack/volume/test_snapshots.py deleted file mode 100644 index c6e703f83..000000000 --- a/nova/tests/api/openstack/volume/test_snapshots.py +++ /dev/null @@ -1,299 +0,0 @@ -# Copyright 2011 Denali Systems, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from lxml import etree -import webob - -from nova.api.openstack.volume import snapshots -from nova import db -from nova import exception -from nova import flags -from nova.openstack.common import log as logging -from nova.openstack.common import timeutils -from nova import test -from nova.tests.api.openstack import fakes -from nova import volume - -FLAGS = flags.FLAGS - -LOG = logging.getLogger(__name__) - - -def _get_default_snapshot_param(): - return { - 'id': 123, - 'volume_id': 12, - 'status': 'available', - 'volume_size': 100, - 'created_at': None, - 'display_name': 'Default name', - 'display_description': 'Default description', - } - - -def stub_snapshot_create(self, context, volume_id, name, description): - snapshot = _get_default_snapshot_param() - snapshot['volume_id'] = volume_id - snapshot['display_name'] = name - snapshot['display_description'] = description - return snapshot - - -def stub_snapshot_delete(self, context, snapshot): - if snapshot['id'] != 123: - raise exception.NotFound - - -def stub_snapshot_get(self, context, snapshot_id): - if snapshot_id != 123: - raise exception.NotFound - - param = _get_default_snapshot_param() - return param - - -def stub_snapshot_get_all(self, context, search_opts=None): - param = _get_default_snapshot_param() - return [param] - - -class SnapshotApiTest(test.TestCase): - def setUp(self): - super(SnapshotApiTest, self).setUp() - self.controller = snapshots.SnapshotsController() - - self.stubs.Set(db, 'snapshot_get_all_by_project', - fakes.stub_snapshot_get_all_by_project) - self.stubs.Set(db, 'snapshot_get_all', - fakes.stub_snapshot_get_all) - - def test_snapshot_create(self): - self.stubs.Set(volume.api.API, "create_snapshot", stub_snapshot_create) - self.stubs.Set(volume.api.API, 'get', fakes.stub_volume_get) - snapshot = {"volume_id": '12', - "force": False, - "display_name": "Snapshot Test Name", - "display_description": "Snapshot Test Desc"} - body = dict(snapshot=snapshot) - req = fakes.HTTPRequest.blank('/v1/snapshots') - resp_dict = self.controller.create(req, body) - - self.assertTrue('snapshot' in resp_dict) - self.assertEqual(resp_dict['snapshot']['display_name'], - snapshot['display_name']) - self.assertEqual(resp_dict['snapshot']['display_description'], - snapshot['display_description']) - - def test_snapshot_create_force(self): - self.stubs.Set(volume.api.API, "create_snapshot_force", - stub_snapshot_create) - self.stubs.Set(volume.api.API, 'get', fakes.stub_volume_get) - snapshot = {"volume_id": '12', - "force": True, - "display_name": "Snapshot Test Name", - "display_description": "Snapshot Test Desc"} - body = dict(snapshot=snapshot) - req = fakes.HTTPRequest.blank('/v1/snapshots') - resp_dict = self.controller.create(req, body) - - self.assertTrue('snapshot' in resp_dict) - self.assertEqual(resp_dict['snapshot']['display_name'], - snapshot['display_name']) - self.assertEqual(resp_dict['snapshot']['display_description'], - snapshot['display_description']) - - # Test invalid force paramter - snapshot = {"volume_id": 12, - "force": '**&&^^%%$$##@@'} - body = dict(snapshot=snapshot) - req = fakes.HTTPRequest.blank('/v1/snapshots') - self.assertRaises(exception.InvalidParameterValue, - self.controller.create, - req, - body) - - def test_snapshot_create_nonexistent_volume_id(self): - self.stubs.Set(volume.api.API, 'get', fakes.stub_volume_get_notfound) - - snapshot = {"volume_id": 13, - "force": False, - "display_name": "Snapshot Test Name", - "display_description": "Snapshot Test Desc"} - body = dict(snapshot=snapshot) - req = fakes.HTTPRequest.blank('/v1/snapshots') - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.create, - req, - body) - - def test_snapshot_delete(self): - self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get) - self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete) - - snapshot_id = 123 - req = fakes.HTTPRequest.blank('/v1/snapshots/%d' % snapshot_id) - resp = self.controller.delete(req, snapshot_id) - self.assertEqual(resp.status_int, 202) - - def test_snapshot_delete_invalid_id(self): - self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete) - snapshot_id = 234 - req = fakes.HTTPRequest.blank('/v1/snapshots/%d' % snapshot_id) - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.delete, - req, - snapshot_id) - - def test_snapshot_show(self): - self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get) - req = fakes.HTTPRequest.blank('/v1/snapshots/123') - resp_dict = self.controller.show(req, 123) - - self.assertTrue('snapshot' in resp_dict) - self.assertEqual(resp_dict['snapshot']['id'], '123') - - def test_snapshot_show_invalid_id(self): - snapshot_id = 234 - req = fakes.HTTPRequest.blank('/v1/snapshots/%d' % snapshot_id) - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, - req, - snapshot_id) - - def test_snapshot_detail(self): - self.stubs.Set(volume.api.API, "get_all_snapshots", - stub_snapshot_get_all) - req = fakes.HTTPRequest.blank('/v1/snapshots/detail') - resp_dict = self.controller.detail(req) - - self.assertTrue('snapshots' in resp_dict) - resp_snapshots = resp_dict['snapshots'] - self.assertEqual(len(resp_snapshots), 1) - - resp_snapshot = resp_snapshots.pop() - self.assertEqual(resp_snapshot['id'], '123') - - def test_admin_list_snapshots_limited_to_project(self): - req = fakes.HTTPRequest.blank('/v1/fake/snapshots', - use_admin_context=True) - res = self.controller.index(req) - - self.assertTrue('snapshots' in res) - self.assertEqual(1, len(res['snapshots'])) - - def test_admin_list_snapshots_all_tenants(self): - req = fakes.HTTPRequest.blank('/v1/fake/snapshots?all_tenants=1', - use_admin_context=True) - res = self.controller.index(req) - self.assertTrue('snapshots' in res) - self.assertEqual(3, len(res['snapshots'])) - - def test_all_tenants_non_admin_gets_all_tenants(self): - req = fakes.HTTPRequest.blank('/v1/fake/snapshots?all_tenants=1') - res = self.controller.index(req) - self.assertTrue('snapshots' in res) - self.assertEqual(1, len(res['snapshots'])) - - def test_non_admin_get_by_project(self): - req = fakes.HTTPRequest.blank('/v1/fake/snapshots') - res = self.controller.index(req) - self.assertTrue('snapshots' in res) - self.assertEqual(1, len(res['snapshots'])) - - -class SnapshotSerializerTest(test.TestCase): - def _verify_snapshot(self, snap, tree): - self.assertEqual(tree.tag, 'snapshot') - - for attr in ('id', 'status', 'size', 'created_at', - 'display_name', 'display_description', 'volume_id'): - self.assertEqual(str(snap[attr]), tree.get(attr)) - - def test_snapshot_show_create_serializer(self): - serializer = snapshots.SnapshotTemplate() - raw_snapshot = dict( - id='snap_id', - status='snap_status', - size=1024, - created_at=timeutils.utcnow(), - display_name='snap_name', - display_description='snap_desc', - volume_id='vol_id', - ) - text = serializer.serialize(dict(snapshot=raw_snapshot)) - - print text - tree = etree.fromstring(text) - - self._verify_snapshot(raw_snapshot, tree) - - def test_snapshot_index_detail_serializer(self): - serializer = snapshots.SnapshotsTemplate() - raw_snapshots = [dict( - id='snap1_id', - status='snap1_status', - size=1024, - created_at=timeutils.utcnow(), - display_name='snap1_name', - display_description='snap1_desc', - volume_id='vol1_id', - ), - dict( - id='snap2_id', - status='snap2_status', - size=1024, - created_at=timeutils.utcnow(), - display_name='snap2_name', - display_description='snap2_desc', - volume_id='vol2_id', - )] - text = serializer.serialize(dict(snapshots=raw_snapshots)) - - print text - tree = etree.fromstring(text) - - self.assertEqual('snapshots', tree.tag) - self.assertEqual(len(raw_snapshots), len(tree)) - for idx, child in enumerate(tree): - self._verify_snapshot(raw_snapshots[idx], child) - - -class SnapshotsUnprocessableEntityTestCase(test.TestCase): - - """ - Tests of places we throw 422 Unprocessable Entity from - """ - - def setUp(self): - super(SnapshotsUnprocessableEntityTestCase, self).setUp() - self.controller = snapshots.SnapshotsController() - - def _unprocessable_snapshot_create(self, body): - req = fakes.HTTPRequest.blank('/v2/fake/snapshots') - req.method = 'POST' - - self.assertRaises(webob.exc.HTTPUnprocessableEntity, - self.controller.create, req, body) - - def test_create_no_body(self): - self._unprocessable_snapshot_create(body=None) - - def test_create_missing_snapshot(self): - body = {'foo': {'a': 'b'}} - self._unprocessable_snapshot_create(body=body) - - def test_create_malformed_entity(self): - body = {'snapshot': 'string'} - self._unprocessable_snapshot_create(body=body) diff --git a/nova/tests/api/openstack/volume/test_types.py b/nova/tests/api/openstack/volume/test_types.py deleted file mode 100644 index e7aa4cc0a..000000000 --- a/nova/tests/api/openstack/volume/test_types.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# aLL Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from lxml import etree -import webob - -from nova.api.openstack.volume import types -from nova.api.openstack.volume.views import types as views_types -from nova import exception -from nova.openstack.common import timeutils -from nova import test -from nova.tests.api.openstack import fakes -from nova.volume import volume_types - - -def stub_volume_type(id): - specs = { - "key1": "value1", - "key2": "value2", - "key3": "value3", - "key4": "value4", - "key5": "value5"} - return dict(id=id, name='vol_type_%s' % str(id), extra_specs=specs) - - -def return_volume_types_get_all_types(context): - return dict(vol_type_1=stub_volume_type(1), - vol_type_2=stub_volume_type(2), - vol_type_3=stub_volume_type(3)) - - -def return_empty_volume_types_get_all_types(context): - return {} - - -def return_volume_types_get_volume_type(context, id): - if id == "777": - raise exception.VolumeTypeNotFound(volume_type_id=id) - return stub_volume_type(int(id)) - - -def return_volume_types_get_by_name(context, name): - if name == "777": - raise exception.VolumeTypeNotFoundByName(volume_type_name=name) - return stub_volume_type(int(name.split("_")[2])) - - -class VolumeTypesApiTest(test.TestCase): - def setUp(self): - super(VolumeTypesApiTest, self).setUp() - self.controller = types.VolumeTypesController() - - def test_volume_types_index(self): - self.stubs.Set(volume_types, 'get_all_types', - return_volume_types_get_all_types) - - req = fakes.HTTPRequest.blank('/v1/fake/types') - res_dict = self.controller.index(req) - - self.assertEqual(3, len(res_dict['volume_types'])) - - expected_names = ['vol_type_1', 'vol_type_2', 'vol_type_3'] - actual_names = map(lambda e: e['name'], res_dict['volume_types']) - self.assertEqual(set(actual_names), set(expected_names)) - for entry in res_dict['volume_types']: - self.assertEqual('value1', entry['extra_specs']['key1']) - - def test_volume_types_index_no_data(self): - self.stubs.Set(volume_types, 'get_all_types', - return_empty_volume_types_get_all_types) - - req = fakes.HTTPRequest.blank('/v1/fake/types') - res_dict = self.controller.index(req) - - self.assertEqual(0, len(res_dict['volume_types'])) - - def test_volume_types_show(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - - req = fakes.HTTPRequest.blank('/v1/fake/types/1') - res_dict = self.controller.show(req, 1) - - self.assertEqual(1, len(res_dict)) - self.assertEqual('1', res_dict['volume_type']['id']) - self.assertEqual('vol_type_1', res_dict['volume_type']['name']) - - def test_volume_types_show_not_found(self): - self.stubs.Set(volume_types, 'get_volume_type', - return_volume_types_get_volume_type) - - req = fakes.HTTPRequest.blank('/v1/fake/types/777') - self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, - req, '777') - - def test_view_builder_show(self): - view_builder = views_types.ViewBuilder() - - now = timeutils.isotime() - raw_volume_type = dict(name='new_type', - deleted=False, - created_at=now, - updated_at=now, - extra_specs={}, - deleted_at=None, - id=42) - - request = fakes.HTTPRequest.blank("/v1") - output = view_builder.show(request, raw_volume_type) - - self.assertTrue('volume_type' in output) - expected_volume_type = dict(name='new_type', - extra_specs={}, - id=42) - self.assertDictMatch(output['volume_type'], expected_volume_type) - - def test_view_builder_list(self): - view_builder = views_types.ViewBuilder() - - now = timeutils.isotime() - raw_volume_types = [] - for i in range(0, 10): - raw_volume_types.append(dict(name='new_type', - deleted=False, - created_at=now, - updated_at=now, - extra_specs={}, - deleted_at=None, - id=42 + i)) - - request = fakes.HTTPRequest.blank("/v1") - output = view_builder.index(request, raw_volume_types) - - self.assertTrue('volume_types' in output) - for i in range(0, 10): - expected_volume_type = dict(name='new_type', - extra_specs={}, - id=42 + i) - self.assertDictMatch(output['volume_types'][i], - expected_volume_type) - - -class VolumeTypesSerializerTest(test.TestCase): - def _verify_volume_type(self, vtype, tree): - self.assertEqual('volume_type', tree.tag) - self.assertEqual(vtype['name'], tree.get('name')) - self.assertEqual(str(vtype['id']), tree.get('id')) - self.assertEqual(1, len(tree)) - extra_specs = tree[0] - self.assertEqual('extra_specs', extra_specs.tag) - seen = set(vtype['extra_specs'].keys()) - for child in extra_specs: - self.assertTrue(child.tag in seen) - self.assertEqual(vtype['extra_specs'][child.tag], child.text) - seen.remove(child.tag) - self.assertEqual(len(seen), 0) - - def test_index_serializer(self): - serializer = types.VolumeTypesTemplate() - - # Just getting some input data - vtypes = return_volume_types_get_all_types(None) - text = serializer.serialize({'volume_types': vtypes.values()}) - - tree = etree.fromstring(text) - - self.assertEqual('volume_types', tree.tag) - self.assertEqual(len(vtypes), len(tree)) - for child in tree: - name = child.get('name') - self.assertTrue(name in vtypes) - self._verify_volume_type(vtypes[name], child) - - def test_voltype_serializer(self): - serializer = types.VolumeTypeTemplate() - - vtype = stub_volume_type(1) - text = serializer.serialize(dict(volume_type=vtype)) - - tree = etree.fromstring(text) - - self._verify_volume_type(vtype, tree) diff --git a/nova/tests/api/openstack/volume/test_volumes.py b/nova/tests/api/openstack/volume/test_volumes.py deleted file mode 100644 index e7a0e66f3..000000000 --- a/nova/tests/api/openstack/volume/test_volumes.py +++ /dev/null @@ -1,602 +0,0 @@ -# Copyright 2013 Josh Durgin -# All Rights Reserved. -# -# 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 - -from lxml import etree -import webob - -from nova.api.openstack.volume import extensions -from nova.api.openstack.volume import volumes -from nova import db -from nova import exception -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): - super(VolumeApiTest, self).setUp() - self.ext_mgr = extensions.ExtensionManager() - self.ext_mgr.extensions = {} - self.controller = volumes.VolumeController(self.ext_mgr) - - self.stubs.Set(db, 'volume_get_all', fakes.stub_volume_get_all) - self.stubs.Set(db, 'volume_get_all_by_project', - fakes.stub_volume_get_all_by_project) - self.stubs.Set(volume_api.API, 'get', fakes.stub_volume_get) - self.stubs.Set(volume_api.API, 'delete', fakes.stub_volume_delete) - - def test_volume_create(self): - self.stubs.Set(volume_api.API, "create", fakes.stub_volume_create) - - vol = {"size": 100, - "display_name": "Volume Test Name", - "display_description": "Volume Test Desc", - "availability_zone": "zone1:host1"} - body = {"volume": vol} - req = fakes.HTTPRequest.blank('/v1/volumes') - res = self.controller.create(req, body) - expected = {'volume': {'status': 'fakestatus', - 'display_description': 'Volume Test Desc', - 'availability_zone': 'zone1:host1', - 'display_name': 'Volume Test Name', - 'attachments': [{'device': '/', - 'server_id': 'fakeuuid', - 'id': '1', - 'volume_id': '1'}], - 'volume_type': 'vol_type_name', - 'snapshot_id': None, - 'metadata': {}, - 'id': '1', - 'created_at': datetime.datetime(1999, 1, 1, - 1, 1, 1), - 'size': 100}} - self.assertEqual(res.obj, expected) - self.assertEqual(res.code, 200) - self.assertTrue('location' in res.headers) - - def test_volume_creation_fails_with_bad_size(self): - vol = {"size": '', - "display_name": "Volume Test Name", - "display_description": "Volume Test Desc", - "availability_zone": "zone1:host1"} - body = {"volume": vol} - req = fakes.HTTPRequest.blank('/v1/volumes') - self.assertRaises(exception.InvalidInput, - self.controller.create, - 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) - - req = fakes.HTTPRequest.blank('/v1/volumes') - res_dict = self.controller.index(req) - expected = {'volumes': [{'status': 'fakestatus', - 'display_description': 'displaydesc', - 'availability_zone': 'fakeaz', - 'display_name': 'displayname', - 'attachments': [{'device': '/', - 'server_id': 'fakeuuid', - 'id': '1', - 'volume_id': '1'}], - 'volume_type': 'vol_type_name', - 'snapshot_id': None, - 'metadata': {}, - 'id': '1', - 'created_at': datetime.datetime(1999, 1, 1, - 1, 1, 1), - 'size': 1}]} - self.maxDiff = None - self.assertEqual(res_dict, expected) - - def test_volume_list_detail(self): - self.stubs.Set(volume_api.API, 'get_all', - fakes.stub_volume_get_all_by_project) - - req = fakes.HTTPRequest.blank('/v1/volumes/detail') - res_dict = self.controller.index(req) - expected = {'volumes': [{'status': 'fakestatus', - 'display_description': 'displaydesc', - 'availability_zone': 'fakeaz', - 'display_name': 'displayname', - 'attachments': [{'device': '/', - 'server_id': 'fakeuuid', - 'id': '1', - 'volume_id': '1'}], - 'volume_type': 'vol_type_name', - 'snapshot_id': None, - 'metadata': {}, - 'id': '1', - 'created_at': datetime.datetime(1999, 1, 1, - 1, 1, 1), - 'size': 1}]} - self.assertEqual(res_dict, expected) - - def test_volume_show(self): - req = fakes.HTTPRequest.blank('/v1/volumes/1') - res_dict = self.controller.show(req, '1') - expected = {'volume': {'status': 'fakestatus', - 'display_description': 'displaydesc', - 'availability_zone': 'fakeaz', - 'display_name': 'displayname', - 'attachments': [{'device': '/', - 'server_id': 'fakeuuid', - 'id': '1', - 'volume_id': '1'}], - 'volume_type': 'vol_type_name', - 'snapshot_id': None, - 'metadata': {}, - 'id': '1', - 'created_at': datetime.datetime(1999, 1, 1, - 1, 1, 1), - 'size': 1}} - self.assertEqual(res_dict, expected) - - def test_volume_show_no_attachments(self): - def stub_volume_get(self, context, volume_id): - return fakes.stub_volume(volume_id, attach_status='detached') - - self.stubs.Set(volume_api.API, 'get', stub_volume_get) - - req = fakes.HTTPRequest.blank('/v1/volumes/1') - res_dict = self.controller.show(req, '1') - expected = {'volume': {'status': 'fakestatus', - 'display_description': 'displaydesc', - 'availability_zone': 'fakeaz', - 'display_name': 'displayname', - 'attachments': [], - 'volume_type': 'vol_type_name', - 'snapshot_id': None, - 'metadata': {}, - 'id': '1', - 'created_at': datetime.datetime(1999, 1, 1, - 1, 1, 1), - 'size': 1}} - self.assertEqual(res_dict, expected) - - def test_volume_show_no_volume(self): - self.stubs.Set(volume_api.API, "get", fakes.stub_volume_get_notfound) - - req = fakes.HTTPRequest.blank('/v1/volumes/1') - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.show, - req, - 1) - - def test_volume_delete(self): - req = fakes.HTTPRequest.blank('/v1/volumes/1') - resp = self.controller.delete(req, 1) - self.assertEqual(resp.status_int, 202) - - def test_volume_delete_no_volume(self): - self.stubs.Set(volume_api.API, "get", fakes.stub_volume_get_notfound) - - req = fakes.HTTPRequest.blank('/v1/volumes/1') - self.assertRaises(webob.exc.HTTPNotFound, - self.controller.delete, - req, - 1) - - def test_admin_list_volumes_limited_to_project(self): - req = fakes.HTTPRequest.blank('/v1/fake/volumes', - use_admin_context=True) - res = self.controller.index(req) - - self.assertTrue('volumes' in res) - self.assertEqual(1, len(res['volumes'])) - - def test_admin_list_volumes_all_tenants(self): - req = fakes.HTTPRequest.blank('/v1/fake/volumes?all_tenants=1', - use_admin_context=True) - res = self.controller.index(req) - self.assertTrue('volumes' in res) - self.assertEqual(3, len(res['volumes'])) - - def test_all_tenants_non_admin_gets_all_tenants(self): - req = fakes.HTTPRequest.blank('/v1/fake/volumes?all_tenants=1') - res = self.controller.index(req) - self.assertTrue('volumes' in res) - self.assertEqual(1, len(res['volumes'])) - - def test_non_admin_get_by_project(self): - req = fakes.HTTPRequest.blank('/v1/fake/volumes') - res = self.controller.index(req) - self.assertTrue('volumes' in res) - self.assertEqual(1, len(res['volumes'])) - - -class VolumeSerializerTest(test.TestCase): - def _verify_volume_attachment(self, attach, tree): - for attr in ('id', 'volume_id', 'server_id', 'device'): - self.assertEqual(str(attach[attr]), tree.get(attr)) - - def _verify_volume(self, vol, tree): - self.assertEqual(tree.tag, 'volume') - - for attr in ('id', 'status', 'size', 'availability_zone', 'created_at', - 'display_name', 'display_description', 'volume_type', - 'snapshot_id'): - self.assertEqual(str(vol[attr]), tree.get(attr)) - - for child in tree: - self.assertTrue(child.tag in ('attachments', 'metadata')) - if child.tag == 'attachments': - self.assertEqual(1, len(child)) - self.assertEqual('attachment', child[0].tag) - self._verify_volume_attachment(vol['attachments'][0], child[0]) - elif child.tag == 'metadata': - not_seen = set(vol['metadata'].keys()) - for gr_child in child: - self.assertTrue(gr_child.get("key") in not_seen) - self.assertEqual(str(vol['metadata'][gr_child.get("key")]), - gr_child.text) - not_seen.remove(gr_child.get("key")) - self.assertEqual(0, len(not_seen)) - - def test_volume_show_create_serializer(self): - serializer = volumes.VolumeTemplate() - raw_volume = dict( - id='vol_id', - status='vol_status', - size=1024, - availability_zone='vol_availability', - created_at=timeutils.utcnow(), - attachments=[dict( - id='vol_id', - volume_id='vol_id', - server_id='instance_uuid', - device='/foo')], - display_name='vol_name', - display_description='vol_desc', - volume_type='vol_type', - snapshot_id='snap_id', - metadata=dict( - foo='bar', - baz='quux', - ), - ) - text = serializer.serialize(dict(volume=raw_volume)) - - print text - tree = etree.fromstring(text) - - self._verify_volume(raw_volume, tree) - - def test_volume_index_detail_serializer(self): - serializer = volumes.VolumesTemplate() - raw_volumes = [dict( - id='vol1_id', - status='vol1_status', - size=1024, - availability_zone='vol1_availability', - created_at=timeutils.utcnow(), - attachments=[dict( - id='vol1_id', - volume_id='vol1_id', - server_id='instance_uuid', - device='/foo1')], - display_name='vol1_name', - display_description='vol1_desc', - volume_type='vol1_type', - snapshot_id='snap1_id', - metadata=dict( - foo='vol1_foo', - bar='vol1_bar', - ), - ), - dict( - id='vol2_id', - status='vol2_status', - size=1024, - availability_zone='vol2_availability', - created_at=timeutils.utcnow(), - attachments=[dict( - id='vol2_id', - volume_id='vol2_id', - server_id='instance_uuid', - device='/foo2')], - display_name='vol2_name', - display_description='vol2_desc', - volume_type='vol2_type', - snapshot_id='snap2_id', - metadata=dict( - foo='vol2_foo', - bar='vol2_bar', - ), - )] - text = serializer.serialize(dict(volumes=raw_volumes)) - - print text - tree = etree.fromstring(text) - - self.assertEqual('volumes', tree.tag) - self.assertEqual(len(raw_volumes), len(tree)) - for idx, child in enumerate(tree): - self._verify_volume(raw_volumes[idx], child) - - -class TestVolumeCreateRequestXMLDeserializer(test.TestCase): - - def setUp(self): - super(TestVolumeCreateRequestXMLDeserializer, self).setUp() - self.deserializer = volumes.CreateDeserializer() - - def test_minimal_volume(self): - self_request = """ -<volume xmlns="http://docs.openstack.org/compute/api/v1.1" - size="1"></volume>""" - request = self.deserializer.deserialize(self_request) - expected = { - "volume": { - "size": "1", - }, - } - self.assertEquals(request['body'], expected) - - def test_display_name(self): - self_request = """ -<volume xmlns="http://docs.openstack.org/compute/api/v1.1" - size="1" - display_name="Volume-xml"></volume>""" - request = self.deserializer.deserialize(self_request) - expected = { - "volume": { - "size": "1", - "display_name": "Volume-xml", - }, - } - self.assertEquals(request['body'], expected) - - def test_display_description(self): - self_request = """ -<volume xmlns="http://docs.openstack.org/compute/api/v1.1" - size="1" - display_name="Volume-xml" - display_description="description"></volume>""" - request = self.deserializer.deserialize(self_request) - expected = { - "volume": { - "size": "1", - "display_name": "Volume-xml", - "display_description": "description", - }, - } - self.assertEquals(request['body'], expected) - - def test_volume_type(self): - self_request = """ -<volume xmlns="http://docs.openstack.org/compute/api/v1.1" - size="1" - display_name="Volume-xml" - display_description="description" - volume_type="289da7f8-6440-407c-9fb4-7db01ec49164"></volume>""" - request = self.deserializer.deserialize(self_request) - expected = { - "volume": { - "display_name": "Volume-xml", - "size": "1", - "display_name": "Volume-xml", - "display_description": "description", - "volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164", - }, - } - self.assertEquals(request['body'], expected) - - def test_availability_zone(self): - self_request = """ -<volume xmlns="http://docs.openstack.org/compute/api/v1.1" - size="1" - display_name="Volume-xml" - display_description="description" - volume_type="289da7f8-6440-407c-9fb4-7db01ec49164" - availability_zone="us-east1"></volume>""" - request = self.deserializer.deserialize(self_request) - expected = { - "volume": { - "size": "1", - "display_name": "Volume-xml", - "display_description": "description", - "volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164", - "availability_zone": "us-east1", - }, - } - self.assertEquals(request['body'], expected) - - def test_metadata(self): - self_request = """ -<volume xmlns="http://docs.openstack.org/compute/api/v1.1" - display_name="Volume-xml" - size="1"> - <metadata><meta key="Type">work</meta></metadata></volume>""" - request = self.deserializer.deserialize(self_request) - expected = { - "volume": { - "display_name": "Volume-xml", - "size": "1", - "metadata": { - "Type": "work", - }, - }, - } - self.assertEquals(request['body'], expected) - - def test_full_volume(self): - self_request = """ -<volume xmlns="http://docs.openstack.org/compute/api/v1.1" - size="1" - display_name="Volume-xml" - display_description="description" - volume_type="289da7f8-6440-407c-9fb4-7db01ec49164" - availability_zone="us-east1"> - <metadata><meta key="Type">work</meta></metadata></volume>""" - request = self.deserializer.deserialize(self_request) - expected = { - "volume": { - "size": "1", - "display_name": "Volume-xml", - "display_description": "description", - "volume_type": "289da7f8-6440-407c-9fb4-7db01ec49164", - "availability_zone": "us-east1", - "metadata": { - "Type": "work", - }, - }, - } - self.maxDiff = None - self.assertEquals(request['body'], expected) - - -class VolumesUnprocessableEntityTestCase(test.TestCase): - - """ - Tests of places we throw 422 Unprocessable Entity from - """ - - def setUp(self): - super(VolumesUnprocessableEntityTestCase, self).setUp() - 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') - req.method = 'POST' - - self.assertRaises(webob.exc.HTTPUnprocessableEntity, - self.controller.create, req, body) - - def test_create_no_body(self): - self._unprocessable_volume_create(body=None) - - def test_create_missing_volume(self): - body = {'foo': {'a': 'b'}} - self._unprocessable_volume_create(body=body) - - def test_create_malformed_entity(self): - body = {'volume': 'string'} - self._unprocessable_volume_create(body=body) diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index 6a419feea..5d938622b 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -61,7 +61,7 @@ from nova.tests import fake_network from nova.tests import fake_network_cache_model from nova.tests.image import fake as fake_image from nova import utils -import nova.volume +from nova.volume import cinder QUOTAS = quota.QUOTAS @@ -657,9 +657,9 @@ class ComputeTestCase(BaseTestCase): def fake_volume_get(self, context, volume_id): return {'id': volume_id} - self.stubs.Set(nova.volume.api.API, 'get', fake_volume_get) - self.stubs.Set(nova.volume.api.API, 'check_attach', fake_check_attach) - self.stubs.Set(nova.volume.api.API, 'reserve_volume', + self.stubs.Set(cinder.API, 'get', fake_volume_get) + self.stubs.Set(cinder.API, 'check_attach', fake_check_attach) + self.stubs.Set(cinder.API, 'reserve_volume', fake_reserve_volume) self.compute_api.attach_volume(self.context, instance, 1, @@ -2222,11 +2222,16 @@ class ComputeTestCase(BaseTestCase): topic = rpc.queue_get_for(c, FLAGS.compute_topic, instance['host']) # creating volume testdata - volume_id = db.volume_create(c, {'size': 1})['id'] + volume_id = 'fake' values = {'instance_uuid': inst_uuid, 'device_name': '/dev/vdc', 'delete_on_termination': False, 'volume_id': volume_id} db.block_device_mapping_create(c, values) + def fake_volume_get(self, context, volume_id): + return {'id': volume_id} + + self.stubs.Set(cinder.API, 'get', fake_volume_get) + # creating mocks self.mox.StubOutWithMock(rpc, 'call') @@ -2272,7 +2277,6 @@ class ComputeTestCase(BaseTestCase): for bdms in db.block_device_mapping_get_all_by_instance( c, inst_uuid): db.block_device_mapping_destroy(c, bdms['id']) - db.volume_destroy(c, volume_id) db.instance_destroy(c, inst_uuid) def test_live_migration_works_correctly(self): @@ -2321,7 +2325,6 @@ class ComputeTestCase(BaseTestCase): db.instance_update(c, inst_uuid, {'task_state': task_states.MIGRATING, 'power_state': power_state.PAUSED}) - v_ref = db.volume_create(c, {'size': 1, 'instance_id': inst_id}) fix_addr = db.fixed_ip_create(c, {'address': '1.1.1.1', 'instance_uuid': inst_ref['uuid']}) fix_ref = db.fixed_ip_get_by_address(c, fix_addr) @@ -2356,7 +2359,6 @@ class ComputeTestCase(BaseTestCase): # cleanup db.instance_destroy(c, inst_uuid) - db.volume_destroy(c, v_ref['id']) db.floating_ip_destroy(c, flo_addr) def test_run_kill_vm(self): @@ -3406,8 +3408,7 @@ class ComputeAPITestCase(BaseTestCase): instance = jsonutils.to_primitive(self._create_fake_instance()) self.compute.run_instance(self.context, instance=instance) - volume_id = db.volume_create(context.get_admin_context(), - {'size': 1})['id'] + volume_id = 'fake' volume = {'instance_uuid': instance['uuid'], 'device_name': '/dev/vdc', 'delete_on_termination': False, @@ -3432,8 +3433,7 @@ class ComputeAPITestCase(BaseTestCase): instance = jsonutils.to_primitive(self._create_fake_instance()) self.compute.run_instance(self.context, instance=instance) - volume_id = db.volume_create(context.get_admin_context(), - {'size': 1})['id'] + volume_id = 'fake' volume = {'instance_uuid': instance['uuid'], 'device_name': '/dev/vdc', 'delete_on_termination': False, @@ -4616,9 +4616,9 @@ class ComputeAPITestCase(BaseTestCase): def fake_rpc_attach_volume(self, context, **kwargs): called['fake_rpc_attach_volume'] = True - self.stubs.Set(nova.volume.api.API, 'get', fake_volume_get) - self.stubs.Set(nova.volume.api.API, 'check_attach', fake_check_attach) - self.stubs.Set(nova.volume.api.API, 'reserve_volume', + self.stubs.Set(cinder.API, 'get', fake_volume_get) + self.stubs.Set(cinder.API, 'check_attach', fake_check_attach) + self.stubs.Set(cinder.API, 'reserve_volume', fake_reserve_volume) self.stubs.Set(compute_rpcapi.ComputeAPI, 'attach_volume', fake_rpc_attach_volume) @@ -4647,9 +4647,9 @@ class ComputeAPITestCase(BaseTestCase): def fake_rpc_attach_volume(self, context, **kwargs): called['fake_rpc_attach_volume'] = True - self.stubs.Set(nova.volume.api.API, 'get', fake_volume_get) - self.stubs.Set(nova.volume.api.API, 'check_attach', fake_check_attach) - self.stubs.Set(nova.volume.api.API, 'reserve_volume', + self.stubs.Set(cinder.API, 'get', fake_volume_get) + self.stubs.Set(cinder.API, 'check_attach', fake_check_attach) + self.stubs.Set(cinder.API, 'reserve_volume', fake_reserve_volume) self.stubs.Set(compute_rpcapi.ComputeAPI, 'attach_volume', fake_rpc_attach_volume) @@ -4659,37 +4659,35 @@ class ComputeAPITestCase(BaseTestCase): admin = context.get_admin_context() instance = self._create_fake_instance() - # Create a volume and attach it to our instance - volume_id = db.volume_create(admin, {'size': 1})['id'] + volume_id = 'fake' values = {'instance_uuid': instance['uuid'], 'device_name': '/dev/vdc', 'delete_on_termination': False, 'volume_id': volume_id, } db.block_device_mapping_create(admin, values) - db.volume_attached(admin, volume_id, instance["uuid"], - "/dev/vdc") + + def fake_volume_get(self, context, volume): + return {'id': volume_id} + self.stubs.Set(cinder.API, "get", fake_volume_get) # Stub out and record whether it gets detached result = {"detached": False} def fake_detach(self, context, volume): result["detached"] = volume["id"] == volume_id - self.stubs.Set(nova.volume.api.API, "detach", fake_detach) + self.stubs.Set(cinder.API, "detach", fake_detach) + + def fake_terminate_connection(self, context, volume, connector): + return {} + self.stubs.Set(cinder.API, "terminate_connection", + fake_terminate_connection) # Kill the instance and check that it was detached self.compute.terminate_instance(admin, instance=instance) self.assertTrue(result["detached"]) def test_inject_network_info(self): - instance = self._create_fake_instance() - self.compute_api.attach_volume(self.context, instance, 1, device=None) - self.assertTrue(called.get('fake_check_attach')) - self.assertTrue(called.get('fake_reserve_volume')) - self.assertTrue(called.get('fake_reserve_volume')) - self.assertTrue(called.get('fake_rpc_attach_volume')) - - def test_inject_network_info(self): instance = self._create_fake_instance(params={'host': FLAGS.host}) self.compute.run_instance(self.context, instance=jsonutils.to_primitive(instance)) diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py index 32f34b3e7..0b50d45e2 100644 --- a/nova/tests/fake_flags.py +++ b/nova/tests/fake_flags.py @@ -26,7 +26,6 @@ flags.DECLARE('iscsi_num_targets', 'nova.volume.driver') flags.DECLARE('network_size', 'nova.network.manager') flags.DECLARE('num_networks', 'nova.network.manager') flags.DECLARE('policy_file', 'nova.policy') -flags.DECLARE('volume_driver', 'nova.volume.manager') def set_defaults(conf): @@ -44,7 +43,6 @@ def set_defaults(conf): conf.set_default('sqlite_synchronous', False) conf.set_default('use_ipv6', True) conf.set_default('verbose', True) - conf.set_default('volume_driver', 'nova.volume.driver.FakeISCSIDriver') conf.set_default('api_paste_config', '$state_path/etc/nova/api-paste.ini') conf.set_default('rpc_response_timeout', 5) conf.set_default('rpc_cast_timeout', 5) diff --git a/nova/tests/fake_volume.py b/nova/tests/fake_volume.py index 37aaa83b4..54fd85fe5 100644 --- a/nova/tests/fake_volume.py +++ b/nova/tests/fake_volume.py @@ -27,21 +27,21 @@ class fake_volume(): instance_uuid = '4a3cd441-b9c2-11e1-afa6-0800200c9a66' def __init__(self, size, name, - description, id, snapshot, + description, volume_id, snapshot, volume_type, metadata, availability_zone): snapshot_id = None if snapshot is not None: snapshot_id = snapshot['id'] - if id is None: - id = str(utils.gen_uuid()) + if volume_id is None: + volume_id = str(utils.gen_uuid()) self.vol = { 'created_at': timeutils.utcnow(), 'deleted_at': None, 'updated_at': timeutils.utcnow(), 'uuid': 'WTF', 'deleted': False, - 'id': id, + 'id': volume_id, 'user_id': self.user_uuid, 'project_id': 'fake-project-id', 'snapshot_id': snapshot_id, @@ -133,14 +133,17 @@ class API(object): return v.vol def create_with_kwargs(self, context, **kwargs): + volume_id = kwargs.get('volume_id', None) + print volume_id v = fake_volume(kwargs['size'], kwargs['name'], kwargs['description'], - str(kwargs.get('volume_id', None)), + str(volume_id), None, None, None, None) + print v.vol['id'] if kwargs.get('status', None) is not None: v.vol['status'] = kwargs['status'] if kwargs['host'] is not None: @@ -175,6 +178,7 @@ class API(object): def check_attach(self, context, volume): if volume['status'] != 'available': msg = _("status must be available") + msg = "%s" % volume raise exception.InvalidVolume(reason=msg) if volume['attach_status'] == 'attached': msg = _("already attached") diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index f566a5020..9581a0e7e 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -329,14 +329,6 @@ "updated": "%(timestamp)s" }, { - "alias": "os-volume-types", - "description": "%(text)s", - "links": [], - "name": "VolumeTypes", - "namespace": "http://docs.openstack.org/compute/ext/volume_types/api/v1.1", - "updated": "%(timestamp)s" - }, - { "alias": "os-volumes", "description": "%(text)s", "links": [], diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index 20e650d7c..e8246aad8 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -123,9 +123,6 @@ <extension alias="os-virtual-interfaces" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1" name="VirtualInterfaces"> <description>%(text)s</description> </extension> - <extension alias="os-volume-types" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/volume_types/api/v1.1" name="VolumeTypes"> - <description>%(text)s</description> - </extension> <extension alias="os-volumes" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/volumes/api/v1.1" name="Volumes"> <description>%(text)s</description> </extension> diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py index d81013920..f3bd944da 100644 --- a/nova/tests/integrated/integrated_helpers.py +++ b/nova/tests/integrated/integrated_helpers.py @@ -75,7 +75,6 @@ class _IntegratedTestBase(test.TestCase): # set up services self.compute = self.start_service('compute') self.scheduler = self.start_service('cert') - self.volume = self.start_service('volume') self.network = self.start_service('network') self.scheduler = self.start_service('scheduler') @@ -101,13 +100,11 @@ class _IntegratedTestBase(test.TestCase): # Ensure tests only listen on localhost f['ec2_listen'] = '127.0.0.1' f['osapi_compute_listen'] = '127.0.0.1' - f['osapi_volume_listen'] = '127.0.0.1' f['metadata_listen'] = '127.0.0.1' # Auto-assign ports to allow concurrent tests f['ec2_listen_port'] = 0 f['osapi_compute_listen_port'] = 0 - f['osapi_volume_listen_port'] = 0 f['metadata_listen_port'] = 0 f['fake_network'] = True diff --git a/nova/tests/integrated/test_volumes.py b/nova/tests/integrated/test_volumes.py deleted file mode 100644 index fe70c3ce8..000000000 --- a/nova/tests/integrated/test_volumes.py +++ /dev/null @@ -1,181 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 Justin Santa Barbara -# All Rights Reserved. -# -# 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 time -import unittest - -from nova.openstack.common.log import logging -from nova import service -from nova.tests.integrated.api import client -from nova.tests.integrated import integrated_helpers -from nova.volume import driver - - -LOG = logging.getLogger(__name__) - - -class VolumesTest(integrated_helpers._IntegratedTestBase): - def setUp(self): - super(VolumesTest, self).setUp() - driver.LoggingVolumeDriver.clear_logs() - - def _start_api_service(self): - self.osapi = service.WSGIService("osapi_volume") - self.osapi.start() - self.auth_url = 'http://%s:%s/v1' % (self.osapi.host, self.osapi.port) - LOG.warn(self.auth_url) - - def _get_flags(self): - f = super(VolumesTest, self)._get_flags() - f['use_local_volumes'] = False # Avoids calling local_path - f['volume_driver'] = 'nova.volume.driver.LoggingVolumeDriver' - return f - - def test_get_volumes_summary(self): - """Simple check that listing volumes works.""" - volumes = self.api.get_volumes(False) - for volume in volumes: - LOG.debug("volume: %s" % volume) - - def test_get_volumes(self): - """Simple check that listing volumes works.""" - volumes = self.api.get_volumes() - for volume in volumes: - LOG.debug("volume: %s" % volume) - - def _poll_while(self, volume_id, continue_states, max_retries=5): - """Poll (briefly) while the state is in continue_states.""" - retries = 0 - while True: - try: - found_volume = self.api.get_volume(volume_id) - except client.OpenStackApiNotFoundException: - found_volume = None - LOG.debug("Got 404, proceeding") - break - - LOG.debug("Found %s" % found_volume) - - self.assertEqual(volume_id, found_volume['id']) - - if not found_volume['status'] in continue_states: - break - - time.sleep(1) - retries = retries + 1 - if retries > max_retries: - break - return found_volume - - def test_create_and_delete_volume(self): - """Creates and deletes a volume.""" - - # Create volume - created_volume = self.api.post_volume({'volume': {'size': 1}}) - LOG.debug("created_volume: %s" % created_volume) - self.assertTrue(created_volume['id']) - created_volume_id = created_volume['id'] - - # Check it's there - found_volume = self.api.get_volume(created_volume_id) - self.assertEqual(created_volume_id, found_volume['id']) - - # It should also be in the all-volume list - volumes = self.api.get_volumes() - volume_names = [volume['id'] for volume in volumes] - self.assertTrue(created_volume_id in volume_names) - - # Wait (briefly) for creation. Delay is due to the 'message queue' - found_volume = self._poll_while(created_volume_id, ['creating']) - - # It should be available... - self.assertEqual('available', found_volume['status']) - - # Delete the volume - self.api.delete_volume(created_volume_id) - - # Wait (briefly) for deletion. Delay is due to the 'message queue' - found_volume = self._poll_while(created_volume_id, ['deleting']) - - # Should be gone - self.assertFalse(found_volume) - - LOG.debug("Logs: %s" % driver.LoggingVolumeDriver.all_logs()) - - create_actions = driver.LoggingVolumeDriver.logs_like( - 'create_volume', - id=created_volume_id) - LOG.debug("Create_Actions: %s" % create_actions) - - self.assertEquals(1, len(create_actions)) - create_action = create_actions[0] - self.assertEquals(create_action['id'], created_volume_id) - self.assertEquals(create_action['availability_zone'], 'nova') - self.assertEquals(create_action['size'], 1) - - export_actions = driver.LoggingVolumeDriver.logs_like( - 'create_export', - id=created_volume_id) - self.assertEquals(1, len(export_actions)) - export_action = export_actions[0] - self.assertEquals(export_action['id'], created_volume_id) - self.assertEquals(export_action['availability_zone'], 'nova') - - delete_actions = driver.LoggingVolumeDriver.logs_like( - 'delete_volume', - id=created_volume_id) - self.assertEquals(1, len(delete_actions)) - delete_action = export_actions[0] - self.assertEquals(delete_action['id'], created_volume_id) - - def test_create_volume_with_metadata(self): - """Creates a volume with metadata.""" - - # Create volume - metadata = {'key1': 'value1', - 'key2': 'value2'} - created_volume = self.api.post_volume( - {'volume': {'size': 1, - 'metadata': metadata}}) - LOG.debug("created_volume: %s" % created_volume) - self.assertTrue(created_volume['id']) - created_volume_id = created_volume['id'] - - # Check it's there and metadata present - found_volume = self.api.get_volume(created_volume_id) - self.assertEqual(created_volume_id, found_volume['id']) - self.assertEqual(metadata, found_volume['metadata']) - - def test_create_volume_in_availability_zone(self): - """Creates a volume in availability_zone.""" - - # Create volume - availability_zone = 'zone1:host1' - created_volume = self.api.post_volume( - {'volume': {'size': 1, - 'availability_zone': availability_zone}}) - LOG.debug("created_volume: %s" % created_volume) - self.assertTrue(created_volume['id']) - created_volume_id = created_volume['id'] - - # Check it's there and availability zone present - found_volume = self.api.get_volume(created_volume_id) - self.assertEqual(created_volume_id, found_volume['id']) - self.assertEqual(availability_zone, found_volume['availability_zone']) - -if __name__ == "__main__": - unittest.main() diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index c6b2d7dd3..6a0e93b7d 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -175,18 +175,6 @@ class SchedulerManagerTestCase(test.TestCase): self.manager.run_instance(self.context, request_spec, None, None, None, None, {}) - def test_create_volume_no_valid_host_puts_volume_in_error(self): - self._mox_schedule_method_helper('schedule_create_volume') - self.mox.StubOutWithMock(db, 'volume_update') - - self.manager.driver.schedule_create_volume(self.context, '1', '2', - None).AndRaise(exception.NoValidHost(reason='')) - db.volume_update(self.context, '1', {'status': 'error'}) - - self.mox.ReplayAll() - self.assertRaises(exception.NoValidHost, self.manager.create_volume, - self.context, '1', '2') - def test_prep_resize_no_valid_host_back_in_active_state(self): fake_instance_uuid = 'fake-instance-id' inst = {"vm_state": "", "task_state": ""} @@ -305,13 +293,10 @@ class SchedulerTestCase(test.TestCase): self.assertEqual(result, ['host2']) def _live_migration_instance(self): - volume1 = {'id': 31338} - volume2 = {'id': 31339} return {'id': 31337, 'uuid': 'fake_uuid', 'name': 'fake-instance', 'host': 'fake_host1', - 'volumes': [volume1, volume2], 'power_state': power_state.RUNNING, 'memory_mb': 1024, 'root_gb': 1024, @@ -656,48 +641,6 @@ class SchedulerDriverModuleTestCase(test.TestCase): super(SchedulerDriverModuleTestCase, self).setUp() self.context = context.RequestContext('fake_user', 'fake_project') - def test_cast_to_volume_host_update_db_with_volume_id(self): - host = 'fake_host1' - method = 'fake_method' - fake_kwargs = {'volume_id': 31337, - 'extra_arg': 'meow'} - queue = 'fake_queue' - - self.mox.StubOutWithMock(timeutils, 'utcnow') - self.mox.StubOutWithMock(db, 'volume_update') - self.mox.StubOutWithMock(rpc, 'queue_get_for') - self.mox.StubOutWithMock(rpc, 'cast') - - timeutils.utcnow().AndReturn('fake-now') - db.volume_update(self.context, 31337, - {'host': host, 'scheduled_at': 'fake-now'}) - rpc.queue_get_for(self.context, 'volume', host).AndReturn(queue) - rpc.cast(self.context, queue, - {'method': method, - 'args': fake_kwargs}) - - self.mox.ReplayAll() - driver.cast_to_volume_host(self.context, host, method, - **fake_kwargs) - - def test_cast_to_volume_host_update_db_without_volume_id(self): - host = 'fake_host1' - method = 'fake_method' - fake_kwargs = {'extra_arg': 'meow'} - queue = 'fake_queue' - - self.mox.StubOutWithMock(rpc, 'queue_get_for') - self.mox.StubOutWithMock(rpc, 'cast') - - rpc.queue_get_for(self.context, 'volume', host).AndReturn(queue) - rpc.cast(self.context, queue, - {'method': method, - 'args': fake_kwargs}) - - self.mox.ReplayAll() - driver.cast_to_volume_host(self.context, host, method, - **fake_kwargs) - def test_cast_to_compute_host_update_db_with_instance_uuid(self): host = 'fake_host1' method = 'fake_method' @@ -753,19 +696,6 @@ class SchedulerDriverModuleTestCase(test.TestCase): driver.cast_to_host(self.context, 'compute', host, method, **fake_kwargs) - def test_cast_to_host_volume_topic(self): - host = 'fake_host1' - method = 'fake_method' - fake_kwargs = {'extra_arg': 'meow'} - - self.mox.StubOutWithMock(driver, 'cast_to_volume_host') - driver.cast_to_volume_host(self.context, host, method, - **fake_kwargs) - - self.mox.ReplayAll() - driver.cast_to_host(self.context, 'volume', host, method, - **fake_kwargs) - def test_cast_to_host_unknown_topic(self): host = 'fake_host1' method = 'fake_method' diff --git a/nova/tests/test_cinder.py b/nova/tests/test_cinder.py index 18532d642..3302aedb8 100644 --- a/nova/tests/test_cinder.py +++ b/nova/tests/test_cinder.py @@ -118,9 +118,6 @@ class CinderTestCase(test.TestCase): self.fake_client_factory = FakeClientFactory() self.stubs.Set(cinder.cinder_client, "Client", self.fake_client_factory) - self.flags( - volume_api_class='nova.volume.cinder.API', - ) self.api = cinder.API() catalog = [{ "type": "volume", diff --git a/nova/tests/test_iscsi.py b/nova/tests/test_iscsi.py deleted file mode 100644 index 09a6e9e89..000000000 --- a/nova/tests/test_iscsi.py +++ /dev/null @@ -1,121 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 Red Hat, Inc. -# -# 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 os.path -import shutil -import string -import tempfile - -from nova import test -from nova.volume import iscsi - - -class TargetAdminTestCase(object): - - def setUp(self): - self.cmds = [] - - self.tid = 1 - self.target_name = 'iqn.2011-09.org.foo.bar:blaa' - self.lun = 10 - self.path = '/foo' - self.vol_id = 'blaa' - - self.script_template = None - self.stubs.Set(os.path, 'isfile', lambda _: True) - self.stubs.Set(os, 'unlink', lambda _: '') - self.stubs.Set(iscsi.TgtAdm, '_get_target', self.fake_get_target) - - def fake_get_target(obj, iqn): - return 1 - - def get_script_params(self): - return {'tid': self.tid, - 'target_name': self.target_name, - 'lun': self.lun, - 'path': self.path} - - def get_script(self): - return self.script_template % self.get_script_params() - - def fake_execute(self, *cmd, **kwargs): - self.cmds.append(string.join(cmd)) - return "", None - - def clear_cmds(self): - cmds = [] - - def verify_cmds(self, cmds): - self.assertEqual(len(cmds), len(self.cmds)) - for a, b in zip(cmds, self.cmds): - self.assertEqual(a, b) - - def verify(self): - script = self.get_script() - cmds = [] - for line in script.split('\n'): - if not line.strip(): - continue - cmds.append(line) - self.verify_cmds(cmds) - - def run_commands(self): - tgtadm = iscsi.get_target_admin() - tgtadm.set_execute(self.fake_execute) - tgtadm.create_iscsi_target(self.target_name, self.tid, - self.lun, self.path) - tgtadm.show_target(self.tid, iqn=self.target_name) - tgtadm.remove_iscsi_target(self.tid, self.lun, self.vol_id) - - def test_target_admin(self): - self.clear_cmds() - self.run_commands() - self.verify() - - -class TgtAdmTestCase(test.TestCase, TargetAdminTestCase): - - def setUp(self): - super(TgtAdmTestCase, self).setUp() - TargetAdminTestCase.setUp(self) - self.persist_tempdir = tempfile.mkdtemp() - self.flags(iscsi_helper='tgtadm') - self.flags(volumes_dir=self.persist_tempdir) - self.script_template = "\n".join([ - 'tgt-admin --update iqn.2011-09.org.foo.bar:blaa', - 'tgt-admin --delete iqn.2010-10.org.openstack:volume-blaa']) - - def tearDown(self): - try: - shutil.rmtree(self.persist_tempdir) - except OSError: - pass - super(TgtAdmTestCase, self).tearDown() - - -class IetAdmTestCase(test.TestCase, TargetAdminTestCase): - - def setUp(self): - super(IetAdmTestCase, self).setUp() - TargetAdminTestCase.setUp(self) - self.flags(iscsi_helper='ietadm') - self.script_template = "\n".join([ - 'ietadm --op new --tid=%(tid)s --params Name=%(target_name)s', - 'ietadm --op new --tid=%(tid)s --lun=%(lun)s ' - '--params Path=%(path)s,Type=fileio', - 'ietadm --op show --tid=%(tid)s', - 'ietadm --op delete --tid=%(tid)s --lun=%(lun)s', - 'ietadm --op delete --tid=%(tid)s']) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index c84440e58..f8bc3c339 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -155,7 +155,6 @@ class LibvirtVolumeTestCase(test.TestCase): } def test_libvirt_volume_driver_serial(self): - vol_driver = volume_driver.VolumeDriver() libvirt_driver = volume.LibvirtVolumeDriver(self.fake_conn) name = 'volume-00000001' vol = {'id': 1, 'name': name} diff --git a/nova/tests/test_netapp.py b/nova/tests/test_netapp.py deleted file mode 100644 index 79a8526ee..000000000 --- a/nova/tests/test_netapp.py +++ /dev/null @@ -1,1380 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2012 NetApp, Inc. -# All Rights Reserved. -# -# 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. -""" -Tests for NetApp volume driver - -""" - -import BaseHTTPServer -import httplib -import StringIO - -from lxml import etree - -from nova.openstack.common import log as logging -from nova import test -from nova.volume import netapp - - -LOG = logging.getLogger(__name__) - - -WSDL_HEADER = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" - xmlns:na="http://www.netapp.com/management/v1" - xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" - xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="NetAppDfm" - targetNamespace="http://www.netapp.com/management/v1">""" - -WSDL_TYPES = """<types> -<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" - targetNamespace="http://www.netapp.com/management/v1"> -<xsd:element name="ApiProxy"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Request" type="na:Request"/> - <xsd:element name="Target" type="xsd:string"/> - <xsd:element minOccurs="0" name="Timeout" type="xsd:integer"/> - <xsd:element minOccurs="0" name="Username" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="ApiProxyResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Response" type="na:Response"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditBegin"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetNameOrId" type="na:ObjNameOrId"/> - <xsd:element minOccurs="0" name="Force" type="xsd:boolean"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditBeginResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditCommit"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="AssumeConfirmation" - type="xsd:boolean"/> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditCommitResult"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="IsProvisioningFailure" - type="xsd:boolean"/> - <xsd:element minOccurs="0" name="JobIds" type="na:ArrayOfJobInfo"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditRollback"> - <xsd:complexType> - <xsd:all> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetEditRollbackResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Datasets" type="na:ArrayOfDatasetInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ObjectNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetMembers" - type="na:ArrayOfDatasetMemberInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetNameOrId" type="na:ObjNameOrId"/> - <xsd:element minOccurs="0" name="IncludeExportsInfo" - type="xsd:boolean"/> - <xsd:element minOccurs="0" name="IncludeIndirect" - type="xsd:boolean"/> - <xsd:element minOccurs="0" name="MemberType" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetMemberListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetProvisionMember"> - <xsd:complexType> - <xsd:all> - <xsd:element name="EditLockId" type="xsd:integer"/> - <xsd:element name="ProvisionMemberRequestInfo" - type="na:ProvisionMemberRequestInfo"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetProvisionMemberResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DatasetRemoveMember"> - <xsd:complexType> - <xsd:all> - <xsd:element name="DatasetMemberParameters" - type="na:ArrayOfDatasetMemberParameter"/> - <xsd:element minOccurs="0" name="Destroy" type="xsd:boolean"/> - <xsd:element name="EditLockId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DatasetRemoveMemberResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="ProgressEvents" - type="na:ArrayOfDpJobProgressEventInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="JobId" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DpJobProgressEventListIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DfmAbout"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="IncludeDirectorySizeInfo" - type="xsd:boolean"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="DfmAboutResult"> - <xsd:complexType> - <xsd:all/> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="HostListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Hosts" type="na:ArrayOfHostInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ObjectNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="HostListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterEnd"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterEndResult"> - <xsd:complexType/> -</xsd:element> -<xsd:element name="LunListInfoIterNext"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Maximum" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterNextResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Luns" type="na:ArrayOfLunInfo"/> - <xsd:element name="Records" type="xsd:integer"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterStart"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ObjectNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="LunListInfoIterStartResult"> - <xsd:complexType> - <xsd:all> - <xsd:element name="Records" type="xsd:integer"/> - <xsd:element name="Tag" type="xsd:string"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="StorageServiceDatasetProvision"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="AssumeConfirmation" - type="xsd:boolean"/> - <xsd:element name="DatasetName" type="na:ObjName"/> - <xsd:element name="StorageServiceNameOrId" type="na:ObjNameOrId"/> - <xsd:element minOccurs="0" name="StorageSetDetails" - type="na:ArrayOfStorageSetInfo"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:element name="StorageServiceDatasetProvisionResult"> - <xsd:complexType> - <xsd:all> - <xsd:element minOccurs="0" name="ConformanceAlerts" - type="na:ArrayOfConformanceAlert"/> - <xsd:element name="DatasetId" type="na:ObjId"/> - <xsd:element minOccurs="0" name="DryRunResults" - type="na:ArrayOfDryRunResult"/> - </xsd:all> - </xsd:complexType> -</xsd:element> -<xsd:complexType name="ArrayOfDatasetInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DatasetInfo" - type="na:DatasetInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDatasetMemberInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DatasetMemberInfo" - type="na:DatasetMemberInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDatasetMemberParameter"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DatasetMemberParameter" - type="na:DatasetMemberParameter"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDfmMetadataField"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DfmMetadataField" - type="na:DfmMetadataField"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfDpJobProgressEventInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="DpJobProgressEventInfo" - type="na:DpJobProgressEventInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfHostInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="HostInfo" type="na:HostInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfJobInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="JobInfo" type="na:JobInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfLunInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="LunInfo" type="na:LunInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="ArrayOfStorageSetInfo"> - <xsd:sequence> - <xsd:element maxOccurs="unbounded" name="StorageSetInfo" - type="na:StorageSetInfo"/> - </xsd:sequence> -</xsd:complexType> -<xsd:complexType name="DatasetExportInfo"> - <xsd:all> - <xsd:element minOccurs="0" name="DatasetExportProtocol" - type="na:DatasetExportProtocol"/> - <xsd:element minOccurs="0" name="DatasetLunMappingInfo" - type="na:DatasetLunMappingInfo"/> - </xsd:all> -</xsd:complexType> -<xsd:simpleType name="DatasetExportProtocol"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:complexType name="DatasetInfo"> - <xsd:all> - <xsd:element name="DatasetId" type="na:ObjId"/> - <xsd:element name="DatasetName" type="na:ObjName"/> - <xsd:element name="DatasetMetadata" type="na:ArrayOfDfmMetadataField"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DatasetLunMappingInfo"> - <xsd:all> - <xsd:element name="IgroupOsType" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DatasetMemberInfo"> - <xsd:all> - <xsd:element name="MemberId" type="na:ObjId"/> - <xsd:element name="MemberName" type="na:ObjName"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DatasetMemberParameter"> - <xsd:all> - <xsd:element name="ObjectNameOrId" type="na:ObjNameOrId"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DfmMetadataField"> - <xsd:all> - <xsd:element name="FieldName" type="xsd:string"/> - <xsd:element name="FieldValue" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="DpJobProgressEventInfo"> - <xsd:all> - <xsd:element name="EventStatus" type="na:ObjStatus"/> - <xsd:element name="EventType" type="xsd:string"/> - <xsd:element minOccurs="0" name="ProgressLunInfo" - type="na:ProgressLunInfo"/> - </xsd:all> -</xsd:complexType> -<xsd:simpleType name="DpPolicyNodeName"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:simpleType name="HostId"> - <xsd:restriction base="xsd:integer"/> -</xsd:simpleType> -<xsd:complexType name="HostInfo"> - <xsd:all> - <xsd:element name="HostAddress" type="xsd:string"/> - <xsd:element name="HostId" type="na:HostId"/> - <xsd:element name="HostName" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="JobInfo"> - <xsd:all> - <xsd:element name="JobId" type="xsd:integer"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="LunInfo"> - <xsd:all> - <xsd:element name="HostId" type="na:ObjId"/> - <xsd:element name="LunPath" type="na:ObjName"/> - </xsd:all> -</xsd:complexType> -<xsd:simpleType name="ObjId"> - <xsd:restriction base="xsd:integer"/> -</xsd:simpleType> -<xsd:simpleType name="ObjName"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:simpleType name="ObjNameOrId"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:simpleType name="ObjStatus"> - <xsd:restriction base="xsd:string"/> -</xsd:simpleType> -<xsd:complexType name="ProgressLunInfo"> - <xsd:all> - <xsd:element name="LunPathId" type="na:ObjId"/> - <xsd:element name="LunName" type="na:ObjName"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="ProvisionMemberRequestInfo"> - <xsd:all> - <xsd:element minOccurs="0" name="Description" type="xsd:string"/> - <xsd:element minOccurs="0" name="MaximumSnapshotSpace" - type="xsd:integer"/> - <xsd:element name="Name" type="xsd:string"/> - <xsd:element name="Size" type="xsd:integer"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="Request"> - <xsd:all> - <xsd:element minOccurs="0" name="Args"> - <xsd:complexType> - <xsd:sequence> - <xsd:any maxOccurs="unbounded" minOccurs="0"/> - </xsd:sequence> - </xsd:complexType> - </xsd:element> - <xsd:element name="Name" type="xsd:string"> - </xsd:element> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="Response"> - <xsd:all> - <xsd:element minOccurs="0" name="Errno" type="xsd:integer"/> - <xsd:element minOccurs="0" name="Reason" type="xsd:string"/> - <xsd:element minOccurs="0" name="Results"> - <xsd:complexType> - <xsd:sequence> - <xsd:any maxOccurs="unbounded" minOccurs="0"/> - </xsd:sequence> - </xsd:complexType> - </xsd:element> - <xsd:element name="Status" type="xsd:string"/> - </xsd:all> -</xsd:complexType> -<xsd:complexType name="StorageSetInfo"> - <xsd:all> - <xsd:element minOccurs="0" name="DatasetExportInfo" - type="na:DatasetExportInfo"/> - <xsd:element minOccurs="0" name="DpNodeName" - type="na:DpPolicyNodeName"/> - <xsd:element minOccurs="0" name="ServerNameOrId" - type="na:ObjNameOrId"/> - </xsd:all> -</xsd:complexType> -</xsd:schema></types>""" - -WSDL_TRAILER = """<service name="DfmService"> -<port binding="na:DfmBinding" name="DfmPort"> -<soap:address location="https://HOST_NAME:8488/apis/soap/v1"/> -</port></service></definitions>""" - -RESPONSE_PREFIX = """<?xml version="1.0" encoding="UTF-8"?> -<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" - xmlns:na="http://www.netapp.com/management/v1"><env:Header/><env:Body>""" - -RESPONSE_SUFFIX = """</env:Body></env:Envelope>""" - -APIS = ['ApiProxy', 'DatasetListInfoIterStart', 'DatasetListInfoIterNext', - 'DatasetListInfoIterEnd', 'DatasetEditBegin', 'DatasetEditCommit', - 'DatasetProvisionMember', 'DatasetRemoveMember', 'DfmAbout', - 'DpJobProgressEventListIterStart', 'DpJobProgressEventListIterNext', - 'DpJobProgressEventListIterEnd', 'DatasetMemberListInfoIterStart', - 'DatasetMemberListInfoIterNext', 'DatasetMemberListInfoIterEnd', - 'HostListInfoIterStart', 'HostListInfoIterNext', 'HostListInfoIterEnd', - 'LunListInfoIterStart', 'LunListInfoIterNext', 'LunListInfoIterEnd', - 'StorageServiceDatasetProvision'] - -iter_count = 0 -iter_table = {} - - -class FakeDfmServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """HTTP handler that fakes enough stuff to allow the driver to run""" - - def do_GET(s): - """Respond to a GET request.""" - if '/dfm.wsdl' != s.path: - s.send_response(404) - s.end_headers - return - s.send_response(200) - s.send_header("Content-Type", "application/wsdl+xml") - s.end_headers() - out = s.wfile - out.write(WSDL_HEADER) - out.write(WSDL_TYPES) - for api in APIS: - out.write('<message name="%sRequest">' % api) - out.write('<part element="na:%s" name="parameters"/>' % api) - out.write('</message>') - out.write('<message name="%sResponse">' % api) - out.write('<part element="na:%sResult" name="results"/>' % api) - out.write('</message>') - out.write('<portType name="DfmInterface">') - for api in APIS: - out.write('<operation name="%s">' % api) - out.write('<input message="na:%sRequest"/>' % api) - out.write('<output message="na:%sResponse"/>' % api) - out.write('</operation>') - out.write('</portType>') - out.write('<binding name="DfmBinding" type="na:DfmInterface">') - out.write('<soap:binding style="document" ' + - 'transport="http://schemas.xmlsoap.org/soap/http"/>') - for api in APIS: - out.write('<operation name="%s">' % api) - out.write('<soap:operation soapAction="urn:%s"/>' % api) - out.write('<input><soap:body use="literal"/></input>') - out.write('<output><soap:body use="literal"/></output>') - out.write('</operation>') - out.write('</binding>') - out.write(WSDL_TRAILER) - - def do_POST(s): - """Respond to a POST request.""" - if '/apis/soap/v1' != s.path: - s.send_response(404) - s.end_headers - return - request_xml = s.rfile.read(int(s.headers['Content-Length'])) - ntap_ns = 'http://www.netapp.com/management/v1' - nsmap = {'env': 'http://schemas.xmlsoap.org/soap/envelope/', - 'na': ntap_ns} - root = etree.fromstring(request_xml) - - body = root.xpath('/env:Envelope/env:Body', namespaces=nsmap)[0] - request = body.getchildren()[0] - tag = request.tag - if not tag.startswith('{' + ntap_ns + '}'): - s.send_response(500) - s.end_headers - return - api = tag[(2 + len(ntap_ns)):] - global iter_count - global iter_table - if 'DatasetListInfoIterStart' == api: - iter_name = 'dataset_%s' % iter_count - iter_count = iter_count + 1 - iter_table[iter_name] = 0 - body = """<na:DatasetListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>%s</na:Tag> - </na:DatasetListInfoIterStartResult>""" % iter_name - elif 'DatasetListInfoIterNext' == api: - tags = body.xpath('na:DatasetListInfoIterNext/na:Tag', - namespaces=nsmap) - iter_name = tags[0].text - if iter_table[iter_name]: - body = """<na:DatasetListInfoIterNextResult> - <na:Datasets></na:Datasets> - <na:Records>0</na:Records> - </na:DatasetListInfoIterNextResult>""" - else: - iter_table[iter_name] = 1 - body = """<na:DatasetListInfoIterNextResult> - <na:Datasets> - <na:DatasetInfo> - <na:DatasetId>0</na:DatasetId> - <na:DatasetMetadata> - <na:DfmMetadataField> - <na:FieldName>OpenStackProject</na:FieldName> - <na:FieldValue>testproj</na:FieldValue> - </na:DfmMetadataField> - <na:DfmMetadataField> - <na:FieldName>OpenStackVolType</na:FieldName> - <na:FieldValue></na:FieldValue> - </na:DfmMetadataField> - </na:DatasetMetadata> - <na:DatasetName>OpenStack_testproj</na:DatasetName> - </na:DatasetInfo> - </na:Datasets> - <na:Records>1</na:Records> - </na:DatasetListInfoIterNextResult>""" - elif 'DatasetListInfoIterEnd' == api: - body = """<na:DatasetListInfoIterEndResult/>""" - elif 'DatasetEditBegin' == api: - body = """<na:DatasetEditBeginResult> - <na:EditLockId>0</na:EditLockId> - </na:DatasetEditBeginResult>""" - elif 'DatasetEditCommit' == api: - body = """<na:DatasetEditCommitResult> - <na:IsProvisioningFailure>false</na:IsProvisioningFailure> - <na:JobIds> - <na:JobInfo> - <na:JobId>0</na:JobId> - </na:JobInfo> - </na:JobIds> - </na:DatasetEditCommitResult>""" - elif 'DatasetProvisionMember' == api: - body = """<na:DatasetProvisionMemberResult/>""" - elif 'DatasetRemoveMember' == api: - body = """<na:DatasetRemoveMemberResult/>""" - elif 'DfmAbout' == api: - body = """<na:DfmAboutResult/>""" - elif 'DpJobProgressEventListIterStart' == api: - iter_name = 'dpjobprogress_%s' % iter_count - iter_count = iter_count + 1 - iter_table[iter_name] = 0 - body = """<na:DpJobProgressEventListIterStartResult> - <na:Records>2</na:Records> - <na:Tag>%s</na:Tag> - </na:DpJobProgressEventListIterStartResult>""" % iter_name - elif 'DpJobProgressEventListIterNext' == api: - tags = body.xpath('na:DpJobProgressEventListIterNext/na:Tag', - namespaces=nsmap) - iter_name = tags[0].text - if iter_table[iter_name]: - body = """<na:DpJobProgressEventListIterNextResult/>""" - else: - iter_table[iter_name] = 1 - name = ('filer:/OpenStack_testproj/volume-00000001/' - 'volume-00000001') - body = """<na:DpJobProgressEventListIterNextResult> - <na:ProgressEvents> - <na:DpJobProgressEventInfo> - <na:EventStatus>normal</na:EventStatus> - <na:EventType>lun-create</na:EventType> - <na:ProgressLunInfo> - <na:LunPathId>0</na:LunPathId> - <na:LunName>%s</na:LunName> - </na:ProgressLunInfo> - </na:DpJobProgressEventInfo> - <na:DpJobProgressEventInfo> - <na:EventStatus>normal</na:EventStatus> - <na:EventType>job-end</na:EventType> - </na:DpJobProgressEventInfo> - </na:ProgressEvents> - <na:Records>2</na:Records> - </na:DpJobProgressEventListIterNextResult>""" % name - elif 'DpJobProgressEventListIterEnd' == api: - body = """<na:DpJobProgressEventListIterEndResult/>""" - elif 'DatasetMemberListInfoIterStart' == api: - iter_name = 'datasetmember_%s' % iter_count - iter_count = iter_count + 1 - iter_table[iter_name] = 0 - body = """<na:DatasetMemberListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>%s</na:Tag> - </na:DatasetMemberListInfoIterStartResult>""" % iter_name - elif 'DatasetMemberListInfoIterNext' == api: - tags = body.xpath('na:DatasetMemberListInfoIterNext/na:Tag', - namespaces=nsmap) - iter_name = tags[0].text - if iter_table[iter_name]: - body = """<na:DatasetMemberListInfoIterNextResult> - <na:DatasetMembers></na:DatasetMembers> - <na:Records>0</na:Records> - </na:DatasetMemberListInfoIterNextResult>""" - else: - iter_table[iter_name] = 1 - name = ('filer:/OpenStack_testproj/volume-00000001/' - 'volume-00000001') - body = """<na:DatasetMemberListInfoIterNextResult> - <na:DatasetMembers> - <na:DatasetMemberInfo> - <na:MemberId>0</na:MemberId> - <na:MemberName>%s</na:MemberName> - </na:DatasetMemberInfo> - </na:DatasetMembers> - <na:Records>1</na:Records> - </na:DatasetMemberListInfoIterNextResult>""" % name - elif 'DatasetMemberListInfoIterEnd' == api: - body = """<na:DatasetMemberListInfoIterEndResult/>""" - elif 'HostListInfoIterStart' == api: - body = """<na:HostListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>host</na:Tag> - </na:HostListInfoIterStartResult>""" - elif 'HostListInfoIterNext' == api: - body = """<na:HostListInfoIterNextResult> - <na:Hosts> - <na:HostInfo> - <na:HostAddress>1.2.3.4</na:HostAddress> - <na:HostId>0</na:HostId> - <na:HostName>filer</na:HostName> - </na:HostInfo> - </na:Hosts> - <na:Records>1</na:Records> - </na:HostListInfoIterNextResult>""" - elif 'HostListInfoIterEnd' == api: - body = """<na:HostListInfoIterEndResult/>""" - elif 'LunListInfoIterStart' == api: - body = """<na:LunListInfoIterStartResult> - <na:Records>1</na:Records> - <na:Tag>lun</na:Tag> - </na:LunListInfoIterStartResult>""" - elif 'LunListInfoIterNext' == api: - path = 'OpenStack_testproj/volume-00000001/volume-00000001' - body = """<na:LunListInfoIterNextResult> - <na:Luns> - <na:LunInfo> - <na:HostId>0</na:HostId> - <na:LunPath>%s</na:LunPath> - </na:LunInfo> - </na:Luns> - <na:Records>1</na:Records> - </na:LunListInfoIterNextResult>""" % path - elif 'LunListInfoIterEnd' == api: - body = """<na:LunListInfoIterEndResult/>""" - elif 'ApiProxy' == api: - names = body.xpath('na:ApiProxy/na:Request/na:Name', - namespaces=nsmap) - proxy = names[0].text - if 'igroup-list-info' == proxy: - igroup = 'openstack-iqn.1993-08.org.debian:01:23456789' - initiator = 'iqn.1993-08.org.debian:01:23456789' - proxy_body = """<initiator-groups> - <initiator-group-info> - <initiator-group-name>%s</initiator-group-name> - <initiator-group-type>iscsi</initiator-group-type> - <initiator-group-os-type>linux</initiator-group-os-type> - <initiators> - <initiator-info> - <initiator-name>%s</initiator-name> - </initiator-info> - </initiators> - </initiator-group-info> - </initiator-groups>""" % (igroup, initiator) - elif 'igroup-create' == proxy: - proxy_body = '' - elif 'igroup-add' == proxy: - proxy_body = '' - elif 'lun-map-list-info' == proxy: - proxy_body = '<initiator-groups/>' - elif 'lun-map' == proxy: - proxy_body = '<lun-id-assigned>0</lun-id-assigned>' - elif 'lun-unmap' == proxy: - proxy_body = '' - elif 'iscsi-portal-list-info' == proxy: - proxy_body = """<iscsi-portal-list-entries> - <iscsi-portal-list-entry-info> - <ip-address>1.2.3.4</ip-address> - <ip-port>3260</ip-port> - <tpgroup-tag>1000</tpgroup-tag> - </iscsi-portal-list-entry-info> - </iscsi-portal-list-entries>""" - elif 'iscsi-node-get-name' == proxy: - target = 'iqn.1992-08.com.netapp:sn.111111111' - proxy_body = '<node-name>%s</node-name>' % target - else: - # Unknown proxy API - s.send_response(500) - s.end_headers - return - api = api + ':' + proxy - proxy_header = '<na:ApiProxyResult><na:Response><na:Results>' - proxy_trailer = """</na:Results><na:Status>passed</na:Status> - </na:Response></na:ApiProxyResult>""" - body = proxy_header + proxy_body + proxy_trailer - else: - # Unknown API - s.send_response(500) - s.end_headers - return - s.send_response(200) - s.send_header("Content-Type", "text/xml; charset=utf-8") - s.end_headers() - s.wfile.write(RESPONSE_PREFIX) - s.wfile.write(body) - s.wfile.write(RESPONSE_SUFFIX) - - -class FakeHttplibSocket(object): - """A fake socket implementation for httplib.HTTPResponse""" - def __init__(self, value): - self._rbuffer = StringIO.StringIO(value) - self._wbuffer = StringIO.StringIO('') - oldclose = self._wbuffer.close - - def newclose(): - self.result = self._wbuffer.getvalue() - oldclose() - self._wbuffer.close = newclose - - def makefile(self, mode, _other): - """Returns the socket's internal buffer""" - if mode == 'r' or mode == 'rb': - return self._rbuffer - if mode == 'w' or mode == 'wb': - return self._wbuffer - - -class FakeHTTPConnection(object): - """A fake httplib.HTTPConnection for netapp tests - - Requests made via this connection actually get translated and routed into - the fake Dfm handler above, we then turn the response into - the httplib.HTTPResponse that the caller expects. - """ - def __init__(self, host, timeout=None): - self.host = host - - def request(self, method, path, data=None, headers=None): - if not headers: - headers = {} - req_str = '%s %s HTTP/1.1\r\n' % (method, path) - for key, value in headers.iteritems(): - req_str += "%s: %s\r\n" % (key, value) - if data: - req_str += '\r\n%s' % data - - # NOTE(vish): normally the http transport normailizes from unicode - sock = FakeHttplibSocket(req_str.decode("latin-1").encode("utf-8")) - # NOTE(vish): stop the server from trying to look up address from - # the fake socket - FakeDfmServerHandler.address_string = lambda x: '127.0.0.1' - self.app = FakeDfmServerHandler(sock, '127.0.0.1:8088', None) - - self.sock = FakeHttplibSocket(sock.result) - self.http_response = httplib.HTTPResponse(self.sock) - - def set_debuglevel(self, level): - pass - - def getresponse(self): - self.http_response.begin() - return self.http_response - - def getresponsebody(self): - return self.sock.result - - -class NetAppDriverTestCase(test.TestCase): - """Test case for NetAppISCSIDriver""" - STORAGE_SERVICE = 'Openstack Service' - STORAGE_SERVICE_PREFIX = 'Openstack Service-' - PROJECT_ID = 'testproj' - VOLUME_NAME = 'volume-00000001' - VOLUME_TYPE = '' - VOLUME_SIZE = 2147483648L # 2 GB - INITIATOR = 'iqn.1993-08.org.debian:01:23456789' - - def setUp(self): - super(NetAppDriverTestCase, self).setUp() - driver = netapp.NetAppISCSIDriver() - self.stubs.Set(httplib, 'HTTPConnection', FakeHTTPConnection) - driver._create_client(wsdl_url='http://localhost:8088/dfm.wsdl', - login='root', password='password', - hostname='localhost', port=8088, cache=False) - driver._set_storage_service(self.STORAGE_SERVICE) - driver._set_storage_service_prefix(self.STORAGE_SERVICE_PREFIX) - driver._set_vfiler('') - self.driver = driver - - def test_connect(self): - self.driver.check_for_setup_error() - - def test_create_destroy(self): - self.driver._discover_luns() - self.driver._provision(self.VOLUME_NAME, None, self.PROJECT_ID, - self.VOLUME_TYPE, self.VOLUME_SIZE) - self.driver._remove_destroy(self.VOLUME_NAME, self.PROJECT_ID) - - def test_map_unmap(self): - self.driver._discover_luns() - self.driver._provision(self.VOLUME_NAME, None, self.PROJECT_ID, - self.VOLUME_TYPE, self.VOLUME_SIZE) - volume = {'name': self.VOLUME_NAME, 'project_id': self.PROJECT_ID, - 'id': 0, 'provider_auth': None} - updates = self.driver._get_export(volume) - self.assertTrue(updates['provider_location']) - volume['provider_location'] = updates['provider_location'] - connector = {'initiator': self.INITIATOR} - connection_info = self.driver.initialize_connection(volume, connector) - self.assertEqual(connection_info['driver_volume_type'], 'iscsi') - properties = connection_info['data'] - self.driver.terminate_connection(volume, connector) - self.driver._remove_destroy(self.VOLUME_NAME, self.PROJECT_ID) - - -WSDL_HEADER_CMODE = """<?xml version="1.0" encoding="UTF-8"?> -<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" - xmlns:na="http://cloud.netapp.com/" -xmlns:xsd="http://www.w3.org/2001/XMLSchema" -xmlns="http://schemas.xmlsoap.org/wsdl/" -targetNamespace="http://cloud.netapp.com/" name="CloudStorageService"> -""" - -WSDL_TYPES_CMODE = """<types> -<xs:schema xmlns:na="http://cloud.netapp.com/" -xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" -targetNamespace="http://cloud.netapp.com/"> - - <xs:element name="ProvisionLun"> - <xs:complexType> - <xs:all> - <xs:element name="Name" type="xs:string"/> - <xs:element name="Size" type="xsd:long"/> - <xs:element name="Metadata" type="na:Metadata" minOccurs="0" - maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="ProvisionLunResult"> - <xs:complexType> - <xs:all> - <xs:element name="Lun" type="na:Lun"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:element name="DestroyLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="DestroyLunResult"> - <xs:complexType> - <xs:all/> - </xs:complexType> - </xs:element> - - <xs:element name="CloneLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="NewName" type="xsd:string"/> - <xs:element name="Metadata" type="na:Metadata" minOccurs="0" - maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="CloneLunResult"> - <xs:complexType> - <xs:all> - <xs:element name="Lun" type="na:Lun"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:element name="MapLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="InitiatorType" type="xsd:string"/> - <xs:element name="InitiatorName" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="MapLunResult"> - <xs:complexType> - <xs:all/> - </xs:complexType> - </xs:element> - - <xs:element name="UnmapLun"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="InitiatorType" type="xsd:string"/> - <xs:element name="InitiatorName" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="UnmapLunResult"> - <xs:complexType> - <xs:all/> - </xs:complexType> - </xs:element> - - <xs:element name="ListLuns"> - <xs:complexType> - <xs:all> - <xs:element name="NameFilter" type="xsd:string" minOccurs="0"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="ListLunsResult"> - <xs:complexType> - <xs:all> - <xs:element name="Lun" type="na:Lun" minOccurs="0" - maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:element name="GetLunTargetDetails"> - <xs:complexType> - <xs:all> - <xs:element name="Handle" type="xsd:string"/> - <xs:element name="InitiatorType" type="xsd:string"/> - <xs:element name="InitiatorName" type="xsd:string"/> - </xs:all> - </xs:complexType> - </xs:element> - <xs:element name="GetLunTargetDetailsResult"> - <xs:complexType> - <xs:all> - <xs:element name="TargetDetails" type="na:TargetDetails" - minOccurs="0" maxOccurs="unbounded"/> - </xs:all> - </xs:complexType> - </xs:element> - - <xs:complexType name="Metadata"> - <xs:sequence> - <xs:element name="Key" type="xs:string"/> - <xs:element name="Value" type="xs:string"/> - </xs:sequence> - </xs:complexType> - - <xs:complexType name="Lun"> - <xs:sequence> - <xs:element name="Name" type="xs:string"/> - <xs:element name="Size" type="xs:long"/> - <xs:element name="Handle" type="xs:string"/> - <xs:element name="Metadata" type="na:Metadata" minOccurs="0" - maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - - <xs:complexType name="TargetDetails"> - <xs:sequence> - <xs:element name="Address" type="xs:string"/> - <xs:element name="Port" type="xs:int"/> - <xs:element name="Portal" type="xs:int"/> - <xs:element name="Iqn" type="xs:string"/> - <xs:element name="LunNumber" type="xs:int"/> - </xs:sequence> - </xs:complexType> - - </xs:schema></types>""" - -WSDL_TRAILER_CMODE = """<service name="CloudStorageService"> - <port name="CloudStoragePort" binding="na:CloudStorageBinding"> - <soap:address location="http://hostname:8080/ws/ntapcloud"/> - </port> - </service> -</definitions>""" - -RESPONSE_PREFIX_CMODE = """<?xml version='1.0' encoding='UTF-8'?> -<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> -<soapenv:Body>""" - -RESPONSE_SUFFIX_CMODE = """</soapenv:Body></soapenv:Envelope>""" - -CMODE_APIS = ['ProvisionLun', 'DestroyLun', 'CloneLun', 'MapLun', 'UnmapLun', - 'ListLuns', 'GetLunTargetDetails'] - - -class FakeCMODEServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """HTTP handler that fakes enough stuff to allow the driver to run""" - - def do_GET(s): - """Respond to a GET request.""" - if '/ntap_cloud.wsdl' != s.path: - s.send_response(404) - s.end_headers - return - s.send_response(200) - s.send_header("Content-Type", "application/wsdl+xml") - s.end_headers() - out = s.wfile - out.write(WSDL_HEADER_CMODE) - out.write(WSDL_TYPES_CMODE) - for api in CMODE_APIS: - out.write('<message name="%sRequest">' % api) - out.write('<part element="na:%s" name="req"/>' % api) - out.write('</message>') - out.write('<message name="%sResponse">' % api) - out.write('<part element="na:%sResult" name="res"/>' % api) - out.write('</message>') - out.write('<portType name="CloudStorage">') - for api in CMODE_APIS: - out.write('<operation name="%s">' % api) - out.write('<input message="na:%sRequest"/>' % api) - out.write('<output message="na:%sResponse"/>' % api) - out.write('</operation>') - out.write('</portType>') - out.write('<binding name="CloudStorageBinding" ' - 'type="na:CloudStorage">') - out.write('<soap:binding style="document" ' + - 'transport="http://schemas.xmlsoap.org/soap/http"/>') - for api in CMODE_APIS: - out.write('<operation name="%s">' % api) - out.write('<soap:operation soapAction=""/>') - out.write('<input><soap:body use="literal"/></input>') - out.write('<output><soap:body use="literal"/></output>') - out.write('</operation>') - out.write('</binding>') - out.write(WSDL_TRAILER_CMODE) - - def do_POST(s): - """Respond to a POST request.""" - if '/ws/ntapcloud' != s.path: - s.send_response(404) - s.end_headers - return - request_xml = s.rfile.read(int(s.headers['Content-Length'])) - ntap_ns = 'http://cloud.netapp.com/' - nsmap = {'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', - 'na': ntap_ns} - root = etree.fromstring(request_xml) - - body = root.xpath('/soapenv:Envelope/soapenv:Body', - namespaces=nsmap)[0] - request = body.getchildren()[0] - tag = request.tag - if not tag.startswith('{' + ntap_ns + '}'): - s.send_response(500) - s.end_headers - return - api = tag[(2 + len(ntap_ns)):] - if 'ProvisionLun' == api: - body = """<ns:ProvisionLunResult xmlns:ns= - "http://cloud.netapp.com/"> - <Lun><Name>lun1</Name><Size>20</Size> - <Handle>1d9c006c-a406-42f6-a23f-5ed7a6dc33e3</Handle> - <Metadata><Key>OsType</Key> - <Value>linux</Value></Metadata></Lun> - </ns:ProvisionLunResult>""" - elif 'DestroyLun' == api: - body = """<ns:DestroyLunResult xmlns:ns="http://cloud.netapp.com/" - />""" - elif 'CloneLun' == api: - body = """<ns:CloneLunResult xmlns:ns="http://cloud.netapp.com/"> - <Lun><Name>lun2</Name><Size>2</Size> - <Handle>98ea1791d228453899d422b4611642c3</Handle> - <Metadata><Key>OsType</Key> - <Value>linux</Value></Metadata> - </Lun></ns:CloneLunResult>""" - elif 'MapLun' == api: - body = """<ns1:MapLunResult xmlns:ns="http://cloud.netapp.com/" - />""" - elif 'Unmap' == api: - body = """<ns1:UnmapLunResult xmlns:ns="http://cloud.netapp.com/" - />""" - elif 'ListLuns' == api: - body = """<ns:ListLunsResult xmlns:ns="http://cloud.netapp.com/"> - <Lun> - <Name>lun1</Name> - <Size>20</Size> - <Handle>asdjdnsd</Handle> - </Lun> - </ns:ListLunsResult>""" - elif 'GetLunTargetDetails' == api: - body = """<ns:GetLunTargetDetailsResult - xmlns:ns="http://cloud.netapp.com/"> - <TargetDetail> - <Address>1.2.3.4</Address> - <Port>3260</Port> - <Portal>1000</Portal> - <Iqn>iqn.199208.com.netapp:sn.123456789</Iqn> - <LunNumber>0</LunNumber> - </TargetDetail> - </ns:GetLunTargetDetailsResult>""" - else: - # Unknown API - s.send_response(500) - s.end_headers - return - s.send_response(200) - s.send_header("Content-Type", "text/xml; charset=utf-8") - s.end_headers() - s.wfile.write(RESPONSE_PREFIX_CMODE) - s.wfile.write(body) - s.wfile.write(RESPONSE_SUFFIX_CMODE) - - -class FakeCmodeHTTPConnection(object): - """A fake httplib.HTTPConnection for netapp tests - - Requests made via this connection actually get translated and routed into - the fake Dfm handler above, we then turn the response into - the httplib.HTTPResponse that the caller expects. - """ - def __init__(self, host, timeout=None): - self.host = host - - def request(self, method, path, data=None, headers=None): - if not headers: - headers = {} - req_str = '%s %s HTTP/1.1\r\n' % (method, path) - for key, value in headers.iteritems(): - req_str += "%s: %s\r\n" % (key, value) - if data: - req_str += '\r\n%s' % data - - # NOTE(vish): normally the http transport normailizes from unicode - sock = FakeHttplibSocket(req_str.decode("latin-1").encode("utf-8")) - # NOTE(vish): stop the server from trying to look up address from - # the fake socket - FakeCMODEServerHandler.address_string = lambda x: '127.0.0.1' - self.app = FakeCMODEServerHandler(sock, '127.0.0.1:8080', None) - - self.sock = FakeHttplibSocket(sock.result) - self.http_response = httplib.HTTPResponse(self.sock) - - def set_debuglevel(self, level): - pass - - def getresponse(self): - self.http_response.begin() - return self.http_response - - def getresponsebody(self): - return self.sock.result - - -class NetAppCmodeISCSIDriverTestCase(test.TestCase): - """Test case for NetAppISCSIDriver""" - volume = { - 'name': 'lun1', 'size': 1, 'volume_name': 'lun1', - 'os_type': 'linux', 'provider_location': 'lun1', - 'id': 'lun1', 'provider_auth': None, 'project_id': 'project', - 'display_name': None, 'display_description': 'lun1', - 'volume_type_id': None - } - snapshot = { - 'name': 'lun2', 'size': 1, 'volume_name': 'lun1', - 'volume_size': 1, 'project_id': 'project' - } - volume_sec = { - 'name': 'vol_snapshot', 'size': 1, 'volume_name': 'lun1', - 'os_type': 'linux', 'provider_location': 'lun1', - 'id': 'lun1', 'provider_auth': None, 'project_id': 'project', - 'display_name': None, 'display_description': 'lun1', - 'volume_type_id': None - } - - def setUp(self): - super(NetAppCmodeISCSIDriverTestCase, self).setUp() - driver = netapp.NetAppCmodeISCSIDriver() - self.stubs.Set(httplib, 'HTTPConnection', FakeCmodeHTTPConnection) - driver._create_client(wsdl_url='http://localhost:8080/ntap_cloud.wsdl', - login='root', password='password', - hostname='localhost', port=8080, cache=False) - self.driver = driver - - def test_connect(self): - self.driver.check_for_setup_error() - - def test_create_destroy(self): - self.driver.create_volume(self.volume) - self.driver.delete_volume(self.volume) - - def test_create_vol_snapshot_destroy(self): - self.driver.create_volume(self.volume) - self.driver.create_snapshot(self.snapshot) - self.driver.create_volume_from_snapshot(self.volume_sec, self.snapshot) - self.driver.delete_snapshot(self.snapshot) - self.driver.delete_volume(self.volume) - - def test_map_unmap(self): - self.driver.create_volume(self.volume) - updates = self.driver.create_export(None, self.volume) - self.assertTrue(updates['provider_location']) - self.volume['provider_location'] = updates['provider_location'] - connector = {'initiator': 'init1'} - connection_info = self.driver.initialize_connection(self.volume, - connector) - self.assertEqual(connection_info['driver_volume_type'], 'iscsi') - properties = connection_info['data'] - self.driver.terminate_connection(self.volume, connector) - self.driver.delete_volume(self.volume) diff --git a/nova/tests/test_netapp_nfs.py b/nova/tests/test_netapp_nfs.py deleted file mode 100644 index 1a8824386..000000000 --- a/nova/tests/test_netapp_nfs.py +++ /dev/null @@ -1,234 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2012 NetApp, Inc. -# All Rights Reserved. -# -# 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. -"""Unit tests for the NetApp-specific NFS driver module (netapp_nfs)""" - -from nova import context -from nova import exception -from nova import test - -from nova.volume import netapp -from nova.volume import netapp_nfs -from nova.volume import nfs - -from mox import IgnoreArg -from mox import IsA -from mox import MockObject - -import mox -import suds -import types - - -class FakeVolume(object): - def __init__(self, size=0): - self.size = size - self.id = hash(self) - self.name = None - - def __getitem__(self, key): - return self.__dict__[key] - - -class FakeSnapshot(object): - def __init__(self, volume_size=0): - self.volume_name = None - self.name = None - self.volume_id = None - self.volume_size = volume_size - self.user_id = None - self.status = None - - def __getitem__(self, key): - return self.__dict__[key] - - -class FakeResponce(object): - def __init__(self, status): - """ - :param status: Either 'failed' or 'passed' - """ - self.Status = status - - if status == 'failed': - self.Reason = 'Sample error' - - -class NetappNfsDriverTestCase(test.TestCase): - """Test case for NetApp specific NFS clone driver""" - - def setUp(self): - self._driver = netapp_nfs.NetAppNFSDriver() - super(NetappNfsDriverTestCase, self).setUp() - - def test_check_for_setup_error(self): - mox = self.mox - drv = self._driver - - # check exception raises when flags are not set - self.assertRaises(exception.NovaException, - drv.check_for_setup_error) - - # set required flags - self.flags(netapp_wsdl_url='val', - netapp_login='val', - netapp_password='val', - netapp_server_hostname='val', - netapp_server_port='val') - - mox.StubOutWithMock(nfs.NfsDriver, 'check_for_setup_error') - nfs.NfsDriver.check_for_setup_error() - mox.ReplayAll() - - drv.check_for_setup_error() - - def test_do_setup(self): - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, 'check_for_setup_error') - mox.StubOutWithMock(netapp_nfs.NetAppNFSDriver, '_get_client') - - drv.check_for_setup_error() - netapp_nfs.NetAppNFSDriver._get_client() - - mox.ReplayAll() - - drv.do_setup(IsA(context.RequestContext)) - - def test_create_snapshot(self): - """Test snapshot can be created and deleted""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_clone_volume') - drv._clone_volume(IgnoreArg(), IgnoreArg(), IgnoreArg()) - mox.ReplayAll() - - drv.create_snapshot(FakeSnapshot()) - - def test_create_volume_from_snapshot(self): - """Tests volume creation from snapshot""" - drv = self._driver - mox = self.mox - volume = FakeVolume(1) - snapshot = FakeSnapshot(2) - - self.assertRaises(exception.NovaException, - drv.create_volume_from_snapshot, - volume, - snapshot) - - snapshot = FakeSnapshot(1) - - location = '127.0.0.1:/nfs' - expected_result = {'provider_location': location} - mox.StubOutWithMock(drv, '_clone_volume') - mox.StubOutWithMock(drv, '_get_volume_location') - drv._clone_volume(IgnoreArg(), IgnoreArg(), IgnoreArg()) - drv._get_volume_location(IgnoreArg()).AndReturn(location) - - mox.ReplayAll() - - loc = drv.create_volume_from_snapshot(volume, snapshot) - - self.assertEquals(loc, expected_result) - - def _prepare_delete_snapshot_mock(self, snapshot_exists): - drv = self._driver - mox = self.mox - - mox.StubOutWithMock(drv, '_get_provider_location') - mox.StubOutWithMock(drv, '_volume_not_present') - - if snapshot_exists: - mox.StubOutWithMock(drv, '_execute') - mox.StubOutWithMock(drv, '_get_volume_path') - - drv._get_provider_location(IgnoreArg()) - drv._volume_not_present(IgnoreArg(), IgnoreArg())\ - .AndReturn(not snapshot_exists) - - if snapshot_exists: - drv._get_volume_path(IgnoreArg(), IgnoreArg()) - drv._execute('rm', None, run_as_root=True) - - mox.ReplayAll() - - return mox - - def test_delete_existing_snapshot(self): - drv = self._driver - self._prepare_delete_snapshot_mock(True) - - drv.delete_snapshot(FakeSnapshot()) - - def test_delete_missing_snapshot(self): - drv = self._driver - self._prepare_delete_snapshot_mock(False) - - drv.delete_snapshot(FakeSnapshot()) - - def _prepare_clone_mock(self, status): - drv = self._driver - mox = self.mox - - volume = FakeVolume() - setattr(volume, 'provider_location', '127.0.0.1:/nfs') - - drv._client = MockObject(suds.client.Client) - drv._client.factory = MockObject(suds.client.Factory) - drv._client.service = MockObject(suds.client.ServiceSelector) - - # ApiProxy() method is generated by ServiceSelector at runtime from the - # XML, so mocking is impossible. - setattr(drv._client.service, - 'ApiProxy', - types.MethodType(lambda *args, **kwargs: FakeResponce(status), - suds.client.ServiceSelector)) - mox.StubOutWithMock(drv, '_get_host_id') - mox.StubOutWithMock(drv, '_get_full_export_path') - - drv._get_host_id(IgnoreArg()).AndReturn('10') - drv._get_full_export_path(IgnoreArg(), IgnoreArg()).AndReturn('/nfs') - - return mox - - def test_successfull_clone_volume(self): - drv = self._driver - mox = self._prepare_clone_mock('passed') - - mox.ReplayAll() - - volume_name = 'volume_name' - clone_name = 'clone_name' - volume_id = volume_name + str(hash(volume_name)) - - drv._clone_volume(volume_name, clone_name, volume_id) - - def test_failed_clone_volume(self): - drv = self._driver - mox = self._prepare_clone_mock('failed') - - mox.ReplayAll() - - volume_name = 'volume_name' - clone_name = 'clone_name' - volume_id = volume_name + str(hash(volume_name)) - - self.assertRaises(exception.NovaException, - drv._clone_volume, - volume_name, clone_name, volume_id) diff --git a/nova/tests/test_nexenta.py b/nova/tests/test_nexenta.py deleted file mode 100644 index aac877cc1..000000000 --- a/nova/tests/test_nexenta.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Nexenta Systems, Inc. -# All Rights Reserved. -# -# 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. -""" -Unit tests for OpenStack Nova volume driver -""" - -import base64 -import urllib2 - -import nova.flags -import nova.test -from nova.volume import nexenta -from nova.volume.nexenta import jsonrpc -from nova.volume.nexenta import volume - -FLAGS = nova.flags.FLAGS - - -class TestNexentaDriver(nova.test.TestCase): - TEST_VOLUME_NAME = 'volume1' - TEST_VOLUME_NAME2 = 'volume2' - TEST_SNAPSHOT_NAME = 'snapshot1' - TEST_VOLUME_REF = { - 'name': TEST_VOLUME_NAME, - 'size': 1, - } - TEST_VOLUME_REF2 = { - 'name': TEST_VOLUME_NAME2, - 'size': 1, - } - TEST_SNAPSHOT_REF = { - 'name': TEST_SNAPSHOT_NAME, - 'volume_name': TEST_VOLUME_NAME, - } - - def setUp(self): - super(TestNexentaDriver, self).setUp() - self.flags( - nexenta_host='1.1.1.1', - nexenta_volume='nova', - nexenta_target_prefix='iqn:', - nexenta_target_group_prefix='nova/', - nexenta_blocksize='8K', - nexenta_sparse=True, - ) - self.nms_mock = self.mox.CreateMockAnything() - for mod in ['volume', 'zvol', 'iscsitarget', - 'stmf', 'scsidisk', 'snapshot']: - setattr(self.nms_mock, mod, self.mox.CreateMockAnything()) - self.stubs.Set(jsonrpc, 'NexentaJSONProxy', - lambda *_, **__: self.nms_mock) - self.drv = volume.NexentaDriver() - self.drv.do_setup({}) - - def test_setup_error(self): - self.nms_mock.volume.object_exists('nova').AndReturn(True) - self.mox.ReplayAll() - self.drv.check_for_setup_error() - - def test_setup_error_fail(self): - self.nms_mock.volume.object_exists('nova').AndReturn(False) - self.mox.ReplayAll() - self.assertRaises(LookupError, self.drv.check_for_setup_error) - - def test_local_path(self): - self.assertRaises(NotImplementedError, self.drv.local_path, '') - - def test_create_volume(self): - self.nms_mock.zvol.create('nova/volume1', '1G', '8K', True) - self.mox.ReplayAll() - self.drv.create_volume(self.TEST_VOLUME_REF) - - def test_delete_volume(self): - self.nms_mock.zvol.destroy('nova/volume1', '') - self.mox.ReplayAll() - self.drv.delete_volume(self.TEST_VOLUME_REF) - - def test_create_snapshot(self): - self.nms_mock.zvol.create_snapshot('nova/volume1', 'snapshot1', '') - self.mox.ReplayAll() - self.drv.create_snapshot(self.TEST_SNAPSHOT_REF) - - def test_create_volume_from_snapshot(self): - self.nms_mock.zvol.clone('nova/volume1@snapshot1', 'nova/volume2') - self.mox.ReplayAll() - self.drv.create_volume_from_snapshot(self.TEST_VOLUME_REF2, - self.TEST_SNAPSHOT_REF) - - def test_delete_snapshot(self): - self.nms_mock.snapshot.destroy('nova/volume1@snapshot1', '') - self.mox.ReplayAll() - self.drv.delete_snapshot(self.TEST_SNAPSHOT_REF) - - _CREATE_EXPORT_METHODS = [ - ('iscsitarget', 'create_target', ({'target_name': 'iqn:volume1'},), - u'Unable to create iscsi target\n' - u' iSCSI target iqn.1986-03.com.sun:02:nova-volume1 already' - u' configured\n' - u' itadm create-target failed with error 17\n', - ), - ('stmf', 'create_targetgroup', ('nova/volume1',), - u'Unable to create targetgroup: stmfadm: nova/volume1:' - u' already exists\n', - ), - ('stmf', 'add_targetgroup_member', ('nova/volume1', 'iqn:volume1'), - u'Unable to add member to targetgroup: stmfadm:' - u' iqn.1986-03.com.sun:02:nova-volume1: already exists\n', - ), - ('scsidisk', 'create_lu', ('nova/volume1', {}), - u"Unable to create lu with zvol 'nova/volume1':\n" - u" sbdadm: filename /dev/zvol/rdsk/nova/volume1: in use\n", - ), - ('scsidisk', 'add_lun_mapping_entry', ('nova/volume1', { - 'target_group': 'nova/volume1', 'lun': '0'}), - u"Unable to add view to zvol 'nova/volume1' (LUNs in use: ):\n" - u" stmfadm: view entry exists\n", - ), - ] - - def _stub_export_method(self, module, method, args, error, fail=False): - m = getattr(self.nms_mock, module) - m = getattr(m, method) - mock = m(*args) - if fail: - mock.AndRaise(nexenta.NexentaException(error)) - - def _stub_all_export_methods(self, fail=False): - for params in self._CREATE_EXPORT_METHODS: - self._stub_export_method(*params, fail=fail) - - def test_create_export(self): - self._stub_all_export_methods() - self.mox.ReplayAll() - retval = self.drv.create_export({}, self.TEST_VOLUME_REF) - self.assertEquals(retval, - {'provider_location': - '%s:%s,1 %s%s' % (FLAGS.nexenta_host, - FLAGS.nexenta_iscsi_target_portal_port, - FLAGS.nexenta_target_prefix, - self.TEST_VOLUME_NAME)}) - - def __get_test(i): - def _test_create_export_fail(self): - for params in self._CREATE_EXPORT_METHODS[:i]: - self._stub_export_method(*params) - self._stub_export_method(*self._CREATE_EXPORT_METHODS[i], - fail=True) - self.mox.ReplayAll() - self.assertRaises(nexenta.NexentaException, - self.drv.create_export, {}, self.TEST_VOLUME_REF) - return _test_create_export_fail - - for i in range(len(_CREATE_EXPORT_METHODS)): - locals()['test_create_export_fail_%d' % i] = __get_test(i) - - def test_ensure_export(self): - self._stub_all_export_methods(fail=True) - self.mox.ReplayAll() - self.drv.ensure_export({}, self.TEST_VOLUME_REF) - - def test_remove_export(self): - self.nms_mock.scsidisk.delete_lu('nova/volume1') - self.nms_mock.stmf.destroy_targetgroup('nova/volume1') - self.nms_mock.iscsitarget.delete_target('iqn:volume1') - self.mox.ReplayAll() - self.drv.remove_export({}, self.TEST_VOLUME_REF) - - def test_remove_export_fail_0(self): - self.nms_mock.scsidisk.delete_lu('nova/volume1') - self.nms_mock.stmf.destroy_targetgroup('nova/volume1').AndRaise( - nexenta.NexentaException()) - self.nms_mock.iscsitarget.delete_target('iqn:volume1') - self.mox.ReplayAll() - self.drv.remove_export({}, self.TEST_VOLUME_REF) - - def test_remove_export_fail_1(self): - self.nms_mock.scsidisk.delete_lu('nova/volume1') - self.nms_mock.stmf.destroy_targetgroup('nova/volume1') - self.nms_mock.iscsitarget.delete_target('iqn:volume1').AndRaise( - nexenta.NexentaException()) - self.mox.ReplayAll() - self.drv.remove_export({}, self.TEST_VOLUME_REF) - - -class TestNexentaJSONRPC(nova.test.TestCase): - URL = 'http://example.com/' - URL_S = 'https://example.com/' - USER = 'user' - PASSWORD = 'password' - HEADERS = {'Authorization': 'Basic %s' % (base64.b64encode( - ':'.join((USER, PASSWORD))),), - 'Content-Type': 'application/json'} - REQUEST = 'the request' - - def setUp(self): - super(TestNexentaJSONRPC, self).setUp() - self.proxy = jsonrpc.NexentaJSONProxy( - self.URL, self.USER, self.PASSWORD, auto=True) - self.mox.StubOutWithMock(urllib2, 'Request', True) - self.mox.StubOutWithMock(urllib2, 'urlopen') - self.resp_mock = self.mox.CreateMockAnything() - self.resp_info_mock = self.mox.CreateMockAnything() - self.resp_mock.info().AndReturn(self.resp_info_mock) - urllib2.urlopen(self.REQUEST).AndReturn(self.resp_mock) - - def test_call(self): - urllib2.Request(self.URL, - '{"object": null, "params": ["arg1", "arg2"], "method": null}', - self.HEADERS).AndReturn(self.REQUEST) - self.resp_info_mock.status = '' - self.resp_mock.read().AndReturn( - '{"error": null, "result": "the result"}') - self.mox.ReplayAll() - result = self.proxy('arg1', 'arg2') - self.assertEquals("the result", result) - - def test_call_deep(self): - urllib2.Request(self.URL, - '{"object": "obj1.subobj", "params": ["arg1", "arg2"],' - ' "method": "meth"}', - self.HEADERS).AndReturn(self.REQUEST) - self.resp_info_mock.status = '' - self.resp_mock.read().AndReturn( - '{"error": null, "result": "the result"}') - self.mox.ReplayAll() - result = self.proxy.obj1.subobj.meth('arg1', 'arg2') - self.assertEquals("the result", result) - - def test_call_auto(self): - urllib2.Request(self.URL, - '{"object": null, "params": ["arg1", "arg2"], "method": null}', - self.HEADERS).AndReturn(self.REQUEST) - urllib2.Request(self.URL_S, - '{"object": null, "params": ["arg1", "arg2"], "method": null}', - self.HEADERS).AndReturn(self.REQUEST) - self.resp_info_mock.status = 'EOF in headers' - self.resp_mock.read().AndReturn( - '{"error": null, "result": "the result"}') - urllib2.urlopen(self.REQUEST).AndReturn(self.resp_mock) - self.mox.ReplayAll() - result = self.proxy('arg1', 'arg2') - self.assertEquals("the result", result) - - def test_call_error(self): - urllib2.Request(self.URL, - '{"object": null, "params": ["arg1", "arg2"], "method": null}', - self.HEADERS).AndReturn(self.REQUEST) - self.resp_info_mock.status = '' - self.resp_mock.read().AndReturn( - '{"error": {"message": "the error"}, "result": "the result"}') - self.mox.ReplayAll() - self.assertRaises(jsonrpc.NexentaJSONException, - self.proxy, 'arg1', 'arg2') - - def test_call_fail(self): - urllib2.Request(self.URL, - '{"object": null, "params": ["arg1", "arg2"], "method": null}', - self.HEADERS).AndReturn(self.REQUEST) - self.resp_info_mock.status = 'EOF in headers' - self.proxy.auto = False - self.mox.ReplayAll() - self.assertRaises(jsonrpc.NexentaJSONException, - self.proxy, 'arg1', 'arg2') diff --git a/nova/tests/test_nfs.py b/nova/tests/test_nfs.py deleted file mode 100644 index d0d235b1b..000000000 --- a/nova/tests/test_nfs.py +++ /dev/null @@ -1,569 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2012 NetApp, Inc. -# All Rights Reserved. -# -# 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. -"""Unit tests for the NFS driver module""" - -import __builtin__ -import errno -import os - -import mox as mox_lib -from mox import IgnoreArg -from mox import IsA -from mox import stubout - -from nova import context -from nova import exception -from nova.exception import ProcessExecutionError -from nova import test - -from nova.volume import nfs - - -class DumbVolume(object): - fields = {} - - def __setitem__(self, key, value): - self.fields[key] = value - - def __getitem__(self, item): - return self.fields[item] - - -class NfsDriverTestCase(test.TestCase): - """Test case for NFS driver""" - - TEST_NFS_EXPORT1 = 'nfs-host1:/export' - TEST_NFS_EXPORT2 = 'nfs-host2:/export' - TEST_SIZE_IN_GB = 1 - TEST_MNT_POINT = '/mnt/nfs' - TEST_MNT_POINT_BASE = '/mnt/test' - TEST_LOCAL_PATH = '/mnt/nfs/volume-123' - TEST_FILE_NAME = 'test.txt' - TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf' - ONE_GB_IN_BYTES = 1024 * 1024 * 1024 - - def setUp(self): - self._driver = nfs.NfsDriver() - super(NfsDriverTestCase, self).setUp() - - def stub_out_not_replaying(self, obj, attr_name): - attr_to_replace = getattr(obj, attr_name) - stub = mox_lib.MockObject(attr_to_replace) - self.stubs.Set(obj, attr_name, stub) - - def test_path_exists_should_return_true(self): - """_path_exists should return True if stat returns 0""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_execute') - drv._execute('stat', self.TEST_FILE_NAME, run_as_root=True) - - mox.ReplayAll() - - self.assertTrue(drv._path_exists(self.TEST_FILE_NAME)) - - def test_path_exists_should_return_false(self): - """_path_exists should return True if stat doesn't return 0""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_execute') - drv._execute('stat', self.TEST_FILE_NAME, run_as_root=True).\ - AndRaise(ProcessExecutionError( - stderr="stat: cannot stat `test.txt': No such file or directory")) - - mox.ReplayAll() - - self.assertFalse(drv._path_exists(self.TEST_FILE_NAME)) - - def test_local_path(self): - """local_path common use case""" - self.flags(nfs_mount_point_base=self.TEST_MNT_POINT_BASE) - drv = self._driver - - volume = DumbVolume() - volume['provider_location'] = self.TEST_NFS_EXPORT1 - volume['name'] = 'volume-123' - - self.assertEqual( - '/mnt/test/2f4f60214cf43c595666dd815f0360a4/volume-123', - drv.local_path(volume)) - - def test_mount_nfs_should_mount_correctly(self): - """_mount_nfs common case usage""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_path_exists') - drv._path_exists(self.TEST_MNT_POINT).AndReturn(True) - - mox.StubOutWithMock(drv, '_execute') - drv._execute('mount', '-t', 'nfs', self.TEST_NFS_EXPORT1, - self.TEST_MNT_POINT, run_as_root=True) - - mox.ReplayAll() - - drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT) - - def test_mount_nfs_should_suppress_already_mounted_error(self): - """_mount_nfs should suppress already mounted error if ensure=True - """ - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_path_exists') - drv._path_exists(self.TEST_MNT_POINT).AndReturn(True) - - mox.StubOutWithMock(drv, '_execute') - drv._execute('mount', '-t', 'nfs', self.TEST_NFS_EXPORT1, - self.TEST_MNT_POINT, run_as_root=True).\ - AndRaise(ProcessExecutionError( - stderr='is busy or already mounted')) - - mox.ReplayAll() - - drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT, ensure=True) - - def test_mount_nfs_should_reraise_already_mounted_error(self): - """_mount_nfs should not suppress already mounted error if ensure=False - """ - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_path_exists') - drv._path_exists(self.TEST_MNT_POINT).AndReturn(True) - - mox.StubOutWithMock(drv, '_execute') - drv._execute('mount', '-t', 'nfs', self.TEST_NFS_EXPORT1, - self.TEST_MNT_POINT, run_as_root=True).\ - AndRaise(ProcessExecutionError(stderr='is busy or already mounted')) - - mox.ReplayAll() - - self.assertRaises(ProcessExecutionError, drv._mount_nfs, - self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT, - ensure=False) - - def test_mount_nfs_should_create_mountpoint_if_not_yet(self): - """_mount_nfs should create mountpoint if it doesn't exist""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_path_exists') - drv._path_exists(self.TEST_MNT_POINT).AndReturn(False) - - mox.StubOutWithMock(drv, '_execute') - drv._execute('mkdir', '-p', self.TEST_MNT_POINT) - drv._execute(*([IgnoreArg()] * 5), run_as_root=IgnoreArg()) - - mox.ReplayAll() - - drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT) - - def test_mount_nfs_should_not_create_mountpoint_if_already(self): - """_mount_nfs should not create mountpoint if it already exists""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_path_exists') - drv._path_exists(self.TEST_MNT_POINT).AndReturn(True) - - mox.StubOutWithMock(drv, '_execute') - drv._execute(*([IgnoreArg()] * 5), run_as_root=IgnoreArg()) - - mox.ReplayAll() - - drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT) - - def test_get_hash_str(self): - """_get_hash_str should calculation correct value""" - drv = self._driver - - self.assertEqual('2f4f60214cf43c595666dd815f0360a4', - drv._get_hash_str(self.TEST_NFS_EXPORT1)) - - def test_get_mount_point_for_share(self): - """_get_mount_point_for_share should calculate correct value""" - drv = self._driver - - self.flags(nfs_mount_point_base=self.TEST_MNT_POINT_BASE) - - self.assertEqual('/mnt/test/2f4f60214cf43c595666dd815f0360a4', - drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1)) - - def test_get_available_capacity_with_df(self): - """_get_available_capacity should calculate correct value""" - mox = self.mox - drv = self._driver - - df_avail = 1490560 - df_head = 'Filesystem 1K-blocks Used Available Use% Mounted on\n' - df_data = 'nfs-host:/export 2620544 996864 %d 41%% /mnt' % df_avail - df_output = df_head + df_data - - self.flags(nfs_disk_util='df') - - mox.StubOutWithMock(drv, '_get_mount_point_for_share') - drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1).\ - AndReturn(self.TEST_MNT_POINT) - - mox.StubOutWithMock(drv, '_execute') - drv._execute('df', '-P', '-B', '1', self.TEST_MNT_POINT, - run_as_root=True).AndReturn((df_output, None)) - - mox.ReplayAll() - - self.assertEquals(df_avail, - drv._get_available_capacity(self.TEST_NFS_EXPORT1)) - - def test_get_available_capacity_with_du(self): - """_get_available_capacity should calculate correct value""" - mox = self.mox - drv = self._driver - - self.flags(nfs_disk_util='du') - - df_total_size = 2620544 - df_used_size = 996864 - df_avail_size = 1490560 - df_title = 'Filesystem 1-blocks Used Available Use% Mounted on\n' - df_mnt_data = 'nfs-host:/export %d %d %d 41%% /mnt' % (df_total_size, - df_used_size, - df_avail_size) - df_output = df_title + df_mnt_data - - du_used = 490560 - du_output = '%d /mnt' % du_used - - mox.StubOutWithMock(drv, '_get_mount_point_for_share') - drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1).\ - AndReturn(self.TEST_MNT_POINT) - - mox.StubOutWithMock(drv, '_execute') - drv._execute('df', '-P', '-B', '1', self.TEST_MNT_POINT, - run_as_root=True).\ - AndReturn((df_output, None)) - drv._execute('du', '-sb', '--apparent-size', - '--exclude', '*snapshot*', - self.TEST_MNT_POINT, - run_as_root=True).AndReturn((du_output, None)) - - mox.ReplayAll() - - self.assertEquals(df_total_size - du_used, - drv._get_available_capacity(self.TEST_NFS_EXPORT1)) - - def test_load_shares_config(self): - mox = self.mox - drv = self._driver - - self.flags(nfs_shares_config=self.TEST_SHARES_CONFIG_FILE) - - mox.StubOutWithMock(__builtin__, 'open') - config_data = [] - config_data.append(self.TEST_NFS_EXPORT1) - config_data.append('#' + self.TEST_NFS_EXPORT2) - config_data.append('') - __builtin__.open(self.TEST_SHARES_CONFIG_FILE).AndReturn(config_data) - mox.ReplayAll() - - shares = drv._load_shares_config() - - self.assertEqual([self.TEST_NFS_EXPORT1], shares) - - def test_ensure_share_mounted(self): - """_ensure_share_mounted simple use case""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_get_mount_point_for_share') - drv._get_mount_point_for_share(self.TEST_NFS_EXPORT1).\ - AndReturn(self.TEST_MNT_POINT) - - mox.StubOutWithMock(drv, '_mount_nfs') - drv._mount_nfs(self.TEST_NFS_EXPORT1, self.TEST_MNT_POINT, ensure=True) - - mox.ReplayAll() - - drv._ensure_share_mounted(self.TEST_NFS_EXPORT1) - - def test_ensure_shares_mounted_should_save_mounting_successfully(self): - """_ensure_shares_mounted should save share if mounted with success""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_load_shares_config') - drv._load_shares_config().AndReturn([self.TEST_NFS_EXPORT1]) - mox.StubOutWithMock(drv, '_ensure_share_mounted') - drv._ensure_share_mounted(self.TEST_NFS_EXPORT1) - - mox.ReplayAll() - - drv._ensure_shares_mounted() - - self.assertEqual(1, len(drv._mounted_shares)) - self.assertEqual(self.TEST_NFS_EXPORT1, drv._mounted_shares[0]) - - def test_ensure_shares_mounted_should_not_save_mounting_with_error(self): - """_ensure_shares_mounted should not save share if failed to mount""" - mox = self.mox - drv = self._driver - - mox.StubOutWithMock(drv, '_load_shares_config') - drv._load_shares_config().AndReturn([self.TEST_NFS_EXPORT1]) - mox.StubOutWithMock(drv, '_ensure_share_mounted') - drv._ensure_share_mounted(self.TEST_NFS_EXPORT1).AndRaise(Exception()) - - mox.ReplayAll() - - drv._ensure_shares_mounted() - - self.assertEqual(0, len(drv._mounted_shares)) - - def test_setup_should_throw_error_if_shares_config_not_configured(self): - """do_setup should throw error if shares config is not configured """ - drv = self._driver - - self.flags(nfs_shares_config=self.TEST_SHARES_CONFIG_FILE) - - self.assertRaises(exception.NfsException, - drv.do_setup, IsA(context.RequestContext)) - - def test_setup_should_throw_exception_if_nfs_client_is_not_installed(self): - """do_setup should throw error if nfs client is not installed """ - mox = self.mox - drv = self._driver - - self.flags(nfs_shares_config=self.TEST_SHARES_CONFIG_FILE) - - mox.StubOutWithMock(os.path, 'exists') - os.path.exists(self.TEST_SHARES_CONFIG_FILE).AndReturn(True) - mox.StubOutWithMock(drv, '_execute') - drv._execute('mount.nfs', check_exit_code=False).\ - AndRaise(OSError(errno.ENOENT, 'No such file or directory')) - - mox.ReplayAll() - - self.assertRaises(exception.NfsException, - drv.do_setup, IsA(context.RequestContext)) - - def test_find_share_should_throw_error_if_there_is_no_mounted_shares(self): - """_find_share should throw error if there is no mounted shares""" - drv = self._driver - - drv._mounted_shares = [] - - self.assertRaises(exception.NotFound, drv._find_share, - self.TEST_SIZE_IN_GB) - - def test_find_share(self): - """_find_share simple use case""" - mox = self.mox - drv = self._driver - - drv._mounted_shares = [self.TEST_NFS_EXPORT1, self.TEST_NFS_EXPORT2] - - mox.StubOutWithMock(drv, '_get_available_capacity') - drv._get_available_capacity(self.TEST_NFS_EXPORT1).\ - AndReturn(2 * self.ONE_GB_IN_BYTES) - drv._get_available_capacity(self.TEST_NFS_EXPORT2).\ - AndReturn(3 * self.ONE_GB_IN_BYTES) - - mox.ReplayAll() - - self.assertEqual(self.TEST_NFS_EXPORT2, - drv._find_share(self.TEST_SIZE_IN_GB)) - - def test_find_share_should_throw_error_if_there_is_no_enough_place(self): - """_find_share should throw error if there is no share to host vol""" - mox = self.mox - drv = self._driver - - drv._mounted_shares = [self.TEST_NFS_EXPORT1, self.TEST_NFS_EXPORT2] - - mox.StubOutWithMock(drv, '_get_available_capacity') - drv._get_available_capacity(self.TEST_NFS_EXPORT1).\ - AndReturn(0) - drv._get_available_capacity(self.TEST_NFS_EXPORT2).\ - AndReturn(0) - - mox.ReplayAll() - - self.assertRaises(exception.NfsNoSuitableShareFound, drv._find_share, - self.TEST_SIZE_IN_GB) - - def _simple_volume(self): - volume = DumbVolume() - volume['provider_location'] = '127.0.0.1:/mnt' - volume['name'] = 'volume_name' - volume['size'] = 10 - - return volume - - def test_create_sparsed_volume(self): - mox = self.mox - drv = self._driver - volume = self._simple_volume() - - self.flags(nfs_sparsed_volumes=True) - - mox.StubOutWithMock(drv, '_create_sparsed_file') - mox.StubOutWithMock(drv, '_set_rw_permissions_for_all') - - drv._create_sparsed_file(IgnoreArg(), IgnoreArg()) - drv._set_rw_permissions_for_all(IgnoreArg()) - - mox.ReplayAll() - - drv._do_create_volume(volume) - - def test_create_nonsparsed_volume(self): - mox = self.mox - drv = self._driver - volume = self._simple_volume() - - self.flags(nfs_sparsed_volumes=False) - - mox.StubOutWithMock(drv, '_create_regular_file') - mox.StubOutWithMock(drv, '_set_rw_permissions_for_all') - - drv._create_regular_file(IgnoreArg(), IgnoreArg()) - drv._set_rw_permissions_for_all(IgnoreArg()) - - mox.ReplayAll() - - drv._do_create_volume(volume) - - def test_create_volume_should_ensure_nfs_mounted(self): - """create_volume should ensure shares provided in config are mounted""" - mox = self.mox - drv = self._driver - - self.stub_out_not_replaying(nfs, 'LOG') - self.stub_out_not_replaying(drv, '_find_share') - self.stub_out_not_replaying(drv, '_do_create_volume') - - mox.StubOutWithMock(drv, '_ensure_shares_mounted') - drv._ensure_shares_mounted() - - mox.ReplayAll() - - volume = DumbVolume() - volume['size'] = self.TEST_SIZE_IN_GB - drv.create_volume(volume) - - def test_create_volume_should_return_provider_location(self): - """create_volume should return provider_location with found share """ - mox = self.mox - drv = self._driver - - self.stub_out_not_replaying(nfs, 'LOG') - self.stub_out_not_replaying(drv, '_ensure_shares_mounted') - self.stub_out_not_replaying(drv, '_do_create_volume') - - mox.StubOutWithMock(drv, '_find_share') - drv._find_share(self.TEST_SIZE_IN_GB).AndReturn(self.TEST_NFS_EXPORT1) - - mox.ReplayAll() - - volume = DumbVolume() - volume['size'] = self.TEST_SIZE_IN_GB - result = drv.create_volume(volume) - self.assertEqual(self.TEST_NFS_EXPORT1, result['provider_location']) - - def test_delete_volume(self): - """delete_volume simple test case""" - mox = self.mox - drv = self._driver - - self.stub_out_not_replaying(drv, '_ensure_share_mounted') - - volume = DumbVolume() - volume['name'] = 'volume-123' - volume['provider_location'] = self.TEST_NFS_EXPORT1 - - mox.StubOutWithMock(drv, 'local_path') - drv.local_path(volume).AndReturn(self.TEST_LOCAL_PATH) - - mox.StubOutWithMock(drv, '_path_exists') - drv._path_exists(self.TEST_LOCAL_PATH).AndReturn(True) - - mox.StubOutWithMock(drv, '_execute') - drv._execute('rm', '-f', self.TEST_LOCAL_PATH, run_as_root=True) - - mox.ReplayAll() - - drv.delete_volume(volume) - - def test_delete_should_ensure_share_mounted(self): - """delete_volume should ensure that corresponding share is mounted""" - mox = self.mox - drv = self._driver - - self.stub_out_not_replaying(drv, '_execute') - - volume = DumbVolume() - volume['name'] = 'volume-123' - volume['provider_location'] = self.TEST_NFS_EXPORT1 - - mox.StubOutWithMock(drv, '_ensure_share_mounted') - drv._ensure_share_mounted(self.TEST_NFS_EXPORT1) - - mox.ReplayAll() - - drv.delete_volume(volume) - - def test_delete_should_not_delete_if_provider_location_not_provided(self): - """delete_volume shouldn't try to delete if provider_location missed""" - mox = self.mox - drv = self._driver - - self.stub_out_not_replaying(drv, '_ensure_share_mounted') - - volume = DumbVolume() - volume['name'] = 'volume-123' - volume['provider_location'] = None - - mox.StubOutWithMock(drv, '_execute') - - mox.ReplayAll() - - drv.delete_volume(volume) - - def test_delete_should_not_delete_if_there_is_no_file(self): - """delete_volume should not try to delete if file missed""" - mox = self.mox - drv = self._driver - - self.stub_out_not_replaying(drv, '_ensure_share_mounted') - - volume = DumbVolume() - volume['name'] = 'volume-123' - volume['provider_location'] = self.TEST_NFS_EXPORT1 - - mox.StubOutWithMock(drv, 'local_path') - drv.local_path(volume).AndReturn(self.TEST_LOCAL_PATH) - - mox.StubOutWithMock(drv, '_path_exists') - drv._path_exists(self.TEST_LOCAL_PATH).AndReturn(False) - - mox.StubOutWithMock(drv, '_execute') - - mox.ReplayAll() - - drv.delete_volume(volume) diff --git a/nova/tests/test_plugin_api_extensions.py b/nova/tests/test_plugin_api_extensions.py index af30c10d1..a40dd3276 100644 --- a/nova/tests/test_plugin_api_extensions.py +++ b/nova/tests/test_plugin_api_extensions.py @@ -72,7 +72,6 @@ class APITestCase(test.TestCase): # Marking out the default extension paths makes this test MUCH faster. self.flags(osapi_compute_extension=[]) - self.flags(osapi_volume_extension=[]) found = False mgr = computeextensions.ExtensionManager() diff --git a/nova/tests/test_quota.py b/nova/tests/test_quota.py index dd86c7c03..5ec753efe 100644 --- a/nova/tests/test_quota.py +++ b/nova/tests/test_quota.py @@ -127,27 +127,6 @@ class QuotaIntegrationTestCase(test.TestCase): image_href=image_uuid) db.instance_destroy(self.context, instance['uuid']) - def test_too_many_volumes(self): - volume_ids = [] - for i in range(FLAGS.quota_volumes): - volume_id = self._create_volume() - volume_ids.append(volume_id) - self.assertRaises(exception.QuotaError, - volume.API().create, - self.context, 10, '', '', None) - for volume_id in volume_ids: - db.volume_destroy(self.context, volume_id) - - def test_too_many_gigabytes(self): - volume_ids = [] - volume_id = self._create_volume(size=20) - volume_ids.append(volume_id) - self.assertRaises(exception.QuotaError, - volume.API().create, - self.context, 10, '', '', None) - for volume_id in volume_ids: - db.volume_destroy(self.context, volume_id) - def test_too_many_addresses(self): address = '192.168.0.100' db.floating_ip_create(context.get_admin_context(), @@ -720,8 +699,6 @@ class DbQuotaDriverTestCase(test.TestCase): self.flags(quota_instances=10, quota_cores=20, quota_ram=50 * 1024, - quota_volumes=10, - quota_gigabytes=1000, quota_floating_ips=10, quota_metadata_items=128, quota_injected_files=5, diff --git a/nova/tests/test_rbd.py b/nova/tests/test_rbd.py deleted file mode 100644 index 8e90f3ae8..000000000 --- a/nova/tests/test_rbd.py +++ /dev/null @@ -1,161 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Josh Durgin -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from nova import db -from nova import exception -from nova.openstack.common import log as logging -from nova.openstack.common import timeutils -from nova import test -from nova.tests.image import fake as fake_image -from nova.tests.test_volume import DriverTestCase -from nova.volume.driver import RBDDriver - -LOG = logging.getLogger(__name__) - - -class RBDTestCase(test.TestCase): - - def setUp(self): - super(RBDTestCase, self).setUp() - - def fake_execute(*args): - pass - self.driver = RBDDriver(execute=fake_execute) - - def test_good_locations(self): - locations = [ - 'rbd://fsid/pool/image/snap', - 'rbd://%2F/%2F/%2F/%2F', - ] - map(self.driver._parse_location, locations) - - def test_bad_locations(self): - locations = [ - 'rbd://image', - 'http://path/to/somewhere/else', - 'rbd://image/extra', - 'rbd://image/', - 'rbd://fsid/pool/image/', - 'rbd://fsid/pool/image/snap/', - 'rbd://///', - ] - for loc in locations: - self.assertRaises(exception.ImageUnacceptable, - self.driver._parse_location, - loc) - self.assertFalse(self.driver._is_cloneable(loc)) - - def test_cloneable(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') - location = 'rbd://abc/pool/image/snap' - self.assertTrue(self.driver._is_cloneable(location)) - - def test_uncloneable_different_fsid(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') - location = 'rbd://def/pool/image/snap' - self.assertFalse(self.driver._is_cloneable(location)) - - def test_uncloneable_unreadable(self): - def fake_exc(*args): - raise exception.ProcessExecutionError() - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') - self.stubs.Set(self.driver, '_execute', fake_exc) - location = 'rbd://abc/pool/image/snap' - self.assertFalse(self.driver._is_cloneable(location)) - - -class FakeRBDDriver(RBDDriver): - - def _clone(self): - pass - - def _resize(self): - pass - - -class ManagedRBDTestCase(DriverTestCase): - driver_name = "nova.tests.test_rbd.FakeRBDDriver" - - def setUp(self): - super(ManagedRBDTestCase, self).setUp() - fake_image.stub_out_image_service(self.stubs) - - def _clone_volume_from_image(self, expected_status, - clone_works=True): - """Try to clone a volume from an image, and check the status - afterwards""" - def fake_clone_image(volume, image_location): - pass - - def fake_clone_error(volume, image_location): - raise exception.NovaException() - - self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) - if clone_works: - self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_image) - else: - self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_error) - - image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' - volume_id = 1 - # creating volume testdata - db.volume_create(self.context, {'id': volume_id, - 'updated_at': timeutils.utcnow(), - 'display_description': 'Test Desc', - 'size': 20, - 'status': 'creating', - 'instance_uuid': None, - 'host': 'dummy'}) - try: - if clone_works: - self.volume.create_volume(self.context, - volume_id, - image_id=image_id) - else: - self.assertRaises(exception.NovaException, - 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) - - def test_clone_image_status_available(self): - """Verify that before cloning, an image is in the available state.""" - self._clone_volume_from_image('available', True) - - def test_clone_image_status_error(self): - """Verify that before cloning, an image is in the available state.""" - self._clone_volume_from_image('error', False) - - def test_clone_success(self): - self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) - self.stubs.Set(self.volume.driver, 'clone_image', lambda a, b: True) - image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' - self.assertTrue(self.volume.driver.clone_image({}, image_id)) - - def test_clone_bad_image_id(self): - self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) - self.assertFalse(self.volume.driver.clone_image({}, None)) - - def test_clone_uncloneable(self): - self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: False) - self.assertFalse(self.volume.driver.clone_image({}, 'dne')) diff --git a/nova/tests/test_solidfire.py b/nova/tests/test_solidfire.py deleted file mode 100644 index 87a211da5..000000000 --- a/nova/tests/test_solidfire.py +++ /dev/null @@ -1,208 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from nova import exception -from nova.openstack.common import log as logging -from nova import test -from nova.volume.solidfire import SolidFire - -LOG = logging.getLogger(__name__) - - -class SolidFireVolumeTestCase(test.TestCase): - def fake_issue_api_request(obj, method, params): - if method is 'GetClusterInfo': - LOG.info('Called Fake GetClusterInfo...') - results = {'result': {'clusterInfo': - {'name': 'fake-cluster', - 'mvip': '1.1.1.1', - 'svip': '1.1.1.1', - 'uniqueID': 'unqid', - 'repCount': 2, - 'attributes': {}}}} - return results - - elif method is 'AddAccount': - LOG.info('Called Fake AddAccount...') - return {'result': {'accountID': 25}, 'id': 1} - - elif method is 'GetAccountByName': - LOG.info('Called Fake GetAccountByName...') - results = {'result': {'account': - {'accountID': 25, - 'username': params['username'], - 'status': 'active', - 'initiatorSecret': '123456789012', - 'targetSecret': '123456789012', - 'attributes': {}, - 'volumes': [6, 7, 20]}}, - "id": 1} - return results - - elif method is 'CreateVolume': - LOG.info('Called Fake CreateVolume...') - return {'result': {'volumeID': 5}, 'id': 1} - - elif method is 'DeleteVolume': - LOG.info('Called Fake DeleteVolume...') - return {'result': {}, 'id': 1} - - elif method is 'ListVolumesForAccount': - test_name = 'OS-VOLID-a720b3c0-d1f0-11e1-9b23-0800200c9a66' - LOG.info('Called Fake ListVolumesForAccount...') - result = {'result': { - 'volumes': [{'volumeID': 5, - 'name': test_name, - 'accountID': 25, - 'sliceCount': 1, - 'totalSize': 1048576 * 1024, - 'enable512e': True, - 'access': "readWrite", - 'status': "active", - 'attributes':None, - 'qos': None, - 'iqn': test_name}]}} - return result - - else: - LOG.error('Crap, unimplemented API call in Fake:%s' % method) - - def fake_issue_api_request_no_volume(obj, method, params): - if method is 'ListVolumesForAccount': - LOG.info('Called Fake ListVolumesForAccount...') - return {'result': {'volumes': []}} - else: - return obj.fake_issue_api_request(method, params) - - def fake_issue_api_request_fails(obj, method, params): - return {'error': {'code': 000, - 'name': 'DummyError', - 'message': 'This is a fake error response'}, - 'id': 1} - - def fake_volume_get(obj, key, default=None): - return {'qos': 'fast'} - - def test_create_volume(self): - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request) - testvol = {'project_id': 'testprjid', - 'name': 'testvol', - 'size': 1, - 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'} - sfv = SolidFire() - model_update = sfv.create_volume(testvol) - - def test_create_volume_with_qos(self): - preset_qos = {} - preset_qos['qos'] = 'fast' - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request) - - testvol = {'project_id': 'testprjid', - 'name': 'testvol', - 'size': 1, - 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66', - 'metadata': [preset_qos]} - - sfv = SolidFire() - model_update = sfv.create_volume(testvol) - - def test_create_volume_fails(self): - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request_fails) - testvol = {'project_id': 'testprjid', - 'name': 'testvol', - 'size': 1, - 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'} - sfv = SolidFire() - self.assertRaises(exception.SolidFireAPIDataException, - sfv.create_volume, testvol) - - def test_create_sfaccount(self): - sfv = SolidFire() - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request) - account = sfv._create_sfaccount('project-id') - self.assertNotEqual(account, None) - - def test_create_sfaccount_fails(self): - sfv = SolidFire() - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request_fails) - account = sfv._create_sfaccount('project-id') - self.assertEqual(account, None) - - def test_get_sfaccount_by_name(self): - sfv = SolidFire() - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request) - account = sfv._get_sfaccount_by_name('some-name') - self.assertNotEqual(account, None) - - def test_get_sfaccount_by_name_fails(self): - sfv = SolidFire() - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request_fails) - account = sfv._get_sfaccount_by_name('some-name') - self.assertEqual(account, None) - - def test_delete_volume(self): - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request) - testvol = {'project_id': 'testprjid', - 'name': 'test_volume', - 'size': 1, - 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'} - sfv = SolidFire() - model_update = sfv.delete_volume(testvol) - - def test_delete_volume_fails_no_volume(self): - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request_no_volume) - testvol = {'project_id': 'testprjid', - 'name': 'no-name', - 'size': 1, - 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'} - sfv = SolidFire() - self.assertRaises(exception.VolumeNotFound, - sfv.delete_volume, testvol) - - def test_delete_volume_fails_account_lookup(self): - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request_fails) - testvol = {'project_id': 'testprjid', - 'name': 'no-name', - 'size': 1, - 'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'} - sfv = SolidFire() - self.assertRaises(exception.SfAccountNotFound, - sfv.delete_volume, - testvol) - - def test_get_cluster_info(self): - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request) - sfv = SolidFire() - sfv._get_cluster_info() - - def test_get_cluster_info_fail(self): - self.stubs.Set(SolidFire, '_issue_api_request', - self.fake_issue_api_request_fails) - sfv = SolidFire() - self.assertRaises(exception.SolidFireAPIException, - sfv._get_cluster_info) diff --git a/nova/tests/test_storwize_svc.py b/nova/tests/test_storwize_svc.py deleted file mode 100644 index 513043256..000000000 --- a/nova/tests/test_storwize_svc.py +++ /dev/null @@ -1,1376 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2012 IBM, Inc. -# Copyright (c) 2012 OpenStack LLC. -# All Rights Reserved. -# -# 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. -# -# Authors: -# Ronen Kat <ronenkat@il.ibm.com> -# Avishay Traeger <avishay@il.ibm.com> - -""" -Tests for the IBM Storwize V7000 and SVC volume driver. -""" - -import random -import socket - -from nova import exception -from nova import flags -from nova.openstack.common import excutils -from nova.openstack.common import log as logging -from nova import test -from nova.volume import storwize_svc - -FLAGS = flags.FLAGS - -LOG = logging.getLogger(__name__) - - -class StorwizeSVCManagementSimulator: - def __init__(self, pool_name): - self._flags = {"storwize_svc_volpool_name": pool_name} - self._volumes_list = {} - self._hosts_list = {} - self._mappings_list = {} - self._fcmappings_list = {} - self._next_cmd_error = { - "lsportip": "", - "lsnodecanister": "", - "mkvdisk": "", - "lsvdisk": "", - "lsfcmap": "", - "prestartfcmap": "", - "startfcmap": "", - "rmfcmap": "", - } - self._errors = { - "CMMVC5701E": ("", "CMMVC5701E No object ID was specified."), - "CMMVC6035E": ("", "CMMVC6035E The action failed as the " + - "object already exists."), - "CMMVC5753E": ("", "CMMVC5753E The specified object does not " + - "exist or is not a suitable candidate."), - "CMMVC5707E": ("", "CMMVC5707E Required parameters are missing."), - "CMMVC6581E": ("", "CMMVC6581E The command has failed because " + - "the maximum number of allowed iSCSI " + - "qualified names (IQNs) has been reached, " + - "or the IQN is already assigned or is not " + - "valid."), - "CMMVC5754E": ("", "CMMVC5754E The specified object does not " + - "exist, or the name supplied does not meet " + - "the naming rules."), - "CMMVC6071E": ("", "CMMVC6071E The VDisk-to-host mapping was " + - "not created because the VDisk is already " + - "mapped to a host."), - "CMMVC5879E": ("", "CMMVC5879E The VDisk-to-host mapping was " + - "not created because a VDisk is already " + - "mapped to this host with this SCSI LUN."), - "CMMVC5840E": ("", "CMMVC5840E The virtual disk (VDisk) was " + - "not deleted because it is mapped to a " + - "host or because it is part of a FlashCopy " + - "or Remote Copy mapping, or is involved in " + - "an image mode migrate."), - "CMMVC6527E": ("", "CMMVC6527E The name that you have entered " + - "is not valid. The name can contain letters, " + - "numbers, spaces, periods, dashes, and " + - "underscores. The name must begin with a " + - "letter or an underscore. The name must not " + - "begin or end with a space."), - "CMMVC5871E": ("", "CMMVC5871E The action failed because one or " + - "more of the configured port names is in a " + - "mapping."), - "CMMVC5924E": ("", "CMMVC5924E The FlashCopy mapping was not " + - "created because the source and target " + - "virtual disks (VDisks) are different sizes."), - "CMMVC6303E": ("", "CMMVC6303E The create failed because the " + - "source and target VDisks are the same."), - "CMMVC7050E": ("", "CMMVC7050E The command failed because at " + - "least one node in the I/O group does not " + - "support compressed VDisks."), - } - - # Find an unused ID - def _find_unused_id(self, d): - ids = [] - for k, v in d.iteritems(): - ids.append(int(v["id"])) - ids.sort() - for index, n in enumerate(ids): - if n > index: - return str(index) - return str(len(ids)) - - # Check if name is valid - def _is_invalid_name(self, name): - if (name[0] == " ") or (name[-1] == " "): - return True - for c in name: - if ((not c.isalnum()) and (c != " ") and (c != ".") - and (c != "-") and (c != "_")): - return True - return False - - # Convert argument string to dictionary - def _cmd_to_dict(self, cmd): - arg_list = cmd.split() - no_param_args = [ - "autodelete", - "autoexpand", - "bytes", - "compressed", - "force", - "nohdr", - ] - one_param_args = [ - "cleanrate", - "delim", - "filtervalue", - "grainsize", - "host", - "iogrp", - "iscsiname", - "mdiskgrp", - "name", - "rsize", - "scsi", - "size", - "source", - "target", - "unit", - "easytier", - "warning", - ] - - # Handle the special case of lsnode which is a two-word command - # Use the one word version of the command internally - if arg_list[0] == "svcinfo" and arg_list[1] == "lsnode": - ret = {"cmd": "lsnodecanister"} - arg_list.pop(0) - else: - ret = {"cmd": arg_list[0]} - - skip = False - for i in range(1, len(arg_list)): - if skip: - skip = False - continue - if arg_list[i][0] == "-": - if arg_list[i][1:] in no_param_args: - ret[arg_list[i][1:]] = True - elif arg_list[i][1:] in one_param_args: - ret[arg_list[i][1:]] = arg_list[i + 1] - skip = True - else: - raise exception.InvalidInput( - reason=_('unrecognized argument %s') % arg_list[i]) - else: - ret["obj"] = arg_list[i] - return ret - - # Generic function for printing information - def _print_info_cmd(self, rows, delim=" ", nohdr=False, **kwargs): - if nohdr: - del rows[0] - - for index in range(len(rows)): - rows[index] = delim.join(rows[index]) - return ("%s" % "\n".join(rows), "") - - # Print mostly made-up stuff in the correct syntax - def _cmd_lsmdiskgrp(self, **kwargs): - rows = [None] * 3 - rows[0] = ["id", "name", "status", "mdisk_count", - "vdisk_count capacity", "extent_size", "free_capacity", - "virtual_capacity", "used_capacity", "real_capacity", - "overallocation", "warning", "easy_tier", - "easy_tier_status"] - rows[1] = ["1", self._flags["storwize_svc_volpool_name"], "online", - "1", str(len(self._volumes_list)), "3.25TB", "256", - "3.21TB", "1.54TB", "264.97MB", "35.58GB", "47", "80", - "auto", "inactive"] - rows[2] = ["2", "volpool2", "online", - "1", "0", "3.25TB", "256", - "3.21TB", "1.54TB", "264.97MB", "35.58GB", "47", "80", - "auto", "inactive"] - return self._print_info_cmd(rows=rows, **kwargs) - - # Print mostly made-up stuff in the correct syntax - def _cmd_lsnodecanister(self, **kwargs): - rows = [None] * 3 - rows[0] = ["id", "name", "UPS_serial_number", "WWNN", "status", - "IO_group_id", "IO_group_name", "config_node", - "UPS_unique_id", "hardware", "iscsi_name", "iscsi_alias", - "panel_name", "enclosure_id", "canister_id", - "enclosure_serial_number"] - rows[1] = ["5", "node1", "", "123456789ABCDEF0", "online", "0", - "io_grp0", - "yes", "123456789ABCDEF0", "100", - "iqn.1982-01.com.ibm:1234.sim.node1", "", "01-1", "1", "1", - "0123ABC"] - rows[2] = ["6", "node2", "", "123456789ABCDEF1", "online", "0", - "io_grp0", - "no", "123456789ABCDEF1", "100", - "iqn.1982-01.com.ibm:1234.sim.node2", "", "01-2", "1", "2", - "0123ABC"] - - if self._next_cmd_error["lsnodecanister"] == "header_mismatch": - rows[0].pop(2) - self._next_cmd_error["lsnodecanister"] = "" - if self._next_cmd_error["lsnodecanister"] == "remove_field": - for row in rows: - row.pop(0) - self._next_cmd_error["lsnodecanister"] = "" - - return self._print_info_cmd(rows=rows, **kwargs) - - # Print mostly made-up stuff in the correct syntax - def _cmd_lsportip(self, **kwargs): - if self._next_cmd_error["lsportip"] == "ip_no_config": - self._next_cmd_error["lsportip"] = "" - ip_addr1 = "" - ip_addr2 = "" - gw = "" - else: - ip_addr1 = "1.234.56.78" - ip_addr2 = "1.234.56.79" - gw = "1.234.56.1" - - rows = [None] * 17 - rows[0] = ["id", "node_id", "node_name", "IP_address", "mask", - "gateway", "IP_address_6", "prefix_6", "gateway_6", "MAC", - "duplex", "state", "speed", "failover"] - rows[1] = ["1", "5", "node1", ip_addr1, "255.255.255.0", - gw, "", "", "", "01:23:45:67:89:00", "Full", - "online", "1Gb/s", "no"] - rows[2] = ["1", "5", "node1", "", "", "", "", "", "", - "01:23:45:67:89:00", "Full", "online", "1Gb/s", "yes"] - rows[3] = ["2", "5", "node1", "", "", "", "", "", "", - "01:23:45:67:89:01", "Full", "unconfigured", "1Gb/s", "no"] - rows[4] = ["2", "5", "node1", "", "", "", "", "", "", - "01:23:45:67:89:01", "Full", "unconfigured", "1Gb/s", "yes"] - rows[5] = ["3", "5", "node1", "", "", "", "", "", "", "", "", - "unconfigured", "", "no"] - rows[6] = ["3", "5", "node1", "", "", "", "", "", "", "", "", - "unconfigured", "", "yes"] - rows[7] = ["4", "5", "node1", "", "", "", "", "", "", "", "", - "unconfigured", "", "no"] - rows[8] = ["4", "5", "node1", "", "", "", "", "", "", "", "", - "unconfigured", "", "yes"] - rows[9] = ["1", "6", "node2", ip_addr2, "255.255.255.0", - gw, "", "", "", "01:23:45:67:89:02", "Full", - "online", "1Gb/s", "no"] - rows[10] = ["1", "6", "node2", "", "", "", "", "", "", - "01:23:45:67:89:02", "Full", "online", "1Gb/s", "yes"] - rows[11] = ["2", "6", "node2", "", "", "", "", "", "", - "01:23:45:67:89:03", "Full", "unconfigured", "1Gb/s", "no"] - rows[12] = ["2", "6", "node2", "", "", "", "", "", "", - "01:23:45:67:89:03", "Full", "unconfigured", "1Gb/s", - "yes"] - rows[13] = ["3", "6", "node2", "", "", "", "", "", "", "", "", - "unconfigured", "", "no"] - rows[14] = ["3", "6", "node2", "", "", "", "", "", "", "", "", - "unconfigured", "", "yes"] - rows[15] = ["4", "6", "node2", "", "", "", "", "", "", "", "", - "unconfigured", "", "no"] - rows[16] = ["4", "6", "node2", "", "", "", "", "", "", "", "", - "unconfigured", "", "yes"] - - if self._next_cmd_error["lsportip"] == "header_mismatch": - rows[0].pop(2) - self._next_cmd_error["lsportip"] = "" - if self._next_cmd_error["lsportip"] == "remove_field": - for row in rows: - row.pop(1) - self._next_cmd_error["lsportip"] = "" - - return self._print_info_cmd(rows=rows, **kwargs) - - # Create a vdisk - def _cmd_mkvdisk(self, **kwargs): - # We only save the id/uid, name, and size - all else will be made up - volume_info = {} - volume_info["id"] = self._find_unused_id(self._volumes_list) - volume_info["uid"] = ("ABCDEF" * 3) + ("0" * 14) + volume_info["id"] - - if "name" in kwargs: - volume_info["name"] = kwargs["name"].strip('\'\"') - else: - volume_info["name"] = "vdisk" + volume_info["id"] - - # Assume size and unit are given, store it in bytes - capacity = int(kwargs["size"]) - unit = kwargs["unit"] - - if unit == "b": - cap_bytes = capacity - elif unit == "kb": - cap_bytes = capacity * pow(1024, 1) - elif unit == "mb": - cap_bytes = capacity * pow(1024, 2) - elif unit == "gb": - cap_bytes = capacity * pow(1024, 3) - elif unit == "tb": - cap_bytes = capacity * pow(1024, 4) - elif unit == "pb": - cap_bytes = capacity * pow(1024, 5) - volume_info["cap_bytes"] = str(cap_bytes) - volume_info["capacity"] = str(capacity) + unit.upper() - - if "easytier" in kwargs: - if kwargs["easytier"] == "on": - volume_info["easy_tier"] = "on" - else: - volume_info["easy_tier"] = "off" - - if "rsize" in kwargs: - # Fake numbers - volume_info["used_capacity"] = "0.75MB" - volume_info["real_capacity"] = "36.98MB" - volume_info["free_capacity"] = "36.23MB" - volume_info["used_capacity_bytes"] = "786432" - volume_info["real_capacity_bytes"] = "38776340" - volume_info["free_capacity_bytes"] = "37989908" - if "warning" in kwargs: - volume_info["warning"] = kwargs["warning"].rstrip('%') - else: - volume_info["warning"] = "80" - if "autoexpand" in kwargs: - volume_info["autoexpand"] = "on" - else: - volume_info["autoexpand"] = "off" - if "grainsize" in kwargs: - volume_info["grainsize"] = kwargs["grainsize"] - else: - volume_info["grainsize"] = "32" - if "compressed" in kwargs: - if self._next_cmd_error["mkvdisk"] == "no_compression": - self._next_cmd_error["mkvdisk"] = "" - return self._errors["CMMVC7050E"] - volume_info["compressed_copy"] = "yes" - else: - volume_info["compressed_copy"] = "no" - else: - volume_info["used_capacity"] = volume_info["capacity"] - volume_info["real_capacity"] = volume_info["capacity"] - volume_info["free_capacity"] = "0.00MB" - volume_info["used_capacity_bytes"] = volume_info["cap_bytes"] - volume_info["real_capacity_bytes"] = volume_info["cap_bytes"] - volume_info["free_capacity_bytes"] = "0" - volume_info["warning"] = "" - volume_info["autoexpand"] = "" - volume_info["grainsize"] = "" - volume_info["compressed_copy"] = "no" - - if volume_info["name"] in self._volumes_list: - return self._errors["CMMVC6035E"] - else: - self._volumes_list[volume_info["name"]] = volume_info - return ("Virtual Disk, id [%s], successfully created" % - (volume_info["id"]), "") - - # Delete a vdisk - def _cmd_rmvdisk(self, **kwargs): - force = 0 - if "force" in kwargs: - force = 1 - - if "obj" not in kwargs: - return self._errors["CMMVC5701E"] - vol_name = kwargs["obj"].strip('\'\"') - - if not vol_name in self._volumes_list: - return self._errors["CMMVC5753E"] - - if force == 0: - for k, mapping in self._mappings_list.iteritems(): - if mapping["vol"] == vol_name: - return self._errors["CMMVC5840E"] - for k, fcmap in self._fcmappings_list.iteritems(): - if ((fcmap["source"] == vol_name) or - (fcmap["target"] == vol_name)): - return self._errors["CMMVC5840E"] - - del self._volumes_list[vol_name] - return ("", "") - - def _get_fcmap_info(self, vol_name): - ret_vals = { - "fc_id": "", - "fc_name": "", - "fc_map_count": "0", - } - for k, fcmap in self._fcmappings_list.iteritems(): - if ((fcmap["source"] == vol_name) or - (fcmap["target"] == vol_name)): - ret_vals["fc_id"] = fcmap["id"] - ret_vals["fc_name"] = fcmap["name"] - ret_vals["fc_map_count"] = "1" - return ret_vals - - # List information about vdisks - def _cmd_lsvdisk(self, **kwargs): - if "obj" not in kwargs: - rows = [] - rows.append(["id", "name", "IO_group_id", "IO_group_name", - "status", "mdisk_grp_id", "mdisk_grp_name", - "capacity", "type", "FC_id", "FC_name", "RC_id", - "RC_name", "vdisk_UID", "fc_map_count", "copy_count", - "fast_write_state", "se_copy_count", "RC_change"]) - - for k, vol in self._volumes_list.iteritems(): - if (("filtervalue" not in kwargs) or - (kwargs["filtervalue"] == "name=" + vol["name"])): - fcmap_info = self._get_fcmap_info(vol["name"]) - - if "bytes" in kwargs: - cap = vol["cap_bytes"] - else: - cap = vol["capacity"] - rows.append([str(vol["id"]), vol["name"], "0", "io_grp0", - "online", "0", - self._flags["storwize_svc_volpool_name"], - cap, "striped", - fcmap_info["fc_id"], fcmap_info["fc_name"], - "", "", vol["uid"], - fcmap_info["fc_map_count"], "1", "empty", - "1", "no"]) - - return self._print_info_cmd(rows=rows, **kwargs) - - else: - if kwargs["obj"] not in self._volumes_list: - return self._errors["CMMVC5754E"] - vol = self._volumes_list[kwargs["obj"]] - fcmap_info = self._get_fcmap_info(vol["name"]) - if "bytes" in kwargs: - cap = vol["cap_bytes"] - cap_u = vol["used_capacity_bytes"] - cap_r = vol["real_capacity_bytes"] - cap_f = vol["free_capacity_bytes"] - else: - cap = vol["capacity"] - cap_u = vol["used_capacity"] - cap_r = vol["real_capacity"] - cap_f = vol["free_capacity"] - rows = [] - - rows.append(["id", str(vol["id"])]) - rows.append(["name", vol["name"]]) - rows.append(["IO_group_id", "0"]) - rows.append(["IO_group_name", "io_grp0"]) - rows.append(["status", "online"]) - rows.append(["mdisk_grp_id", "0"]) - rows.append(["mdisk_grp_name", - self._flags["storwize_svc_volpool_name"]]) - rows.append(["capacity", cap]) - rows.append(["type", "striped"]) - rows.append(["formatted", "no"]) - rows.append(["mdisk_id", ""]) - rows.append(["mdisk_name", ""]) - rows.append(["FC_id", fcmap_info["fc_id"]]) - rows.append(["FC_name", fcmap_info["fc_name"]]) - rows.append(["RC_id", ""]) - rows.append(["RC_name", ""]) - rows.append(["vdisk_UID", vol["uid"]]) - rows.append(["throttling", "0"]) - - if self._next_cmd_error["lsvdisk"] == "blank_pref_node": - rows.append(["preferred_node_id", ""]) - self._next_cmd_error["lsvdisk"] = "" - elif self._next_cmd_error["lsvdisk"] == "no_pref_node": - self._next_cmd_error["lsvdisk"] = "" - else: - rows.append(["preferred_node_id", "6"]) - rows.append(["fast_write_state", "empty"]) - rows.append(["cache", "readwrite"]) - rows.append(["udid", ""]) - rows.append(["fc_map_count", fcmap_info["fc_map_count"]]) - rows.append(["sync_rate", "50"]) - rows.append(["copy_count", "1"]) - rows.append(["se_copy_count", "0"]) - rows.append(["mirror_write_priority", "latency"]) - rows.append(["RC_change", "no"]) - rows.append(["used_capacity", cap_u]) - rows.append(["real_capacity", cap_r]) - rows.append(["free_capacity", cap_f]) - rows.append(["autoexpand", vol["autoexpand"]]) - rows.append(["warning", vol["warning"]]) - rows.append(["grainsize", vol["grainsize"]]) - rows.append(["easy_tier", vol["easy_tier"]]) - rows.append(["compressed_copy", vol["compressed_copy"]]) - - if "nohdr" in kwargs: - for index in range(len(rows)): - rows[index] = " ".join(rows[index][1:]) - - if "delim" in kwargs: - for index in range(len(rows)): - rows[index] = kwargs["delim"].join(rows[index]) - - return ("%s" % "\n".join(rows), "") - - # Make a host - def _cmd_mkhost(self, **kwargs): - host_info = {} - host_info["id"] = self._find_unused_id(self._hosts_list) - - if "name" in kwargs: - host_name = kwargs["name"].strip('\'\"') - else: - host_name = "host" + str(host_info["id"]) - host_info["host_name"] = host_name - - if "iscsiname" not in kwargs: - return self._errors["CMMVC5707E"] - host_info["iscsi_name"] = kwargs["iscsiname"].strip('\'\"') - - if self._is_invalid_name(host_name): - return self._errors["CMMVC6527E"] - - if host_name in self._hosts_list: - return self._errors["CMMVC6035E"] - - for k, v in self._hosts_list.iteritems(): - if v["iscsi_name"] == host_info["iscsi_name"]: - return self._errors["CMMVC6581E"] - - self._hosts_list[host_name] = host_info - return ("Host, id [%s], successfully created" % - (host_info["id"]), "") - - # Remove a host - def _cmd_rmhost(self, **kwargs): - if "obj" not in kwargs: - return self._errors["CMMVC5701E"] - - host_name = kwargs["obj"].strip('\'\"') - if host_name not in self._hosts_list: - return self._errors["CMMVC5753E"] - - for k, v in self._mappings_list.iteritems(): - if (v["host"] == host_name): - return self._errors["CMMVC5871E"] - - del self._hosts_list[host_name] - return ("", "") - - # List information about hosts - def _cmd_lshost(self, **kwargs): - if "obj" not in kwargs: - rows = [] - rows.append(["id", "name", "port_count", "iogrp_count", "status"]) - - found = False - for k, host in self._hosts_list.iteritems(): - filterstr = "name=" + host["host_name"] - if (("filtervalue" not in kwargs) or - (kwargs["filtervalue"] == filterstr)): - rows.append([host["id"], host["host_name"], "1", "4", - "offline"]) - found = True - if found: - return self._print_info_cmd(rows=rows, **kwargs) - else: - return ("", "") - else: - if kwargs["obj"] not in self._hosts_list: - return self._errors["CMMVC5754E"] - host = self._hosts_list[kwargs["obj"]] - rows = [] - rows.append(["id", host["id"]]) - rows.append(["name", host["host_name"]]) - rows.append(["port_count", "1"]) - rows.append(["type", "generic"]) - rows.append(["mask", "1111"]) - rows.append(["iogrp_count", "4"]) - rows.append(["status", "offline"]) - rows.append(["iscsi_name", host["iscsi_name"]]) - rows.append(["node_logged_in_count", "0"]) - rows.append(["state", "offline"]) - - if "nohdr" in kwargs: - for index in range(len(rows)): - rows[index] = " ".join(rows[index][1:]) - - if "delim" in kwargs: - for index in range(len(rows)): - rows[index] = kwargs["delim"].join(rows[index]) - - return ("%s" % "\n".join(rows), "") - - # Create a vdisk-host mapping - def _cmd_mkvdiskhostmap(self, **kwargs): - mapping_info = {} - mapping_info["id"] = self._find_unused_id(self._mappings_list) - - if "host" not in kwargs: - return self._errors["CMMVC5707E"] - mapping_info["host"] = kwargs["host"].strip('\'\"') - - if "scsi" not in kwargs: - return self._errors["CMMVC5707E"] - mapping_info["lun"] = kwargs["scsi"].strip('\'\"') - - if "obj" not in kwargs: - return self._errors["CMMVC5707E"] - mapping_info["vol"] = kwargs["obj"].strip('\'\"') - - if not mapping_info["vol"] in self._volumes_list: - return self._errors["CMMVC5753E"] - - if not mapping_info["host"] in self._hosts_list: - return self._errors["CMMVC5754E"] - - if mapping_info["vol"] in self._mappings_list: - return self._errors["CMMVC6071E"] - - for k, v in self._mappings_list.iteritems(): - if ((v["host"] == mapping_info["host"]) and - (v["lun"] == mapping_info["lun"])): - return self._errors["CMMVC5879E"] - - self._mappings_list[mapping_info["vol"]] = mapping_info - return ("Virtual Disk to Host map, id [%s], successfully created" - % (mapping_info["id"]), "") - - # Delete a vdisk-host mapping - def _cmd_rmvdiskhostmap(self, **kwargs): - if "host" not in kwargs: - return self._errors["CMMVC5707E"] - host = kwargs["host"].strip('\'\"') - - if "obj" not in kwargs: - return self._errors["CMMVC5701E"] - vol = kwargs["obj"].strip('\'\"') - - if not vol in self._mappings_list: - return self._errors["CMMVC5753E"] - - if self._mappings_list[vol]["host"] != host: - return self._errors["CMMVC5753E"] - - del self._mappings_list[vol] - return ("", "") - - # List information about vdisk-host mappings - def _cmd_lshostvdiskmap(self, **kwargs): - index = 1 - no_hdr = 0 - delimeter = "" - host_name = kwargs["obj"] - - if host_name not in self._hosts_list: - return self._errors["CMMVC5754E"] - - rows = [] - rows.append(["id", "name", "SCSI_id", "vdisk_id", "vdisk_name", - "vdisk_UID"]) - - for k, mapping in self._mappings_list.iteritems(): - if (host_name == "") or (mapping["host"] == host_name): - volume = self._volumes_list[mapping["vol"]] - rows.append([mapping["id"], mapping["host"], - mapping["lun"], volume["id"], - volume["name"], volume["uid"]]) - - return self._print_info_cmd(rows=rows, **kwargs) - - # Create a FlashCopy mapping - def _cmd_mkfcmap(self, **kwargs): - source = "" - target = "" - - if "source" not in kwargs: - return self._errors["CMMVC5707E"] - source = kwargs["source"].strip('\'\"') - if not source in self._volumes_list: - return self._errors["CMMVC5754E"] - - if "target" not in kwargs: - return self._errors["CMMVC5707E"] - target = kwargs["target"].strip('\'\"') - if not target in self._volumes_list: - return self._errors["CMMVC5754E"] - - if source == target: - return self._errors["CMMVC6303E"] - - if (self._volumes_list[source]["cap_bytes"] != - self._volumes_list[target]["cap_bytes"]): - return self._errors["CMMVC5924E"] - - fcmap_info = {} - fcmap_info["source"] = source - fcmap_info["target"] = target - fcmap_info["id"] = self._find_unused_id(self._fcmappings_list) - fcmap_info["name"] = "fcmap" + fcmap_info["id"] - fcmap_info["status"] = "idle_or_copied" - fcmap_info["progress"] = "0" - self._fcmappings_list[target] = fcmap_info - - return("FlashCopy Mapping, id [" + fcmap_info["id"] + - "], successfully created", "") - - # Same function used for both prestartfcmap and startfcmap - def _cmd_gen_startfcmap(self, mode, **kwargs): - if "obj" not in kwargs: - return self._errors["CMMVC5701E"] - id_num = kwargs["obj"] - - if mode == "pre": - if self._next_cmd_error["prestartfcmap"] == "bad_id": - id_num = -1 - self._next_cmd_error["prestartfcmap"] = "" - else: - if self._next_cmd_error["startfcmap"] == "bad_id": - id_num = -1 - self._next_cmd_error["startfcmap"] = "" - - for k, fcmap in self._fcmappings_list.iteritems(): - if fcmap["id"] == id_num: - if mode == "pre": - fcmap["status"] = "preparing" - else: - fcmap["status"] = "copying" - fcmap["progress"] = "0" - return ("", "") - return self._errors["CMMVC5753E"] - - # Same function used for both stopfcmap and rmfcmap - # Assumes it is called with "-force <fc_map_id>" - def _cmd_stoprmfcmap(self, mode, **kwargs): - if "obj" not in kwargs: - return self._errors["CMMVC5701E"] - id_num = kwargs["obj"] - - if self._next_cmd_error["rmfcmap"] == "bad_id": - id_num = -1 - self._next_cmd_error["rmfcmap"] = "" - - to_delete = None - found = False - for k, fcmap in self._fcmappings_list.iteritems(): - if fcmap["id"] == id_num: - found = True - if mode == "rm": - to_delete = k - - if to_delete: - del self._fcmappings_list[to_delete] - - if found: - return ("", "") - else: - return self._errors["CMMVC5753E"] - - def _cmd_lsfcmap(self, **kwargs): - rows = [] - rows.append(["id", "name", "source_vdisk_id", "source_vdisk_name", - "target_vdisk_id", "target_vdisk_name", "group_id", - "group_name", "status", "progress", "copy_rate", - "clean_progress", "incremental", "partner_FC_id", - "partner_FC_name", "restoring", "start_time", - "rc_controlled"]) - - # Assume we always get a filtervalue argument - filter_key = kwargs["filtervalue"].split("=")[0] - filter_value = kwargs["filtervalue"].split("=")[1] - to_delete = [] - for k, v in self._fcmappings_list.iteritems(): - if str(v[filter_key]) == filter_value: - source = self._volumes_list[v["source"]] - target = self._volumes_list[v["target"]] - old_status = v["status"] - if old_status == "preparing": - new_status = "prepared" - if self._next_cmd_error["lsfcmap"] == "bogus_prepare": - new_status = "bogus" - elif (old_status == "copying") and (v["progress"] == "0"): - new_status = "copying" - v["progress"] = "50" - elif (old_status == "copying") and (v["progress"] == "50"): - new_status = "idle_or_copied" - to_delete.append(k) - else: - new_status = old_status - v["status"] = new_status - - if ((self._next_cmd_error["lsfcmap"] == "speed_up") or - (self._next_cmd_error["lsfcmap"] == "bogus_prepare")): - print_status = new_status - self._next_cmd_error["lsfcmap"] = "" - else: - print_status = old_status - - rows.append([v["id"], v["name"], source["id"], - source["name"], target["id"], target["name"], "", - "", print_status, v["progress"], "50", "100", - "off", "", "", "no", "", "no"]) - - for d in to_delete: - del self._fcmappings_list[k] - - return self._print_info_cmd(rows=rows, **kwargs) - - # The main function to run commands on the management simulator - def execute_command(self, cmd, check_exit_code=True): - try: - kwargs = self._cmd_to_dict(cmd) - except IndexError: - return self._errors["CMMVC5707E"] - - command = kwargs["cmd"] - del kwargs["cmd"] - arg_list = cmd.split() - - if command == "lsmdiskgrp": - out, err = self._cmd_lsmdiskgrp(**kwargs) - elif command == "lsnodecanister": - out, err = self._cmd_lsnodecanister(**kwargs) - elif command == "lsportip": - out, err = self._cmd_lsportip(**kwargs) - elif command == "mkvdisk": - out, err = self._cmd_mkvdisk(**kwargs) - elif command == "rmvdisk": - out, err = self._cmd_rmvdisk(**kwargs) - elif command == "lsvdisk": - out, err = self._cmd_lsvdisk(**kwargs) - elif command == "mkhost": - out, err = self._cmd_mkhost(**kwargs) - elif command == "rmhost": - out, err = self._cmd_rmhost(**kwargs) - elif command == "lshost": - out, err = self._cmd_lshost(**kwargs) - elif command == "mkvdiskhostmap": - out, err = self._cmd_mkvdiskhostmap(**kwargs) - elif command == "rmvdiskhostmap": - out, err = self._cmd_rmvdiskhostmap(**kwargs) - elif command == "lshostvdiskmap": - out, err = self._cmd_lshostvdiskmap(**kwargs) - elif command == "mkfcmap": - out, err = self._cmd_mkfcmap(**kwargs) - elif command == "prestartfcmap": - out, err = self._cmd_gen_startfcmap(mode="pre", **kwargs) - elif command == "startfcmap": - out, err = self._cmd_gen_startfcmap(mode="start", **kwargs) - elif command == "stopfcmap": - out, err = self._cmd_stoprmfcmap(mode="stop", **kwargs) - elif command == "rmfcmap": - out, err = self._cmd_stoprmfcmap(mode="rm", **kwargs) - elif command == "lsfcmap": - out, err = self._cmd_lsfcmap(**kwargs) - else: - out, err = ("", "ERROR: Unsupported command") - - if (check_exit_code) and (len(err) != 0): - raise exception.ProcessExecutionError(exit_code=1, - stdout=out, - stderr=err, - cmd=' '.join(cmd)) - - return (out, err) - - # After calling this function, the next call to the specified command will - # result in in the error specified - def error_injection(self, cmd, error): - self._next_cmd_error[cmd] = error - - -class StorwizeSVCFakeDriver(storwize_svc.StorwizeSVCDriver): - def set_fake_storage(self, fake): - self.fake_storage = fake - - def _run_ssh(self, cmd, check_exit_code=True): - try: - LOG.debug(_('Run CLI command: %s') % cmd) - ret = self.fake_storage.execute_command(cmd, check_exit_code) - (stdout, stderr) = ret - LOG.debug(_('CLI output:\n stdout: %(out)s\n stderr: %(err)s') % - {'out': stdout, 'err': stderr}) - - except exception.ProcessExecutionError as e: - with excutils.save_and_reraise_exception(): - LOG.debug(_('CLI Exception output:\n stdout: %(out)s\n ' - 'stderr: %(err)s') % {'out': e.stdout, - 'err': e.stderr}) - - return ret - - -class StorwizeSVCDriverTestCase(test.TestCase): - def setUp(self): - super(StorwizeSVCDriverTestCase, self).setUp() - self.USESIM = 1 - if self.USESIM == 1: - self.flags( - san_ip="hostname", - san_login="user", - san_password="pass", - storwize_svc_flashcopy_timeout="20", - ) - self.sim = StorwizeSVCManagementSimulator("volpool") - self.driver = StorwizeSVCFakeDriver() - self.driver.set_fake_storage(self.sim) - else: - self.flags( - san_ip="-1.-1.-1.-1", - san_login="user", - san_password="password", - storwize_svc_volpool_name="pool", - ) - self.driver = storwize_svc.StorwizeSVCDriver() - - self.driver.do_setup(None) - self.driver.check_for_setup_error() - - def test_storwize_svc_volume_tests(self): - self.flags(storwize_svc_vol_rsize="-1") - volume = {} - volume["name"] = "test1_volume%s" % random.randint(10000, 99999) - volume["size"] = 10 - volume["id"] = 1 - self.driver.create_volume(volume) - # Make sure that the volume has been created - is_volume_defined = self.driver._is_volume_defined(volume["name"]) - self.assertEqual(is_volume_defined, True) - self.driver.delete_volume(volume) - - if self.USESIM == 1: - self.flags(storwize_svc_vol_rsize="2%") - self.flags(storwize_svc_vol_compression=True) - self.driver.create_volume(volume) - is_volume_defined = self.driver._is_volume_defined(volume["name"]) - self.assertEqual(is_volume_defined, True) - self.driver.delete_volume(volume) - FLAGS.reset() - - def test_storwize_svc_ip_connectivity(self): - # Check for missing san_ip - self.flags(san_ip=None) - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - - if self.USESIM != 1: - # Check for invalid ip - self.flags(san_ip="-1.-1.-1.-1") - self.assertRaises(socket.gaierror, - self.driver.check_for_setup_error) - - # Check for unreachable IP - self.flags(san_ip="1.1.1.1") - self.assertRaises(socket.error, - self.driver.check_for_setup_error) - - def test_storwize_svc_connectivity(self): - # Make sure we detect if the pool doesn't exist - no_exist_pool = "i-dont-exist-%s" % random.randint(10000, 99999) - self.flags(storwize_svc_volpool_name=no_exist_pool) - self.assertRaises(exception.InvalidInput, - self.driver.check_for_setup_error) - FLAGS.reset() - - # Check the case where the user didn't configure IP addresses - # as well as receiving unexpected results from the storage - if self.USESIM == 1: - self.sim.error_injection("lsnodecanister", "header_mismatch") - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.check_for_setup_error) - self.sim.error_injection("lsnodecanister", "remove_field") - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.check_for_setup_error) - self.sim.error_injection("lsportip", "ip_no_config") - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.check_for_setup_error) - self.sim.error_injection("lsportip", "header_mismatch") - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.check_for_setup_error) - self.sim.error_injection("lsportip", "remove_field") - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.check_for_setup_error) - - # Check with bad parameters - self.flags(san_password=None) - self.flags(san_private_key=None) - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - FLAGS.reset() - - self.flags(storwize_svc_vol_rsize="invalid") - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - FLAGS.reset() - - self.flags(storwize_svc_vol_warning="invalid") - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - FLAGS.reset() - - self.flags(storwize_svc_vol_autoexpand="invalid") - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - FLAGS.reset() - - self.flags(storwize_svc_vol_grainsize=str(42)) - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - FLAGS.reset() - - self.flags(storwize_svc_flashcopy_timeout=str(601)) - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - FLAGS.reset() - - self.flags(storwize_svc_vol_compression=True) - self.flags(storwize_svc_vol_rsize="-1") - self.assertRaises(exception.InvalidInput, - self.driver._check_flags) - FLAGS.reset() - - # Finally, check with good parameters - self.driver.check_for_setup_error() - - def test_storwize_svc_flashcopy(self): - volume1 = {} - volume1["name"] = "test1_volume%s" % random.randint(10000, 99999) - volume1["size"] = 10 - volume1["id"] = 10 - self.driver.create_volume(volume1) - - snapshot = {} - snapshot["name"] = "snap_volume%s" % random.randint(10000, 99999) - snapshot["volume_name"] = volume1["name"] - - # Test timeout and volume cleanup - self.flags(storwize_svc_flashcopy_timeout=str(1)) - self.assertRaises(exception.InvalidSnapshot, - self.driver.create_snapshot, snapshot) - is_volume_defined = self.driver._is_volume_defined(snapshot["name"]) - self.assertEqual(is_volume_defined, False) - FLAGS.reset() - - # Test bogus statuses - if self.USESIM == 1: - self.sim.error_injection("lsfcmap", "bogus_prepare") - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.create_snapshot, snapshot) - - # Test prestartfcmap, startfcmap, and rmfcmap failing - if self.USESIM == 1: - self.sim.error_injection("prestartfcmap", "bad_id") - self.assertRaises(exception.ProcessExecutionError, - self.driver.create_snapshot, snapshot) - self.sim.error_injection("lsfcmap", "speed_up") - self.sim.error_injection("startfcmap", "bad_id") - self.assertRaises(exception.ProcessExecutionError, - self.driver.create_snapshot, snapshot) - self.sim.error_injection("prestartfcmap", "bad_id") - self.sim.error_injection("rmfcmap", "bad_id") - self.assertRaises(exception.ProcessExecutionError, - self.driver.create_snapshot, snapshot) - - # Test successful snapshot - self.driver.create_snapshot(snapshot) - - # Ensure snapshot is defined - is_volume_defined = self.driver._is_volume_defined(snapshot["name"]) - self.assertEqual(is_volume_defined, True) - - # Try to create a snapshot from an non-existing volume - should fail - snapshot2 = {} - snapshot2["name"] = "snap_volume%s" % random.randint(10000, 99999) - snapshot2["volume_name"] = "undefined-vol" - self.assertRaises(exception.VolumeNotFound, - self.driver.create_snapshot, - snapshot2) - - # Create volume from snapshot - volume2 = {} - volume2["name"] = "snap2vol_volume%s" % random.randint(10000, 99999) - - # Create volume from snapshot into an existsing volume - self.assertRaises(exception.InvalidSnapshot, - self.driver.create_volume_from_snapshot, - volume1, - snapshot) - - # Try to create a volume from a non-existing snapshot - self.assertRaises(exception.SnapshotNotFound, - self.driver.create_volume_from_snapshot, - volume2, - snapshot2) - - # Fail the snapshot - if self.USESIM == 1: - self.sim.error_injection("prestartfcmap", "bad_id") - self.assertRaises(exception.ProcessExecutionError, - self.driver.create_volume_from_snapshot, volume2, snapshot) - - # Succeed - if self.USESIM == 1: - self.sim.error_injection("lsfcmap", "speed_up") - self.driver.create_volume_from_snapshot(volume2, snapshot) - - # Ensure volume is defined - is_volume_defined = self.driver._is_volume_defined(volume2["name"]) - self.assertEqual(is_volume_defined, True) - - self.driver._delete_volume(volume2, True) - self.driver._delete_snapshot(snapshot, True) - - # Check with target with different size - volume3 = {} - volume3["name"] = "test3_volume%s" % random.randint(10000, 99999) - volume3["size"] = 11 - volume3["id"] = 11 - self.driver.create_volume(volume3) - snapshot["name"] = volume3["name"] - self.assertRaises(exception.InvalidSnapshot, - self.driver.create_snapshot, snapshot) - self.driver._delete_volume(volume1, True) - self.driver._delete_volume(volume3, True) - - # Snapshot volume that doesn't exist - snapshot = {} - snapshot["name"] = "snap_volume%s" % random.randint(10000, 99999) - snapshot["volume_name"] = "no_exist" - self.assertRaises(exception.VolumeNotFound, - self.driver.create_snapshot, snapshot) - - def test_storwize_svc_volumes(self): - # Create a first volume - volume = {} - volume["name"] = "test1_volume%s" % random.randint(10000, 99999) - volume["size"] = 10 - volume["id"] = 1 - - self.driver.create_volume(volume) - - self.driver.ensure_export(None, volume) - - # Do nothing - self.driver.create_export(None, volume) - self.driver.remove_export(None, volume) - self.assertRaises(NotImplementedError, - self.driver.check_for_export, None, volume["id"]) - - # Make sure volume attributes are as they should be - attributes = self.driver._get_volume_attributes(volume["name"]) - attr_size = float(attributes["capacity"]) / 1073741824 # bytes to GB - self.assertEqual(attr_size, float(volume["size"])) - pool = storwize_svc.FLAGS.storwize_svc_volpool_name - self.assertEqual(attributes["mdisk_grp_name"], pool) - - # Try to create the volume again (should fail) - self.assertRaises(exception.ProcessExecutionError, - self.driver.create_volume, volume) - - # Try to delete a volume that doesn't exist (should not fail) - vol_no_exist = {"name": "i_dont_exist"} - self.driver.delete_volume(vol_no_exist) - # Ensure export for volume that doesn't exist (should not fail) - self.driver.ensure_export(None, vol_no_exist) - - # Delete the volume - self.driver.delete_volume(volume) - - def _create_test_vol(self): - volume = {} - volume["name"] = "testparam_volume%s" % random.randint(10000, 99999) - volume["size"] = 1 - volume["id"] = 1 - self.driver.create_volume(volume) - - attrs = self.driver._get_volume_attributes(volume["name"]) - self.driver.delete_volume(volume) - return attrs - - def test_storwize_svc_volume_params(self): - # Option test matrix - # Option Value Covered by test # - # rsize -1 1 - # rsize 2% 2,3 - # warning 0 2 - # warning 80% 3 - # autoexpand True 2 - # autoexpand False 3 - # grainsize 32 2 - # grainsize 256 3 - # compression True 4 - # compression False 2,3 - # easytier True 1,3 - # easytier False 2 - - # Test 1 - self.flags(storwize_svc_vol_rsize="-1") - self.flags(storwize_svc_vol_easytier=True) - attrs = self._create_test_vol() - self.assertEquals(attrs["free_capacity"], "0") - self.assertEquals(attrs["easy_tier"], "on") - FLAGS.reset() - - # Test 2 - self.flags(storwize_svc_vol_rsize="2%") - self.flags(storwize_svc_vol_compression=False) - self.flags(storwize_svc_vol_warning="0") - self.flags(storwize_svc_vol_autoexpand=True) - self.flags(storwize_svc_vol_grainsize="32") - self.flags(storwize_svc_vol_easytier=False) - attrs = self._create_test_vol() - self.assertNotEqual(attrs["capacity"], attrs["real_capacity"]) - self.assertEquals(attrs["compressed_copy"], "no") - self.assertEquals(attrs["warning"], "0") - self.assertEquals(attrs["autoexpand"], "on") - self.assertEquals(attrs["grainsize"], "32") - self.assertEquals(attrs["easy_tier"], "off") - FLAGS.reset() - - # Test 3 - self.flags(storwize_svc_vol_rsize="2%") - self.flags(storwize_svc_vol_compression=False) - self.flags(storwize_svc_vol_warning="80%") - self.flags(storwize_svc_vol_autoexpand=False) - self.flags(storwize_svc_vol_grainsize="256") - self.flags(storwize_svc_vol_easytier=True) - attrs = self._create_test_vol() - self.assertNotEqual(attrs["capacity"], attrs["real_capacity"]) - self.assertEquals(attrs["compressed_copy"], "no") - self.assertEquals(attrs["warning"], "80") - self.assertEquals(attrs["autoexpand"], "off") - self.assertEquals(attrs["grainsize"], "256") - self.assertEquals(attrs["easy_tier"], "on") - FLAGS.reset() - - # Test 4 - self.flags(storwize_svc_vol_rsize="2%") - self.flags(storwize_svc_vol_compression=True) - try: - attrs = self._create_test_vol() - self.assertNotEqual(attrs["capacity"], attrs["real_capacity"]) - self.assertEquals(attrs["compressed_copy"], "yes") - except exception.ProcessExecutionError as e: - if "CMMVC7050E" not in e.stderr: - raise exception.ProcessExecutionError(exit_code=e.exit_code, - stdout=e.stdout, - stderr=e.stderr, - cmd=e.cmd) - if self.USESIM == 1: - self.sim.error_injection("mkvdisk", "no_compression") - self.assertRaises(exception.ProcessExecutionError, - self._create_test_vol) - FLAGS.reset() - - def test_storwize_svc_unicode_host_and_volume_names(self): - volume1 = {} - volume1["name"] = u"unicode1_volume%s" % random.randint(10000, 99999) - volume1["size"] = 2 - volume1["id"] = 1 - self.driver.create_volume(volume1) - # Make sure that the volumes have been created - is_volume_defined = self.driver._is_volume_defined(volume1["name"]) - self.assertEqual(is_volume_defined, True) - conn = {} - conn["initiator"] = u"unicode:init:%s" % random.randint(10000, 99999) - conn["ip"] = "10.10.10.10" # Bogus ip for testing - self.driver.initialize_connection(volume1, conn) - self.driver.terminate_connection(volume1, conn) - self.driver.delete_volume(volume1) - - def test_storwize_svc_host_maps(self): - # Create two volumes to be used in mappings - volume1 = {} - volume1["name"] = "test1_volume%s" % random.randint(10000, 99999) - volume1["size"] = 2 - volume1["id"] = 1 - self.driver.create_volume(volume1) - volume2 = {} - volume2["name"] = "test2_volume%s" % random.randint(10000, 99999) - volume2["size"] = 2 - volume2["id"] = 1 - self.driver.create_volume(volume2) - - # Check case where no hosts exist - if self.USESIM == 1: - ret = self.driver._get_host_from_iscsiname("foo") - self.assertEquals(ret, None) - ret = self.driver._is_host_defined("foo") - self.assertEquals(ret, False) - - # Make sure that the volumes have been created - is_volume_defined = self.driver._is_volume_defined(volume1["name"]) - self.assertEqual(is_volume_defined, True) - is_volume_defined = self.driver._is_volume_defined(volume2["name"]) - self.assertEqual(is_volume_defined, True) - - # Initialize connection from the first volume to a host - # Add some characters to the initiator name that should be converted - # when used for the host name - conn = {} - conn["initiator"] = "test:init:%s" % random.randint(10000, 99999) - conn["ip"] = "10.10.10.10" # Bogus ip for testing - self.driver.initialize_connection(volume1, conn) - - # Initialize again, should notice it and do nothing - self.driver.initialize_connection(volume1, conn) - - # Try to delete the 1st volume (should fail because it is mapped) - self.assertRaises(exception.ProcessExecutionError, - self.driver.delete_volume, volume1) - - # Test no preferred node - self.driver.terminate_connection(volume1, conn) - if self.USESIM == 1: - self.sim.error_injection("lsvdisk", "no_pref_node") - self.driver.initialize_connection(volume1, conn) - - # Initialize connection from the second volume to the host with no - # preferred node set if in simulation mode, otherwise, just - # another initialize connection. - if self.USESIM == 1: - self.sim.error_injection("lsvdisk", "blank_pref_node") - self.driver.initialize_connection(volume2, conn) - - # Try to remove connection from host that doesn't exist (should fail) - conn_no_exist = {"initiator": "i_dont_exist"} - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.terminate_connection, volume1, conn_no_exist) - - # Try to remove connection from volume that isn't mapped (should print - # message but NOT fail) - vol_no_exist = {"name": "i_dont_exist"} - self.driver.terminate_connection(vol_no_exist, conn) - - # Remove the mapping from the 1st volume and delete it - self.driver.terminate_connection(volume1, conn) - self.driver.delete_volume(volume1) - vol_def = self.driver._is_volume_defined(volume1["name"]) - self.assertEqual(vol_def, False) - - # Make sure our host still exists - host_name = self.driver._get_host_from_iscsiname(conn["initiator"]) - host_def = self.driver._is_host_defined(host_name) - self.assertEquals(host_def, True) - - # Remove the mapping from the 2nd volume and delete it. The host should - # be automatically removed because there are no more mappings. - self.driver.terminate_connection(volume2, conn) - self.driver.delete_volume(volume2) - vol_def = self.driver._is_volume_defined(volume2["name"]) - self.assertEqual(vol_def, False) - - # Check if our host still exists (it should not) - ret = self.driver._get_host_from_iscsiname(conn["initiator"]) - self.assertEquals(ret, None) - ret = self.driver._is_host_defined(host_name) - self.assertEquals(ret, False) diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py deleted file mode 100644 index 7b14d8a99..000000000 --- a/nova/tests/test_volume.py +++ /dev/null @@ -1,931 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# 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. -""" -Tests for Volume Code. - -""" - -import cStringIO -import datetime - -import mox -import os -import shutil -import tempfile - -from nova import context -from nova import db -from nova import exception -from nova import flags -from nova.openstack.common import importutils -from nova.openstack.common.notifier import api as notifier_api -from nova.openstack.common.notifier import test_notifier -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 - - -class VolumeTestCase(test.TestCase): - """Test Case for volumes.""" - - def setUp(self): - super(VolumeTestCase, self).setUp() - self.compute = importutils.import_object(FLAGS.compute_manager) - vol_tmpdir = tempfile.mkdtemp() - self.flags(compute_driver='nova.virt.fake.FakeDriver', - volumes_dir=vol_tmpdir, - notification_driver=[test_notifier.__name__]) - self.stubs.Set(iscsi.TgtAdm, '_get_target', self.fake_get_target) - self.volume = importutils.import_object(FLAGS.volume_manager) - self.context = context.get_admin_context() - instance = db.instance_create(self.context, {}) - 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: - pass - db.instance_destroy(self.context, self.instance_uuid) - notifier_api._reset_drivers() - super(VolumeTestCase, self).tearDown() - - def fake_get_target(obj, iqn): - return 1 - - @staticmethod - 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 - vol['status'] = "creating" - vol['attach_status'] = "detached" - if metadata is not None: - vol['metadata'] = metadata - return db.volume_create(context.get_admin_context(), vol) - - def test_ec2_uuid_mapping(self): - ec2_vol = db.ec2_volume_create(context.get_admin_context(), - 'aaaaaaaa-bbbb-bbbb-bbbb-aaaaaaaaaaaa', 5) - self.assertEqual(5, ec2_vol['id']) - self.assertEqual('aaaaaaaa-bbbb-bbbb-bbbb-aaaaaaaaaaaa', - db.get_volume_uuid_by_ec2_id(context.get_admin_context(), 5)) - - ec2_vol = db.ec2_volume_create(context.get_admin_context(), - 'aaaaaaaa-bbbb-bbbb-bbbb-aaaaaaaaaaaa', 1) - self.assertEqual(1, ec2_vol['id']) - - ec2_vol = db.ec2_volume_create(context.get_admin_context(), - 'aaaaaaaa-bbbb-bbbb-bbbb-aaaaaaaaazzz') - self.assertEqual(6, ec2_vol['id']) - - def test_create_delete_volume(self): - """Test volume can be created and deleted.""" - # Need to stub out reserve, commit, and rollback - def fake_reserve(context, expire=None, **deltas): - return ["RESERVATION"] - - def fake_commit(context, reservations): - pass - - def fake_rollback(context, reservations): - pass - - self.stubs.Set(QUOTAS, "reserve", fake_reserve) - self.stubs.Set(QUOTAS, "commit", fake_commit) - self.stubs.Set(QUOTAS, "rollback", fake_rollback) - - volume = self._create_volume() - volume_id = volume['id'] - self.assertEquals(len(test_notifier.NOTIFICATIONS), 0) - self.volume.create_volume(self.context, volume_id) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) - self.assertEqual(volume_id, db.volume_get(context.get_admin_context(), - volume_id).id) - - self.volume.delete_volume(self.context, volume_id) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 4) - self.assertRaises(exception.NotFound, - db.volume_get, - self.context, - volume_id) - - 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, metadata=test_meta) - volume_id = volume['id'] - self.volume.create_volume(self.context, volume_id) - result_meta = { - volume.volume_metadata[0].key: volume.volume_metadata[0].value} - self.assertEqual(result_meta, test_meta) - - self.volume.delete_volume(self.context, volume_id) - self.assertRaises(exception.NotFound, - db.volume_get, - self.context, - volume_id) - - def _do_test_create_over_quota(self, resource, expected): - """Test volume creation over quota.""" - - def fake_reserve(context, **deltas): - kwargs = dict(overs=[resource], - quotas=dict(gigabytes=1000, volumes=10), - usages=dict(gigabytes=dict(reserved=1, in_use=999), - volumes=dict(reserved=1, in_use=9))) - raise exception.OverQuota(**kwargs) - - def fake_commit(context, reservations): - self.fail('should not commit over quota') - - self.stubs.Set(QUOTAS, 'reserve', fake_reserve) - self.stubs.Set(QUOTAS, 'commit', fake_commit) - - volume_api = nova.volume.api.API() - - self.assertRaises(expected, - volume_api.create, - self.context, - 2, - 'name', - 'description') - - def test_create_volumes_over_quota(self): - self._do_test_create_over_quota('volumes', - exception.VolumeLimitExceeded) - - def test_create_gigabytes_over_quota(self): - self._do_test_create_over_quota('gigabytes', - exception.VolumeSizeTooLarge) - - def test_delete_busy_volume(self): - """Test volume survives deletion if driver reports it as busy.""" - volume = self._create_volume() - volume_id = volume['id'] - self.volume.create_volume(self.context, volume_id) - - self.mox.StubOutWithMock(self.volume.driver, 'delete_volume') - self.volume.driver.delete_volume(mox.IgnoreArg()).AndRaise( - exception.VolumeIsBusy) - self.mox.ReplayAll() - res = self.volume.delete_volume(self.context, volume_id) - self.assertEqual(True, res) - volume_ref = db.volume_get(context.get_admin_context(), volume_id) - self.assertEqual(volume_id, volume_ref.id) - self.assertEqual("available", volume_ref.status) - - self.mox.UnsetStubs() - self.volume.delete_volume(self.context, volume_id) - - def test_create_volume_from_snapshot(self): - """Test volume can be created from a snapshot.""" - volume_src = self._create_volume() - self.volume.create_volume(self.context, volume_src['id']) - snapshot_id = self._create_snapshot(volume_src['id']) - self.volume.create_snapshot(self.context, volume_src['id'], - snapshot_id) - volume_dst = self._create_volume(0, snapshot_id) - self.volume.create_volume(self.context, volume_dst['id'], snapshot_id) - self.assertEqual(volume_dst['id'], - db.volume_get( - context.get_admin_context(), - volume_dst['id']).id) - self.assertEqual(snapshot_id, db.volume_get( - context.get_admin_context(), - volume_dst['id']).snapshot_id) - - self.volume.delete_volume(self.context, volume_dst['id']) - self.volume.delete_snapshot(self.context, snapshot_id) - self.volume.delete_volume(self.context, volume_src['id']) - - def test_too_big_volume(self): - """Ensure failure if a too large of a volume is requested.""" - # FIXME(vish): validation needs to move into the data layer in - # volume_create - return True - try: - volume = self._create_volume('1001') - self.volume.create_volume(self.context, volume) - self.fail("Should have thrown TypeError") - except TypeError: - pass - - def test_run_attach_detach_volume(self): - """Make sure volume can be attached and detached from instance.""" - inst = {} - inst['image_id'] = 1 - inst['reservation_id'] = 'r-fakeres' - inst['launch_time'] = '10' - inst['user_id'] = 'fake' - inst['project_id'] = 'fake' - inst['instance_type_id'] = '2' # m1.tiny - inst['ami_launch_index'] = 0 - instance = db.instance_create(self.context, {}) - instance_id = instance['id'] - instance_uuid = instance['uuid'] - mountpoint = "/dev/sdf" - volume = self._create_volume() - volume_id = volume['id'] - self.volume.create_volume(self.context, volume_id) - if FLAGS.fake_tests: - db.volume_attached(self.context, volume_id, instance_uuid, - mountpoint) - else: - self.compute.attach_volume(self.context, - instance_uuid, - volume_id, - mountpoint) - vol = db.volume_get(context.get_admin_context(), volume_id) - self.assertEqual(vol['status'], "in-use") - self.assertEqual(vol['attach_status'], "attached") - self.assertEqual(vol['mountpoint'], mountpoint) - self.assertEqual(vol['instance_uuid'], instance_uuid) - self.assertNotEqual(vol['attach_time'], None) - - self.assertRaises(exception.VolumeAttached, - self.volume.delete_volume, - self.context, - volume_id) - if FLAGS.fake_tests: - db.volume_detached(self.context, volume_id) - else: - self.compute.detach_volume(self.context, - instance_uuid, - volume_id) - vol = db.volume_get(self.context, volume_id) - self.assertEqual(vol['status'], "available") - self.assertEqual(vol['attach_time'], None) - - self.volume.delete_volume(self.context, volume_id) - self.assertRaises(exception.VolumeNotFound, - db.volume_get, - self.context, - volume_id) - db.instance_destroy(self.context, instance_uuid) - - def test_concurrent_volumes_get_different_targets(self): - """Ensure multiple concurrent volumes get different targets.""" - volume_ids = [] - targets = [] - - def _check(volume_id): - """Make sure targets aren't duplicated.""" - volume_ids.append(volume_id) - admin_context = context.get_admin_context() - iscsi_target = db.volume_get_iscsi_target_num(admin_context, - volume_id) - self.assert_(iscsi_target not in targets) - targets.append(iscsi_target) - - total_slots = FLAGS.iscsi_num_targets - for _index in xrange(total_slots): - self._create_volume() - for volume_id in volume_ids: - self.volume.delete_volume(self.context, volume_id) - - def test_multi_node(self): - # TODO(termie): Figure out how to test with two nodes, - # each of them having a different FLAG for storage_node - # This will allow us to test cross-node interactions - pass - - @staticmethod - def _create_snapshot(volume_id, size='0'): - """Create a snapshot object.""" - snap = {} - snap['volume_size'] = size - snap['user_id'] = 'fake' - snap['project_id'] = 'fake' - snap['volume_id'] = volume_id - snap['status'] = "creating" - return db.snapshot_create(context.get_admin_context(), snap)['id'] - - def test_create_delete_snapshot(self): - """Test snapshot can be created and deleted.""" - volume = self._create_volume() - self.volume.create_volume(self.context, volume['id']) - snapshot_id = self._create_snapshot(volume['id']) - self.volume.create_snapshot(self.context, volume['id'], snapshot_id) - self.assertEqual(snapshot_id, - db.snapshot_get(context.get_admin_context(), - snapshot_id).id) - - self.volume.delete_snapshot(self.context, snapshot_id) - self.assertRaises(exception.NotFound, - db.snapshot_get, - self.context, - snapshot_id) - self.volume.delete_volume(self.context, volume['id']) - - def test_cant_delete_volume_in_use(self): - """Test volume can't be deleted in invalid stats.""" - # create a volume and assign to host - volume = self._create_volume() - self.volume.create_volume(self.context, volume['id']) - volume['status'] = 'in-use' - volume['host'] = 'fakehost' - - volume_api = nova.volume.api.API() - - # 'in-use' status raises InvalidVolume - self.assertRaises(exception.InvalidVolume, - volume_api.delete, - self.context, - volume) - - # clean up - self.volume.delete_volume(self.context, volume['id']) - - def test_force_delete_volume(self): - """Test volume can be forced to delete.""" - # create a volume and assign to host - volume = self._create_volume() - self.volume.create_volume(self.context, volume['id']) - volume['status'] = 'error_deleting' - volume['host'] = 'fakehost' - - volume_api = nova.volume.api.API() - - # 'error_deleting' volumes can't be deleted - self.assertRaises(exception.InvalidVolume, - volume_api.delete, - self.context, - volume) - - # delete with force - volume_api.delete(self.context, volume, force=True) - - # status is deleting - volume = db.volume_get(context.get_admin_context(), volume['id']) - self.assertEquals(volume['status'], 'deleting') - - # clean up - self.volume.delete_volume(self.context, volume['id']) - - def test_cant_delete_volume_with_snapshots(self): - """Test snapshot can be created and deleted.""" - volume = self._create_volume() - self.volume.create_volume(self.context, volume['id']) - snapshot_id = self._create_snapshot(volume['id']) - self.volume.create_snapshot(self.context, volume['id'], snapshot_id) - self.assertEqual(snapshot_id, - db.snapshot_get(context.get_admin_context(), - snapshot_id).id) - - volume['status'] = 'available' - volume['host'] = 'fakehost' - - volume_api = nova.volume.api.API() - - self.assertRaises(exception.InvalidVolume, - volume_api.delete, - self.context, - volume) - self.volume.delete_snapshot(self.context, snapshot_id) - self.volume.delete_volume(self.context, volume['id']) - - def test_can_delete_errored_snapshot(self): - """Test snapshot can be created and deleted.""" - volume = self._create_volume() - self.volume.create_volume(self.context, volume['id']) - snapshot_id = self._create_snapshot(volume['id']) - self.volume.create_snapshot(self.context, volume['id'], snapshot_id) - snapshot = db.snapshot_get(context.get_admin_context(), - snapshot_id) - - volume_api = nova.volume.api.API() - - snapshot['status'] = 'badstatus' - self.assertRaises(exception.InvalidVolume, - volume_api.delete_snapshot, - self.context, - snapshot) - - snapshot['status'] = 'error' - self.volume.delete_snapshot(self.context, snapshot_id) - self.volume.delete_volume(self.context, volume['id']) - - def test_create_snapshot_force(self): - """Test snapshot in use can be created forcibly.""" - - def fake_cast(ctxt, topic, msg): - pass - self.stubs.Set(rpc, 'cast', fake_cast) - - volume = self._create_volume() - self.volume.create_volume(self.context, volume['id']) - db.volume_attached(self.context, volume['id'], self.instance_uuid, - '/dev/sda1') - - volume_api = nova.volume.api.API() - volume = volume_api.get(self.context, volume['id']) - self.assertRaises(exception.InvalidVolume, - volume_api.create_snapshot, - self.context, volume, - 'fake_name', 'fake_description') - snapshot_ref = volume_api.create_snapshot_force(self.context, - volume, - 'fake_name', - 'fake_description') - db.snapshot_destroy(self.context, snapshot_ref['id']) - db.volume_destroy(self.context, volume['id']) - - def test_delete_busy_snapshot(self): - """Test snapshot can be created and deleted.""" - volume = self._create_volume() - volume_id = volume['id'] - self.volume.create_volume(self.context, volume_id) - snapshot_id = self._create_snapshot(volume_id) - self.volume.create_snapshot(self.context, volume_id, snapshot_id) - - self.mox.StubOutWithMock(self.volume.driver, 'delete_snapshot') - self.volume.driver.delete_snapshot(mox.IgnoreArg()).AndRaise( - exception.SnapshotIsBusy) - self.mox.ReplayAll() - self.volume.delete_snapshot(self.context, snapshot_id) - snapshot_ref = db.snapshot_get(self.context, snapshot_id) - self.assertEqual(snapshot_id, snapshot_ref.id) - self.assertEqual("available", snapshot_ref.status) - - self.mox.UnsetStubs() - self.volume.delete_snapshot(self.context, snapshot_id) - self.volume.delete_volume(self.context, volume_id) - - def test_create_volume_usage_notification(self): - """Ensure create volume generates appropriate usage notification""" - volume = self._create_volume() - volume_id = volume['id'] - self.assertEquals(len(test_notifier.NOTIFICATIONS), 0) - self.volume.create_volume(self.context, volume_id) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], 'volume.create.start') - payload = msg['payload'] - self.assertEquals(payload['status'], 'creating') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'volume.create.end') - payload = msg['payload'] - self.assertEquals(payload['tenant_id'], volume['project_id']) - self.assertEquals(payload['user_id'], volume['user_id']) - self.assertEquals(payload['volume_id'], volume['id']) - self.assertEquals(payload['status'], 'available') - self.assertEquals(payload['size'], volume['size']) - self.assertTrue('display_name' in payload) - self.assertTrue('snapshot_id' in payload) - self.assertTrue('launched_at' in payload) - self.assertTrue('created_at' in payload) - self.volume.delete_volume(self.context, volume_id) - - def _do_test_create_volume_with_size(self, size): - def fake_reserve(context, expire=None, **deltas): - return ["RESERVATION"] - - def fake_commit(context, reservations): - pass - - def fake_rollback(context, reservations): - pass - - self.stubs.Set(QUOTAS, "reserve", fake_reserve) - self.stubs.Set(QUOTAS, "commit", fake_commit) - self.stubs.Set(QUOTAS, "rollback", fake_rollback) - - volume_api = nova.volume.api.API() - - volume = volume_api.create(self.context, - size, - 'name', - 'description') - self.assertEquals(volume['size'], int(size)) - - def test_create_volume_int_size(self): - """Test volume creation with int size.""" - self._do_test_create_volume_with_size(2) - - def test_create_volume_string_size(self): - """Test volume creation with string size.""" - self._do_test_create_volume_with_size('2') - - def test_create_volume_with_bad_size(self): - def fake_reserve(context, expire=None, **deltas): - return ["RESERVATION"] - - def fake_commit(context, reservations): - pass - - def fake_rollback(context, reservations): - pass - - self.stubs.Set(QUOTAS, "reserve", fake_reserve) - self.stubs.Set(QUOTAS, "commit", fake_commit) - self.stubs.Set(QUOTAS, "rollback", fake_rollback) - - volume_api = nova.volume.api.API() - - self.assertRaises(exception.InvalidInput, - volume_api.create, - self.context, - '2Gb', - 'name', - 'description') - - def test_begin_roll_detaching_volume(self): - """Test begin_detaching and roll_detaching functions.""" - volume = self._create_volume() - volume_api = nova.volume.api.API() - volume_api.begin_detaching(self.context, volume) - volume = db.volume_get(self.context, volume['id']) - self.assertEqual(volume['status'], "detaching") - volume_api.roll_detaching(self.context, volume) - 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.""" - driver_name = "nova.volume.driver.FakeBaseDriver" - - def setUp(self): - super(DriverTestCase, self).setUp() - vol_tmpdir = tempfile.mkdtemp() - self.flags(volume_driver=self.driver_name, - volumes_dir=vol_tmpdir) - self.volume = importutils.import_object(FLAGS.volume_manager) - self.context = context.get_admin_context() - self.output = "" - self.stubs.Set(iscsi.TgtAdm, '_get_target', self.fake_get_target) - - def _fake_execute(_command, *_args, **_kwargs): - """Fake _execute.""" - return self.output, None - self.volume.driver.set_execute(_fake_execute) - - instance = db.instance_create(self.context, {}) - self.instance_id = instance['id'] - self.instance_uuid = instance['uuid'] - - def tearDown(self): - try: - shutil.rmtree(FLAGS.volumes_dir) - except OSError: - pass - super(DriverTestCase, self).tearDown() - - def fake_get_target(obj, iqn): - return 1 - - def _attach_volume(self): - """Attach volumes to an instance.""" - return [] - - def _detach_volume(self, volume_id_list): - """Detach volumes from an instance.""" - for volume_id in volume_id_list: - db.volume_detached(self.context, volume_id) - self.volume.delete_volume(self.context, volume_id) - - -class VolumeDriverTestCase(DriverTestCase): - """Test case for VolumeDriver""" - driver_name = "nova.volume.driver.VolumeDriver" - - def test_delete_busy_volume(self): - """Test deleting a busy volume.""" - self.stubs.Set(self.volume.driver, '_volume_not_present', - lambda x: False) - self.stubs.Set(self.volume.driver, '_delete_volume', - lambda x, y: False) - # Want DriverTestCase._fake_execute to return 'o' so that - # volume.driver.delete_volume() raises the VolumeIsBusy exception. - self.output = 'o' - self.assertRaises(exception.VolumeIsBusy, - self.volume.driver.delete_volume, - {'name': 'test1', 'size': 1024}) - # when DriverTestCase._fake_execute returns something other than - # 'o' volume.driver.delete_volume() does not raise an exception. - self.output = 'x' - self.volume.driver.delete_volume({'name': 'test1', 'size': 1024}) - - -class ISCSITestCase(DriverTestCase): - """Test Case for ISCSIDriver""" - driver_name = "nova.volume.driver.ISCSIDriver" - - def _attach_volume(self): - """Attach volumes to an instance. """ - volume_id_list = [] - for index in xrange(3): - vol = {} - vol['size'] = 0 - vol_ref = db.volume_create(self.context, vol) - self.volume.create_volume(self.context, vol_ref['id']) - vol_ref = db.volume_get(self.context, vol_ref['id']) - - # each volume has a different mountpoint - mountpoint = "/dev/sd" + chr((ord('b') + index)) - db.volume_attached(self.context, vol_ref['id'], self.instance_uuid, - mountpoint) - volume_id_list.append(vol_ref['id']) - - return volume_id_list - - def test_check_for_export_with_no_volume(self): - self.volume.check_for_export(self.context, self.instance_id) - - -class VolumePolicyTestCase(test.TestCase): - - def setUp(self): - super(VolumePolicyTestCase, self).setUp() - - nova.policy.reset() - nova.policy.init() - - self.context = context.get_admin_context() - - def tearDown(self): - super(VolumePolicyTestCase, self).tearDown() - nova.policy.reset() - - def _set_rules(self, rules): - nova.common.policy.set_brain(nova.common.policy.HttpBrain(rules)) - - def test_check_policy(self): - self.mox.StubOutWithMock(nova.policy, 'enforce') - target = { - 'project_id': self.context.project_id, - 'user_id': self.context.user_id, - } - nova.policy.enforce(self.context, 'volume:attach', target) - self.mox.ReplayAll() - nova.volume.api.check_policy(self.context, 'attach') - - def test_check_policy_with_target(self): - self.mox.StubOutWithMock(nova.policy, 'enforce') - target = { - 'project_id': self.context.project_id, - 'user_id': self.context.user_id, - 'id': 2, - } - nova.policy.enforce(self.context, 'volume:attach', target) - self.mox.ReplayAll() - nova.volume.api.check_policy(self.context, 'attach', {'id': 2}) diff --git a/nova/tests/test_volume_types.py b/nova/tests/test_volume_types.py deleted file mode 100644 index 5e178d5e1..000000000 --- a/nova/tests/test_volume_types.py +++ /dev/null @@ -1,167 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 Zadara Storage Inc. -# Copyright (c) 2011 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. -""" -Unit Tests for volume types code -""" -import time - -from nova import context -from nova.db.sqlalchemy import models -from nova.db.sqlalchemy import session as sql_session -from nova import exception -from nova import flags -from nova.openstack.common import log as logging -from nova import test -from nova.volume import volume_types - -FLAGS = flags.FLAGS -LOG = logging.getLogger(__name__) - - -class VolumeTypeTestCase(test.TestCase): - """Test cases for volume type code""" - def setUp(self): - super(VolumeTypeTestCase, self).setUp() - - self.ctxt = context.get_admin_context() - self.vol_type1_name = str(int(time.time())) - self.vol_type1_specs = dict( - type="physical drive", - drive_type="SAS", - size="300", - rpm="7200", - visible="True") - - def test_volume_type_create_then_destroy(self): - """Ensure volume types can be created and deleted""" - prev_all_vtypes = volume_types.get_all_types(self.ctxt) - - volume_types.create(self.ctxt, - self.vol_type1_name, - self.vol_type1_specs) - new = volume_types.get_volume_type_by_name(self.ctxt, - self.vol_type1_name) - - LOG.info(_("Given data: %s"), self.vol_type1_specs) - LOG.info(_("Result data: %s"), new) - - for k, v in self.vol_type1_specs.iteritems(): - self.assertEqual(v, new['extra_specs'][k], - 'one of fields does not match') - - new_all_vtypes = volume_types.get_all_types(self.ctxt) - self.assertEqual(len(prev_all_vtypes) + 1, - len(new_all_vtypes), - 'drive type was not created') - - volume_types.destroy(self.ctxt, self.vol_type1_name) - new_all_vtypes = volume_types.get_all_types(self.ctxt) - self.assertEqual(prev_all_vtypes, - new_all_vtypes, - 'drive type was not deleted') - - def test_get_all_volume_types(self): - """Ensures that all volume types can be retrieved""" - session = sql_session.get_session() - total_volume_types = session.query(models.VolumeTypes).count() - vol_types = volume_types.get_all_types(self.ctxt) - self.assertEqual(total_volume_types, len(vol_types)) - - def test_non_existent_vol_type_shouldnt_delete(self): - """Ensures that volume type creation fails with invalid args""" - self.assertRaises(exception.VolumeTypeNotFoundByName, - volume_types.destroy, self.ctxt, "sfsfsdfdfs") - - def test_repeated_vol_types_shouldnt_raise(self): - """Ensures that volume duplicates don't raise""" - new_name = self.vol_type1_name + "dup" - volume_types.create(self.ctxt, new_name) - volume_types.destroy(self.ctxt, new_name) - volume_types.create(self.ctxt, new_name) - - def test_invalid_volume_types_params(self): - """Ensures that volume type creation fails with invalid args""" - self.assertRaises(exception.InvalidVolumeType, - volume_types.destroy, self.ctxt, None) - self.assertRaises(exception.InvalidVolumeType, - volume_types.get_volume_type, self.ctxt, None) - self.assertRaises(exception.InvalidVolumeType, - volume_types.get_volume_type_by_name, - self.ctxt, None) - - def test_volume_type_get_by_id_and_name(self): - """Ensure volume types get returns same entry""" - volume_types.create(self.ctxt, - self.vol_type1_name, - self.vol_type1_specs) - new = volume_types.get_volume_type_by_name(self.ctxt, - self.vol_type1_name) - - new2 = volume_types.get_volume_type(self.ctxt, new['id']) - self.assertEqual(new, new2) - - def test_volume_type_search_by_extra_spec(self): - """Ensure volume types get by extra spec returns correct type""" - volume_types.create(self.ctxt, "type1", {"key1": "val1", - "key2": "val2"}) - volume_types.create(self.ctxt, "type2", {"key2": "val2", - "key3": "val3"}) - volume_types.create(self.ctxt, "type3", {"key3": "another_value", - "key4": "val4"}) - - vol_types = volume_types.get_all_types(self.ctxt, - search_opts={'extra_specs': {"key1": "val1"}}) - LOG.info("vol_types: %s" % vol_types) - self.assertEqual(len(vol_types), 1) - self.assertTrue("type1" in vol_types.keys()) - self.assertEqual(vol_types['type1']['extra_specs'], - {"key1": "val1", "key2": "val2"}) - - vol_types = volume_types.get_all_types(self.ctxt, - search_opts={'extra_specs': {"key2": "val2"}}) - LOG.info("vol_types: %s" % vol_types) - self.assertEqual(len(vol_types), 2) - self.assertTrue("type1" in vol_types.keys()) - self.assertTrue("type2" in vol_types.keys()) - - vol_types = volume_types.get_all_types(self.ctxt, - search_opts={'extra_specs': {"key3": "val3"}}) - LOG.info("vol_types: %s" % vol_types) - self.assertEqual(len(vol_types), 1) - self.assertTrue("type2" in vol_types.keys()) - - def test_volume_type_search_by_extra_spec_multiple(self): - """Ensure volume types get by extra spec returns correct type""" - volume_types.create(self.ctxt, "type1", {"key1": "val1", - "key2": "val2", - "key3": "val3"}) - volume_types.create(self.ctxt, "type2", {"key2": "val2", - "key3": "val3"}) - volume_types.create(self.ctxt, "type3", {"key1": "val1", - "key3": "val3", - "key4": "val4"}) - - vol_types = volume_types.get_all_types(self.ctxt, - search_opts={'extra_specs': {"key1": "val1", - "key3": "val3"}}) - LOG.info("vol_types: %s" % vol_types) - self.assertEqual(len(vol_types), 2) - self.assertTrue("type1" in vol_types.keys()) - self.assertTrue("type3" in vol_types.keys()) - self.assertEqual(vol_types['type1']['extra_specs'], - {"key1": "val1", "key2": "val2", "key3": "val3"}) - self.assertEqual(vol_types['type3']['extra_specs'], - {"key1": "val1", "key3": "val3", "key4": "val4"}) diff --git a/nova/tests/test_volume_types_extra_specs.py b/nova/tests/test_volume_types_extra_specs.py deleted file mode 100644 index ed7840e0a..000000000 --- a/nova/tests/test_volume_types_extra_specs.py +++ /dev/null @@ -1,130 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 Zadara Storage Inc. -# Copyright (c) 2011 OpenStack LLC. -# Copyright 2011 University of Southern California -# 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. -""" -Unit Tests for volume types extra specs code -""" - -from nova import context -from nova import db -from nova import test - - -class VolumeTypeExtraSpecsTestCase(test.TestCase): - - def setUp(self): - super(VolumeTypeExtraSpecsTestCase, self).setUp() - self.context = context.get_admin_context() - self.vol_type1 = dict(name="TEST: Regular volume test") - self.vol_type1_specs = dict(vol_extra1="value1", - vol_extra2="value2", - vol_extra3=3) - self.vol_type1['extra_specs'] = self.vol_type1_specs - ref = db.volume_type_create(self.context, self.vol_type1) - self.volume_type1_id = ref.id - for k, v in self.vol_type1_specs.iteritems(): - self.vol_type1_specs[k] = str(v) - - self.vol_type2_noextra = dict(name="TEST: Volume type without extra") - ref = db.volume_type_create(self.context, self.vol_type2_noextra) - self.vol_type2_id = ref.id - - def tearDown(self): - # Remove the volume type from the database - db.volume_type_destroy(context.get_admin_context(), - self.vol_type1['name']) - db.volume_type_destroy(context.get_admin_context(), - self.vol_type2_noextra['name']) - super(VolumeTypeExtraSpecsTestCase, self).tearDown() - - def test_volume_type_specs_get(self): - expected_specs = self.vol_type1_specs.copy() - actual_specs = db.volume_type_extra_specs_get( - context.get_admin_context(), - self.volume_type1_id) - self.assertEquals(expected_specs, actual_specs) - - def test_volume_type_extra_specs_delete(self): - expected_specs = self.vol_type1_specs.copy() - del expected_specs['vol_extra2'] - db.volume_type_extra_specs_delete(context.get_admin_context(), - self.volume_type1_id, - 'vol_extra2') - actual_specs = db.volume_type_extra_specs_get( - context.get_admin_context(), - self.volume_type1_id) - self.assertEquals(expected_specs, actual_specs) - - def test_volume_type_extra_specs_update(self): - expected_specs = self.vol_type1_specs.copy() - expected_specs['vol_extra3'] = "4" - db.volume_type_extra_specs_update_or_create( - context.get_admin_context(), - self.volume_type1_id, - dict(vol_extra3=4)) - actual_specs = db.volume_type_extra_specs_get( - context.get_admin_context(), - self.volume_type1_id) - self.assertEquals(expected_specs, actual_specs) - - def test_volume_type_extra_specs_create(self): - expected_specs = self.vol_type1_specs.copy() - expected_specs['vol_extra4'] = 'value4' - expected_specs['vol_extra5'] = 'value5' - db.volume_type_extra_specs_update_or_create( - context.get_admin_context(), - self.volume_type1_id, - dict(vol_extra4="value4", - vol_extra5="value5")) - actual_specs = db.volume_type_extra_specs_get( - context.get_admin_context(), - self.volume_type1_id) - self.assertEquals(expected_specs, actual_specs) - - def test_volume_type_get_with_extra_specs(self): - volume_type = db.volume_type_get( - context.get_admin_context(), - self.volume_type1_id) - self.assertEquals(volume_type['extra_specs'], - self.vol_type1_specs) - - volume_type = db.volume_type_get( - context.get_admin_context(), - self.vol_type2_id) - self.assertEquals(volume_type['extra_specs'], {}) - - def test_volume_type_get_by_name_with_extra_specs(self): - volume_type = db.volume_type_get_by_name( - context.get_admin_context(), - self.vol_type1['name']) - self.assertEquals(volume_type['extra_specs'], - self.vol_type1_specs) - - volume_type = db.volume_type_get_by_name( - context.get_admin_context(), - self.vol_type2_noextra['name']) - self.assertEquals(volume_type['extra_specs'], {}) - - def test_volume_type_get_all(self): - expected_specs = self.vol_type1_specs.copy() - - types = db.volume_type_get_all(context.get_admin_context()) - - self.assertEquals( - types[self.vol_type1['name']]['extra_specs'], expected_specs) - - self.assertEquals( - types[self.vol_type2_noextra['name']]['extra_specs'], {}) diff --git a/nova/tests/test_volume_utils.py b/nova/tests/test_volume_utils.py deleted file mode 100644 index 89ad7c3db..000000000 --- a/nova/tests/test_volume_utils.py +++ /dev/null @@ -1,91 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 OpenStack LLC. -# All Rights Reserved. -# -# 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. - -"""Tests For miscellaneous util methods used with volume.""" - -from nova import context -from nova import db -from nova import flags -from nova.openstack.common import importutils -from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier_api -from nova.openstack.common.notifier import test_notifier -from nova import test -from nova.tests import fake_network -from nova.volume import utils as volume_utils - - -LOG = logging.getLogger(__name__) -FLAGS = flags.FLAGS - - -class UsageInfoTestCase(test.TestCase): - - def setUp(self): - super(UsageInfoTestCase, self).setUp() - self.flags(compute_driver='nova.virt.fake.FakeDriver', - host='fake', - notification_driver=[test_notifier.__name__]) - fake_network.set_stub_network_methods(self.stubs) - - self.volume = importutils.import_object(FLAGS.volume_manager) - self.user_id = 'fake' - self.project_id = 'fake' - self.snapshot_id = 'fake' - self.volume_size = 0 - self.context = context.RequestContext(self.user_id, self.project_id) - test_notifier.NOTIFICATIONS = [] - - def tearDown(self): - notifier_api._reset_drivers() - super(UsageInfoTestCase, self).tearDown() - - def _create_volume(self, params={}): - """Create a test volume""" - vol = {} - vol['snapshot_id'] = self.snapshot_id - vol['user_id'] = self.user_id - vol['project_id'] = self.project_id - vol['host'] = FLAGS.host - vol['availability_zone'] = FLAGS.storage_availability_zone - vol['status'] = "creating" - vol['attach_status'] = "detached" - vol['size'] = self.volume_size - vol.update(params) - return db.volume_create(self.context, vol)['id'] - - def test_notify_usage_exists(self): - """Ensure 'exists' notification generates appropriate usage data.""" - volume_id = self._create_volume() - volume = db.volume_get(self.context, volume_id) - volume_utils.notify_usage_exists(self.context, volume) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'volume.exists') - payload = msg['payload'] - self.assertEquals(payload['tenant_id'], self.project_id) - self.assertEquals(payload['user_id'], self.user_id) - self.assertEquals(payload['snapshot_id'], self.snapshot_id) - self.assertEquals(payload['volume_id'], volume.id) - self.assertEquals(payload['size'], self.volume_size) - for attr in ('display_name', 'created_at', 'launched_at', - 'status', 'audit_period_beginning', - 'audit_period_ending'): - self.assertTrue(attr in payload, - msg="Key %s not in payload" % attr) - db.volume_destroy(context.get_admin_context(), volume['id']) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index a7bfa7548..11e8844c4 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -170,7 +170,7 @@ class XenAPIVolumeTestCase(stubs.XenAPITestBase): vol['user_id'] = 'fake' vol['project_id'] = 'fake' vol['host'] = 'localhost' - vol['availability_zone'] = FLAGS.storage_availability_zone + vol['availability_zone'] = FLAGS.node_availability_zone vol['status'] = "creating" vol['attach_status'] = "detached" return db.volume_create(self.context, vol) diff --git a/nova/tests/test_xensm.py b/nova/tests/test_xensm.py deleted file mode 100644 index 2f2108aa4..000000000 --- a/nova/tests/test_xensm.py +++ /dev/null @@ -1,140 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2010 Citrix Systems, Inc. -# -# 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. - -"""Test suite for Xen Storage Manager Volume Driver.""" - - -from nova import context -from nova import db -from nova import exception -from nova import flags -from nova.openstack.common import log as logging -from nova.tests.xenapi import stubs -from nova.virt.xenapi import fake as xenapi_fake -from nova.volume import xensm - -LOG = logging.getLogger(__name__) - -FLAGS = flags.FLAGS - - -class XenSMTestCase(stubs.XenAPITestBase): - """Unit tests for Xen Storage Manager Volume operations.""" - - def _get_sm_backend_params(self): - config_params = ("name_label=testsmbackend " - "server=localhost " - "serverpath=/tmp/nfspath") - params = dict(flavor_id=1, - sr_uuid=None, - sr_type='nfs', - config_params=config_params) - return params - - def setUp(self): - super(XenSMTestCase, self).setUp() - self.user_id = 'fake' - self.project_id = 'fake' - self.context = context.RequestContext(self.user_id, self.project_id) - self.flags(compute_driver='xenapi.XenAPIDriver', - xenapi_connection_url='http://test_url', - xenapi_connection_username='test_user', - xenapi_connection_password='test_pass') - stubs.stubout_session(self.stubs, xenapi_fake.SessionBase) - xenapi_fake.reset() - self.driver = xensm.XenSMDriver() - self.driver.db = db - - def _setup_step(self, ctxt): - # Create a fake backend conf - params = self._get_sm_backend_params() - beconf = db.sm_backend_conf_create(ctxt, - params) - # Call setup, the one time operation that will create a backend SR - self.driver.do_setup(ctxt) - return beconf - - def test_do_setup(self): - ctxt = context.get_admin_context() - beconf = self._setup_step(ctxt) - beconf = db.sm_backend_conf_get(ctxt, beconf['id']) - self.assertIsInstance(beconf['sr_uuid'], basestring) - - def _create_volume(self, size=0): - """Create a volume object.""" - vol = {} - vol['size'] = size - vol['user_id'] = 'fake' - vol['project_id'] = 'fake' - vol['host'] = 'localhost' - vol['availability_zone'] = FLAGS.storage_availability_zone - vol['status'] = "creating" - vol['attach_status'] = "detached" - return db.volume_create(self.context, vol) - - def test_create_volume(self): - ctxt = context.get_admin_context() - beconf = self._setup_step(ctxt) - volume = self._create_volume() - self.driver.create_volume(volume) - db.sm_volume_get(ctxt, volume['id']) - - def test_local_path(self): - ctxt = context.get_admin_context() - volume = self._create_volume() - val = self.driver.local_path(volume) - self.assertIsInstance(val, basestring) - - def test_delete_volume(self): - ctxt = context.get_admin_context() - beconf = self._setup_step(ctxt) - volume = self._create_volume() - self.driver.create_volume(volume) - self.driver.delete_volume(volume) - self.assertRaises(exception.NotFound, - db.sm_volume_get, - ctxt, - volume['id']) - - def test_delete_volume_raises_notfound(self): - ctxt = context.get_admin_context() - beconf = self._setup_step(ctxt) - self.assertRaises(exception.NotFound, - self.driver.delete_volume, - {'id': "FA15E-1D"}) - - def _get_expected_conn(self, beconf, vol): - expected = {} - expected['volume_id'] = unicode(vol['id']) - expected['flavor_id'] = beconf['flavor_id'] - expected['sr_uuid'] = unicode(beconf['sr_uuid']) - expected['sr_type'] = unicode(beconf['sr_type']) - return expected - - def test_initialize_connection(self): - ctxt = context.get_admin_context() - beconf = self._setup_step(ctxt) - beconf = db.sm_backend_conf_get(ctxt, beconf['id']) - volume = self._create_volume() - self.driver.create_volume(volume) - expected = self._get_expected_conn(beconf, volume) - conn = self.driver.initialize_connection(volume, 'fakeConnector') - res = {} - for key in ['volume_id', 'flavor_id', 'sr_uuid', 'sr_type']: - res[key] = conn['data'][key] - self.assertDictMatch(expected, res) - self.assertEqual(set(conn['data']['introduce_sr_keys']), - set([u'sr_type', u'server', u'serverpath'])) diff --git a/nova/tests/volume/test_HpSanISCSIDriver.py b/nova/tests/volume/test_HpSanISCSIDriver.py deleted file mode 100644 index d6d3f3488..000000000 --- a/nova/tests/volume/test_HpSanISCSIDriver.py +++ /dev/null @@ -1,209 +0,0 @@ -# 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. -from nova import exception -from nova.openstack.common import log as logging -from nova import test -from nova.volume import san - -LOG = logging.getLogger(__name__) - - -class HpSanISCSITestCase(test.TestCase): - - def setUp(self): - super(HpSanISCSITestCase, self).setUp() - self.stubs.Set(san.HpSanISCSIDriver, "_cliq_run", - self._fake_cliq_run) - self.stubs.Set(san.HpSanISCSIDriver, "_get_iscsi_properties", - self._fake_get_iscsi_properties) - self.driver = san.HpSanISCSIDriver() - self.volume_name = "fakevolume" - self.connector = {'ip': '10.0.0.2', - 'initiator': 'iqn.1993-08.org.debian:01:222', - 'host': 'fakehost'} - self.properties = {'target_discoverd': True, - 'target_portal': '10.0.1.6:3260', - 'target_iqn': - 'iqn.2003-10.com.lefthandnetworks:group01:25366:fakev', - 'volume_id': 1} - - def _fake_get_iscsi_properties(self, volume): - return self.properties - - def _fake_cliq_run(self, verb, cliq_args): - """Return fake results for the various methods.""" - - def create_volume(cliq_args): - """ - input = "createVolume description="fake description" - clusterName=Cluster01 volumeName=fakevolume - thinProvision=0 output=XML size=1GB" - """ - output = """<gauche version="1.0"> - <response description="Operation succeeded." - name="CliqSuccess" processingTime="181" result="0"/> - </gauche>""" - self.assertEqual(cliq_args['volumeName'], self.volume_name) - self.assertEqual(cliq_args['thinProvision'], '1') - self.assertEqual(cliq_args['size'], '1GB') - return output, None - - def delete_volume(cliq_args): - """ - input = "deleteVolume volumeName=fakevolume prompt=false - output=XML" - """ - output = """<gauche version="1.0"> - <response description="Operation succeeded." - name="CliqSuccess" processingTime="164" result="0"/> - </gauche>""" - self.assertEqual(cliq_args['volumeName'], self.volume_name) - self.assertEqual(cliq_args['prompt'], 'false') - return output, None - - def assign_volume(cliq_args): - """ - input = "assignVolumeToServer volumeName=fakevolume - serverName=fakehost - output=XML" - """ - output = """<gauche version="1.0"> - <response description="Operation succeeded." - name="CliqSuccess" processingTime="174" result="0"/> - </gauche>""" - self.assertEqual(cliq_args['volumeName'], self.volume_name) - self.assertEqual(cliq_args['serverName'], self.connector['host']) - return output, None - - def unassign_volume(cliq_args): - """ - input = "unassignVolumeToServer volumeName=fakevolume - serverName=fakehost output=XML - """ - output = """<gauche version="1.0"> - <response description="Operation succeeded." - name="CliqSuccess" processingTime="205" result="0"/> - </gauche>""" - self.assertEqual(cliq_args['volumeName'], self.volume_name) - self.assertEqual(cliq_args['serverName'], self.connector['host']) - return output, None - - def get_cluster_info(cliq_args): - """ - input = "getClusterInfo clusterName=Cluster01 searchDepth=1 - verbose=0 output=XML" - """ - output = """<gauche version="1.0"> - <response description="Operation succeeded." name="CliqSuccess" - processingTime="1164" result="0"> - <cluster blockSize="1024" description="" - maxVolumeSizeReplication1="622957690" - maxVolumeSizeReplication2="311480287" - minVolumeSize="262144" name="Cluster01" - pageSize="262144" spaceTotal="633697992" - storageNodeCount="2" unprovisionedSpace="622960574" - useVip="true"> - <nsm ipAddress="10.0.1.7" name="111-vsa"/> - <nsm ipAddress="10.0.1.8" name="112-vsa"/> - <vip ipAddress="10.0.1.6" subnetMask="255.255.255.0"/> - </cluster></response></gauche>""" - return output, None - - def get_volume_info(cliq_args): - """ - input = "getVolumeInfo volumeName=fakevolume output=XML" - """ - output = """<gauche version="1.0"> - <response description="Operation succeeded." name="CliqSuccess" - processingTime="87" result="0"> - <volume autogrowPages="4" availability="online" - blockSize="1024" bytesWritten="0" checkSum="false" - clusterName="Cluster01" created="2011-02-08T19:56:53Z" - deleting="false" description="" groupName="Group01" - initialQuota="536870912" isPrimary="true" - iscsiIqn="iqn.2003-10.com.lefthandnetworks:group01:25366:fakev" - maxSize="6865387257856" md5="9fa5c8b2cca54b2948a63d833097e1ca" - minReplication="1" name="vol-b" parity="0" replication="2" - reserveQuota="536870912" scratchQuota="4194304" - serialNumber="9fa5c8b2cca54b2948a63d8" - size="1073741824" stridePages="32" thinProvision="true"> - <status description="OK" value="2"/> - <permission access="rw" authGroup="api-1" - chapName="chapusername" chapRequired="true" - id="25369" initiatorSecret="" iqn="" - iscsiEnabled="true" loadBalance="true" - targetSecret="supersecret"/> - </volume></response></gauche>""" - return output, None - - def test_error(cliq_args): - output = """<gauche version="1.0"> - <response description="Volume '134234' not found." - name="CliqVolumeNotFound" processingTime="1083" - result="8000100c"/> - </gauche>""" - return output, None - - self.assertEqual(cliq_args['output'], 'XML') - try: - verbs = {'createVolume': create_volume, - 'deleteVolume': delete_volume, - 'assignVolumeToServer': assign_volume, - 'unassignVolumeToServer': unassign_volume, - 'getClusterInfo': get_cluster_info, - 'getVolumeInfo': get_volume_info, - 'testError': test_error} - except KeyError: - raise NotImplementedError() - - return verbs[verb](cliq_args) - - def test_create_volume(self): - volume = {'name': self.volume_name, 'size': 1} - model_update = self.driver.create_volume(volume) - expected_iqn = "iqn.2003-10.com.lefthandnetworks:group01:25366:fakev 0" - expected_location = "10.0.1.6:3260,1 %s" % expected_iqn - self.assertEqual(model_update['provider_location'], expected_location) - - def test_delete_volume(self): - volume = {'name': self.volume_name} - self.driver.delete_volume(volume) - - def test_initialize_connection(self): - volume = {'name': self.volume_name} - result = self.driver.initialize_connection(volume, self.connector) - self.assertEqual(result['driver_volume_type'], 'iscsi') - self.assertDictMatch(result['data'], self.properties) - - def test_terminate_connection(self): - volume = {'name': self.volume_name} - self.driver.terminate_connection(volume, self.connector) - - def test_create_snapshot(self): - try: - self.driver.create_snapshot("") - except NotImplementedError: - pass - - def test_create_volume_from_snapshot(self): - try: - self.driver.create_volume_from_snapshot("", "") - except NotImplementedError: - pass - - def test_cliq_error(self): - try: - self.driver._cliq_run_xml("testError", {}) - except exception.NovaException: - pass |
