def _test_failover_model_updates(self, in_volumes, in_snapshots, driver_volumes, driver_result, out_volumes, out_snapshots, in_groups=None, out_groups=None, driver_group_result=None, secondary_id=None): host = vol_utils.extract_host(self.manager.host) utils.create_service(self.context, {'host': host, 'binary': 'cinder-volume'}) for volume in in_volumes: utils.create_volume(self.context, self.manager.host, **volume) for snapshot in in_snapshots: utils.create_snapshot(self.context, **snapshot) for group in in_groups: utils.create_group(self.context, self.manager.host, **group) with mock.patch.object( self.manager.driver, 'failover_host', return_value=(secondary_id, driver_result, driver_group_result)) as driver_mock: self.manager.failover_host(self.context, secondary_id) self.assertSetEqual(driver_volumes, {v.id for v in driver_mock.call_args[0][1]}) self._check_failover_db(objects.VolumeList, out_volumes) self._check_failover_db(objects.SnapshotList, out_snapshots) self._check_failover_db(objects.GroupList, out_groups)
def test_create_group_snapshot_with_bootable_volumes(self, mock_create_grpsnap): """Test group_snapshot can be created and deleted.""" group = tests_utils.create_group( self.context, availability_zone=CONF.storage_availability_zone, volume_type_ids=[fake.VOLUME_TYPE_ID], group_type_id=fake.GROUP_TYPE_ID, host=CONF.host) volume = tests_utils.create_volume( self.context, group_id=group.id, host=group.host, volume_type_id=fake.VOLUME_TYPE_ID) self.volume.create_volume(self.context, volume) # Create a bootable volume bootable_vol_params = {'status': 'creating', 'host': CONF.host, 'size': 1, 'bootable': True} bootable_vol = tests_utils.create_volume(self.context, group_id=group.id, **bootable_vol_params) # Create a common volume self.volume.create_volume(self.context, bootable_vol) volume_ids = [volume.id, bootable_vol.id] group_snapshot_returns = self._create_group_snapshot(group.id, volume_ids) group_snapshot = group_snapshot_returns[0] self.volume.create_group_snapshot(self.context, group_snapshot) self.assertEqual(group_snapshot.id, objects.GroupSnapshot.get_by_id( context.get_admin_context(), group_snapshot.id).id) self.assertTrue(mock_create_grpsnap.called)
def test_create_cgsnapshot_when_volume_in_error_status(self, mock_validate): consistencygroup = utils.create_consistencygroup(self.context) utils.create_volume( self.context, status='error', consistencygroup_id=consistencygroup.id ) body = {"cgsnapshot": {"name": "cg1", "description": "CG Snapshot 1", "consistencygroup_id": consistencygroup.id}} req = webob.Request.blank('/v2/%s/cgsnapshots' % fake.PROJECT_ID) req.method = 'POST' req.headers['Content-Type'] = 'application/json' req.body = jsonutils.dump_as_bytes(body) res = req.get_response(fakes.wsgi_app( fake_auth_context=self.user_ctxt)) res_dict = jsonutils.loads(res.body) self.assertEqual(400, res.status_int) self.assertEqual(400, res_dict['badRequest']['code']) self.assertEqual( "Invalid volume: The snapshot cannot be created when the volume " "is in error status.", res_dict['badRequest']['message'] ) self.assertTrue(mock_validate.called) consistencygroup.destroy()
def test_do_cleanup_not_cleaning_already_claimed(self): """Basic cleanup that doesn't touch already cleaning works.""" vol = utils.create_volume(self.context, status='creating') worker1 = db.worker_create(self.context, status='creating', resource_type='Volume', resource_id=vol.id, service_id=self.service.id) worker1 = db.worker_get(self.context, id=worker1.id) vol2 = utils.create_volume(self.context, status='deleting') worker2 = db.worker_create(self.context, status='deleting', resource_type='Volume', resource_id=vol2.id, service_id=self.service.id + 1) worker2 = db.worker_get(self.context, id=worker2.id) # Simulate that the change to vol2 worker happened between # worker_get_all and trying to claim a work for cleanup worker2.service_id = self.service.id clean_req = objects.CleanupRequest(service_id=self.service.id) mngr = FakeManager(self.service.id) with mock.patch('cinder.db.worker_get_all') as get_all_mock: get_all_mock.return_value = [worker1, worker2] mngr.do_cleanup(self.context, clean_req) workers = db.worker_get_all(self.context) self.assertEqual(1, len(workers)) self.assertEqual(worker2.id, workers[0].id) vol.refresh() self.assertEqual('creating_cleaned', vol.status) vol2.refresh() self.assertEqual('deleting', vol2.status)
def test_transfer_accept_invalid_volume(self, mock_notify): svc = self.start_service('volume', host='test_host') self.addCleanup(svc.stop) tx_api = transfer_api.API() utils.create_volume(self.ctxt, id='1', updated_at=self.updated_at) transfer = tx_api.create(self.ctxt, '1', 'Description') volume = db.volume_get(self.ctxt, '1') self.assertEqual('awaiting-transfer', volume['status'], 'Unexpected state') calls = [mock.call(self.ctxt, mock.ANY, "transfer.create.start"), mock.call(self.ctxt, mock.ANY, "transfer.create.end")] mock_notify.assert_has_calls(calls) self.assertEqual(2, mock_notify.call_count) db.volume_update(self.ctxt, '1', {'status': 'wrong'}) self.assertRaises(exception.InvalidVolume, tx_api.accept, self.ctxt, transfer['id'], transfer['auth_key']) db.volume_update(self.ctxt, '1', {'status': 'awaiting-transfer'}) # Because the InvalidVolume exception is raised in tx_api, so there is # only transfer.accept.start called and missing transfer.accept.end. calls = [mock.call(self.ctxt, mock.ANY, "transfer.accept.start")] mock_notify.assert_has_calls(calls) self.assertEqual(3, mock_notify.call_count)
def test_create_volume_from_snapshot_sparse(self): self.configuration.lvm_type = 'thin' lvm_driver = lvm.LVMVolumeDriver(configuration=self.configuration, db=db) with mock.patch.object(lvm_driver, 'vg'), \ mock.patch.object(lvm_driver, '_create_volume'), \ mock.patch.object(volutils, 'copy_volume') as mock_copy: # Test case for thin LVM lvm_driver._sparse_copy_volume = True src_volume = tests_utils.create_volume(self.context) snapshot_ref = tests_utils.create_snapshot(self.context, src_volume['id']) dst_volume = tests_utils.create_volume(self.context) lvm_driver.create_volume_from_snapshot(dst_volume, snapshot_ref) volume_path = lvm_driver.local_path(dst_volume) snapshot_path = lvm_driver.local_path(snapshot_ref) volume_size = 1024 block_size = '1M' mock_copy.assert_called_with(snapshot_path, volume_path, volume_size, block_size, execute=lvm_driver._execute, sparse=True)
def test_create_cgsnapshot_with_bootable_volumes(self, mock_create_cgsnap): """Test cgsnapshot can be created and deleted.""" group = tests_utils.create_consistencygroup( self.context, availability_zone=CONF.storage_availability_zone, volume_type='type1,type2') volume = tests_utils.create_volume( self.context, consistencygroup_id=group.id, **self.volume_params) self.volume.create_volume(self.context, volume) # Create a bootable volume bootable_vol_params = {'status': 'creating', 'host': CONF.host, 'size': 1, 'bootable': True} bootable_vol = tests_utils.create_volume(self.context, consistencygroup_id=group.id, **bootable_vol_params) # Create a common volume self.volume.create_volume(self.context, bootable_vol) volume_ids = [volume.id, bootable_vol.id] cgsnapshot_returns = self._create_cgsnapshot(group.id, volume_ids) cgsnapshot = cgsnapshot_returns[0] self.volume.create_cgsnapshot(self.context, cgsnapshot) self.assertEqual(cgsnapshot.id, objects.CGSnapshot.get_by_id( context.get_admin_context(), cgsnapshot.id).id) self.assertTrue(mock_create_cgsnap.called)
def test_create_cgsnapshot_json(self, mock_validate): cgsnapshot_id = "1" consistencygroup = utils.create_consistencygroup(self.context) utils.create_volume( self.context, consistencygroup_id=consistencygroup.id) body = {"cgsnapshot": {"name": "cg1", "description": "CG Snapshot 1", "consistencygroup_id": consistencygroup.id}} req = webob.Request.blank('/v2/fake/cgsnapshots') req.method = 'POST' req.headers['Content-Type'] = 'application/json' req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) res_dict = json.loads(res.body) self.assertEqual(202, res.status_int) self.assertIn('id', res_dict['cgsnapshot']) self.assertTrue(mock_validate.called) db.cgsnapshot_destroy(context.get_admin_context(), cgsnapshot_id) consistencygroup.destroy()
def test_create_cgsnapshot_json(self, mock_validate): consistencygroup = utils.create_consistencygroup(self.context) utils.create_volume( self.context, consistencygroup_id=consistencygroup.id) body = {"cgsnapshot": {"name": "cg1", "description": "CG Snapshot 1", "consistencygroup_id": consistencygroup.id}} req = webob.Request.blank('/v2/%s/cgsnapshots' % fake.PROJECT_ID) req.method = 'POST' req.headers['Content-Type'] = 'application/json' req.body = jsonutils.dump_as_bytes(body) res = req.get_response(fakes.wsgi_app( fake_auth_context=self.user_ctxt)) res_dict = jsonutils.loads(res.body) self.assertEqual(202, res.status_int) self.assertIn('id', res_dict['cgsnapshot']) self.assertTrue(mock_validate.called) consistencygroup.destroy() cgsnapshot = objects.CGSnapshot.get_by_id( context.get_admin_context(), res_dict['cgsnapshot']['id']) cgsnapshot.destroy()
def test_finish_volume_migration(self): ctxt = context.RequestContext(user_id='user_id', project_id='project_id', is_admin=True) src_volume = testutils.create_volume(ctxt, host='src', migration_status='migrating', status='available') dest_volume = testutils.create_volume(ctxt, host='dest', migration_status='target:fake', status='available') db.finish_volume_migration(ctxt, src_volume['id'], dest_volume['id']) # Check that we have copied destination volume DB data into source DB # entry so we can keep the id src_volume = objects.Volume.get_by_id(ctxt, src_volume['id']) self.assertEqual('dest', src_volume.host) self.assertEqual('available', src_volume.status) self.assertIsNone(src_volume.migration_status) # Check that we have copied source volume DB data into destination DB # entry and we are setting it to deleting dest_volume = objects.Volume.get_by_id(ctxt, dest_volume['id']) self.assertEqual('src', dest_volume.host) self.assertEqual('deleting', dest_volume.status) self.assertEqual('deleting', dest_volume.migration_status)
def test_init_host_sync_provider_info_no_update(self, mock_update): vol0 = tests_utils.create_volume( self.context, size=1, host=CONF.host) vol1 = tests_utils.create_volume( self.context, size=1, host=CONF.host) snap0 = tests_utils.create_snapshot(self.context, vol0.id) snap1 = tests_utils.create_snapshot(self.context, vol1.id) mock_update.return_value = ([], []) # initialize self.volume.init_host(service_id=self.service_id) # Grab volume and snapshot objects vol0_obj = objects.Volume.get_by_id(context.get_admin_context(), vol0.id) vol1_obj = objects.Volume.get_by_id(context.get_admin_context(), vol1.id) snap0_obj = objects.Snapshot.get_by_id(self.context, snap0.id) snap1_obj = objects.Snapshot.get_by_id(self.context, snap1.id) # Check provider ids are not changed self.assertIsNone(vol0_obj.provider_id) self.assertIsNone(vol1_obj.provider_id) self.assertIsNone(snap0_obj.provider_id) self.assertIsNone(snap1_obj.provider_id) # Clean up self.volume.delete_snapshot(self.context, snap0_obj) self.volume.delete_snapshot(self.context, snap1_obj) self.volume.delete_volume(self.context, vol0) self.volume.delete_volume(self.context, vol1)
def test_update(self, mock_policy, mock_volume_types_get, mock_group_type_get, mock_group, mock_update_quota, mock_cast_create_group, mock_volume_get_all, mock_rpc_update_group): vol_type_dict = {'id': fake.VOLUME_TYPE_ID, 'name': 'fake_volume_type'} vol_type = objects.VolumeType(self.ctxt, **vol_type_dict) mock_volume_types_get.return_value = [{'id': fake.VOLUME_TYPE_ID}] mock_group_type_get.return_value = {'id': fake.GROUP_TYPE_ID} name = "test_group" description = "this is a test group" grp = utils.create_group(self.ctxt, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[fake.VOLUME_TYPE_ID], availability_zone='nova', host=None, name=name, description=description, status=fields.GroupStatus.CREATING) mock_group.return_value = grp ret_group = self.group_api.create(self.ctxt, name, description, fake.GROUP_TYPE_ID, [fake.VOLUME_TYPE_ID], availability_zone='nova') self.assertEqual(grp.obj_to_primitive(), ret_group.obj_to_primitive()) ret_group.volume_types = [vol_type] ret_group.host = "test_host@fakedrv#fakepool" ret_group.status = fields.GroupStatus.AVAILABLE ret_group.id = fake.GROUP_ID vol1 = utils.create_volume( self.ctxt, host=ret_group.host, availability_zone=ret_group.availability_zone, volume_type_id=fake.VOLUME_TYPE_ID) vol2 = utils.create_volume( self.ctxt, host=ret_group.host, availability_zone=ret_group.availability_zone, volume_type_id=fake.VOLUME_TYPE_ID, group_id=fake.GROUP_ID) vol2_dict = { 'id': vol2.id, 'group_id': fake.GROUP_ID, 'volume_type_id': fake.VOLUME_TYPE_ID, 'availability_zone': ret_group.availability_zone, 'host': ret_group.host, 'status': 'available', } mock_volume_get_all.return_value = [vol2_dict] new_name = "new_group_name" new_desc = "this is a new group" self.group_api.update(self.ctxt, ret_group, new_name, new_desc, vol1.id, vol2.id) mock_volume_get_all.assert_called_once_with(mock.ANY, ret_group.id) mock_rpc_update_group.assert_called_once_with(self.ctxt, ret_group, add_volumes=vol1.id, remove_volumes=vol2.id) mock_policy.assert_called_with(self.ctxt, 'update', mock.ANY)
def test_create_group_from_group(self, mock_volume_get_all, mock_rpc_create_group_from_src, mock_group_get, mock_volume_api_create, mock_mapping_create, mock_get_volume_type): vol_type = fake_volume.fake_volume_type_obj( self.ctxt, id=fake.VOLUME_TYPE_ID, name='fake_volume_type') mock_get_volume_type.return_value = vol_type grp = utils.create_group(self.ctxt, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[vol_type['id']], availability_zone='nova', status=fields.GroupStatus.CREATING) mock_group_get.return_value = grp vol = utils.create_volume( self.ctxt, availability_zone=grp.availability_zone, volume_type_id=fake.VOLUME_TYPE_ID, group_id=grp.id) mock_volume_get_all.return_value = [vol] grp2 = utils.create_group(self.ctxt, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[vol_type['id']], availability_zone='nova', source_group_id=grp.id, status=fields.GroupStatus.CREATING) vol2 = utils.create_volume( self.ctxt, availability_zone=grp.availability_zone, volume_type_id=vol_type['id'], group_id=grp2.id, source_volid=vol.id) self.group_api._create_group_from_source_group(self.ctxt, grp2, grp.id) mock_volume_api_create.assert_called_once_with( self.ctxt, 1, None, None, availability_zone=grp.availability_zone, source_group=grp, group=grp2, source_volume=vol, volume_type=vol_type) mock_rpc_create_group_from_src.assert_called_once_with( self.ctxt, grp2, None, grp) vol2.destroy() grp2.destroy() vol.destroy() grp.destroy()
def test_transfer_accept(self, mock_notify): svc = self.start_service('volume', host='test_host') tx_api = transfer_api.API() utils.create_volume(self.ctxt, id='1', updated_at=self.updated_at) transfer = tx_api.create(self.ctxt, '1', 'Description') volume = db.volume_get(self.ctxt, '1') self.assertEqual('awaiting-transfer', volume['status'], 'Unexpected state') self.assertRaises(exception.TransferNotFound, tx_api.accept, self.ctxt, '2', transfer['auth_key']) self.assertRaises(exception.InvalidAuthKey, tx_api.accept, self.ctxt, transfer['id'], 'wrong') calls = [mock.call(self.ctxt, mock.ANY, "transfer.create.start"), mock.call(self.ctxt, mock.ANY, "transfer.create.end")] mock_notify.assert_has_calls(calls) self.assertEqual(2, mock_notify.call_count) db.volume_update(self.ctxt, '1', {'status': 'wrong'}) self.assertRaises(exception.InvalidVolume, tx_api.accept, self.ctxt, transfer['id'], transfer['auth_key']) db.volume_update(self.ctxt, '1', {'status': 'awaiting-transfer'}) # Because the InvalidVolume exception is raised in tx_api, so there is # only transfer.accept.start called and missing transfer.accept.end. calls = [mock.call(self.ctxt, mock.ANY, "transfer.accept.start")] mock_notify.assert_has_calls(calls) self.assertEqual(3, mock_notify.call_count) self.ctxt.user_id = 'new_user_id' self.ctxt.project_id = 'new_project_id' response = tx_api.accept(self.ctxt, transfer['id'], transfer['auth_key']) volume = db.volume_get(self.ctxt, '1') self.assertEqual(volume['project_id'], 'new_project_id', 'Unexpected project id') self.assertEqual(volume['user_id'], 'new_user_id', 'Unexpected user id') self.assertEqual(volume['id'], response['volume_id'], 'Unexpected volume id in response.') self.assertEqual(transfer['id'], response['id'], 'Unexpected transfer id in response.') calls = [mock.call(self.ctxt, mock.ANY, "transfer.accept.start"), mock.call(self.ctxt, mock.ANY, "transfer.accept.end")] mock_notify.assert_has_calls(calls) self.assertEqual(5, mock_notify.call_count) svc.stop()
def test_create_vol_with_group_id_driver_exception(self, mock_create_volume, mock_create_from_snap, mock_create_cloned_vol): """Test create a volume with group_id but driver exception.""" # create_raw_volume with group id, but driver exception mock_create_volume.side_effect = exception.CinderException group = tests_utils.create_group( self.context, availability_zone=CONF.storage_availability_zone, volume_type_ids=[fake.VOLUME_TYPE_ID], group_type_id=fake.GROUP_TYPE_ID, host=CONF.host) self.volume.create_group(self.context, group) volume = tests_utils.create_volume( self.context, group_id=group.id, volume_type_id=fake.VOLUME_TYPE_ID, status='available', host=group.host) self.assertRaises(exception.CinderException, self.volume.create_volume, self.context, volume) self.assertIsNone(volume.consistencygroup_id) # create volume from_snapshot with group id but driver exception mock_create_from_snap.side_effect = exception.CinderException snapshot = tests_utils.create_snapshot(self.context, volume.id) volume2 = tests_utils.create_volume( self.context, group_id=group.id, snapshot_id=snapshot.id, status='available', host=group.host, volume_type_id=fake.VOLUME_TYPE_ID) self.assertRaises(exception.CinderException, self.volume.create_volume, self.context, volume2) self.assertIsNone(volume2.consistencygroup_id) # create cloned volume with group_id but driver exception mock_create_cloned_vol.side_effect = exception.CinderException volume3 = tests_utils.create_volume( self.context, group_id=group.id, source_volid=volume.id, status='available', host=group.host, volume_type_id=fake.VOLUME_TYPE_ID) self.assertRaises(exception.CinderException, self.volume.create_volume, self.context, volume3) self.assertIsNone(volume3.consistencygroup_id)
def test_transfer_invalid_volume(self): tx_api = transfer_api.API() utils.create_volume(self.ctxt, id='1', status='in-use', updated_at=self.updated_at) self.assertRaises(exception.InvalidVolume, tx_api.create, self.ctxt, '1', 'Description') volume = db.volume_get(self.ctxt, '1') self.assertEqual('in-use', volume['status'], 'Unexpected state')
def test_show_host(self, mock_get_host): host = 'test_host' test_service = service.Service(id=1, host=host, binary=constants.VOLUME_BINARY, topic=constants.VOLUME_TOPIC) mock_get_host.return_value = test_service ctxt1 = context.RequestContext(project_id=fake_constants.PROJECT_ID, is_admin=True) ctxt2 = context.RequestContext(project_id=fake_constants.PROJECT2_ID, is_admin=True) # Create two volumes with different project. volume1 = test_utils.create_volume(ctxt1, host=host, size=1) test_utils.create_volume(ctxt2, host=host, size=1) # This volume is not on the same host. It should not be counted. test_utils.create_volume(ctxt2, host='fake_host', size=1) test_utils.create_snapshot(ctxt1, volume_id=volume1.id) resp = self.controller.show(self.req, host) host_resp = resp['host'] # There are 3 resource list: total, project1, project2 self.assertEqual(3, len(host_resp)) expected = [ { "resource": { "volume_count": "2", "total_volume_gb": "2", "host": "test_host", "total_snapshot_gb": "1", "project": "(total)", "snapshot_count": "1"} }, { "resource": { "volume_count": "1", "total_volume_gb": "1", "host": "test_host", "project": fake_constants.PROJECT2_ID, "total_snapshot_gb": "0", "snapshot_count": "0"} }, { "resource": { "volume_count": "1", "total_volume_gb": "1", "host": "test_host", "total_snapshot_gb": "1", "project": fake_constants.PROJECT_ID, "snapshot_count": "1"} } ] self.assertListEqual(expected, sorted( host_resp, key=lambda h: h['resource']['project']))
def test_same_filter_vol_list_pass(self): filt_cls = self.class_map["SameBackendFilter"]() host = fakes.FakeHostState("host1", {}) volume1 = utils.create_volume(self.context, host="host1") vol_id1 = volume1.id volume2 = utils.create_volume(self.context, host="host2") vol_id2 = volume2.id filter_properties = {"context": self.context.elevated(), "scheduler_hints": {"same_host": [vol_id1, vol_id2]}} self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_update_consistencygroup_success(self, mock_validate): volume_type_id = '123456' consistencygroup = self._create_consistencygroup( status=fields.ConsistencyGroupStatus.AVAILABLE, host='test_host') remove_volume_id = utils.create_volume( self.ctxt, volume_type_id=volume_type_id, consistencygroup_id=consistencygroup.id)['id'] remove_volume_id2 = utils.create_volume( self.ctxt, volume_type_id=volume_type_id, consistencygroup_id=consistencygroup.id)['id'] self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE, consistencygroup.status) cg_volumes = db.volume_get_all_by_group(self.ctxt.elevated(), consistencygroup.id) cg_vol_ids = [cg_vol['id'] for cg_vol in cg_volumes] self.assertIn(remove_volume_id, cg_vol_ids) self.assertIn(remove_volume_id2, cg_vol_ids) add_volume_id = utils.create_volume( self.ctxt, volume_type_id=volume_type_id)['id'] add_volume_id2 = utils.create_volume( self.ctxt, volume_type_id=volume_type_id)['id'] req = webob.Request.blank('/v2/fake/consistencygroups/%s/update' % consistencygroup.id) req.method = 'PUT' req.headers['Content-Type'] = 'application/json' name = 'newcg' description = 'New Consistency Group Description' add_volumes = add_volume_id + "," + add_volume_id2 remove_volumes = remove_volume_id + "," + remove_volume_id2 body = {"consistencygroup": {"name": name, "description": description, "add_volumes": add_volumes, "remove_volumes": remove_volumes, }} req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) consistencygroup = objects.ConsistencyGroup.get_by_id( self.ctxt, consistencygroup.id) self.assertEqual(202, res.status_int) self.assertTrue(mock_validate.called) self.assertEqual(fields.ConsistencyGroupStatus.UPDATING, consistencygroup.status) consistencygroup.destroy()
def test_transfer_volume_create_delete(self): tx_api = transfer_api.API() utils.create_volume(self.ctxt, id='1', updated_at=self.updated_at) response = tx_api.create(self.ctxt, '1', 'Description') volume = db.volume_get(self.ctxt, '1') self.assertEqual('awaiting-transfer', volume['status'], 'Unexpected state') tx_api.delete(self.ctxt, response['id']) volume = db.volume_get(self.ctxt, '1') self.assertEqual('available', volume['status'], 'Unexpected state')
def test_different_filter_handles_multiple_uuids(self): filt_cls = self.class_map['DifferentBackendFilter']() host = fakes.FakeHostState('host1#pool0', {}) volume1 = utils.create_volume(self.context, host='host1:pool1') vol_id1 = volume1.id volume2 = utils.create_volume(self.context, host='host1:pool3') vol_id2 = volume2.id filter_properties = {'context': self.context.elevated(), 'scheduler_hints': { 'different_host': [vol_id1, vol_id2], }} self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_volume_summary_return_metadata_all_tenant( self, summary_api_version, expect_result): test_utils.create_volume(self.ctxt, metadata={'name': 'test_name1', 'age': 'test_age'}) ctxt2 = context.RequestContext(fake.USER_ID, fake.PROJECT2_ID, True) test_utils.create_volume(ctxt2, metadata={'name': 'test_name2', 'age': 'test_age'}) req = self._fake_volumes_summary_request(version=summary_api_version, all_tenant=True, is_admin=True) res_dict = self.controller.summary(req) self.assertEqual(expect_result, res_dict)
def test_same_filter_vol_list_pass(self): filt_cls = self.class_map['SameBackendFilter']() host = fakes.FakeHostState('host1', {}) volume1 = utils.create_volume(self.context, host='host1') vol_id1 = volume1.id volume2 = utils.create_volume(self.context, host='host2') vol_id2 = volume2.id filter_properties = {'context': self.context.elevated(), 'scheduler_hints': { 'same_host': [vol_id1, vol_id2], }} self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_update_consistencygroup_success(self): volume_type_id = '123456' ctxt = context.RequestContext('fake', 'fake') consistencygroup_id = self._create_consistencygroup(status='available', host='test_host') remove_volume_id = utils.create_volume( ctxt, volume_type_id=volume_type_id, consistencygroup_id=consistencygroup_id)['id'] remove_volume_id2 = utils.create_volume( ctxt, volume_type_id=volume_type_id, consistencygroup_id=consistencygroup_id)['id'] self.assertEqual('available', self._get_consistencygroup_attrib(consistencygroup_id, 'status')) cg_volumes = db.volume_get_all_by_group(ctxt.elevated(), consistencygroup_id) cg_vol_ids = [cg_vol['id'] for cg_vol in cg_volumes] self.assertIn(remove_volume_id, cg_vol_ids) self.assertIn(remove_volume_id2, cg_vol_ids) add_volume_id = utils.create_volume( ctxt, volume_type_id=volume_type_id)['id'] add_volume_id2 = utils.create_volume( ctxt, volume_type_id=volume_type_id)['id'] req = webob.Request.blank('/v2/fake/consistencygroups/%s/update' % consistencygroup_id) req.method = 'PUT' req.headers['Content-Type'] = 'application/json' name = 'newcg' description = 'New Consistency Group Description' add_volumes = add_volume_id + "," + add_volume_id2 remove_volumes = remove_volume_id + "," + remove_volume_id2 body = {"consistencygroup": {"name": name, "description": description, "add_volumes": add_volumes, "remove_volumes": remove_volumes, }} req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) self.assertEqual(202, res.status_int) self.assertEqual('updating', self._get_consistencygroup_attrib(consistencygroup_id, 'status')) db.consistencygroup_destroy(ctxt.elevated(), consistencygroup_id)
def _create_multiple_snapshots_with_different_project(self): volume1 = test_utils.create_volume(self.ctx, project=fake.PROJECT_ID) volume2 = test_utils.create_volume(self.ctx, project=fake.PROJECT2_ID) test_utils.create_snapshot( context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True), volume1.id) test_utils.create_snapshot( context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True), volume1.id) test_utils.create_snapshot( context.RequestContext(fake.USER_ID, fake.PROJECT2_ID, True), volume2.id)
def test_different_filter_handles_multiple_uuids(self): filt_cls = self.class_map["DifferentBackendFilter"]() host = fakes.FakeHostState("host1#pool0", {}) volume1 = utils.create_volume(self.context, host="host1:pool1") vol_id1 = volume1.id volume2 = utils.create_volume(self.context, host="host1:pool3") vol_id2 = volume2.id filter_properties = { "context": self.context.elevated(), "scheduler_hints": {"different_host": [vol_id1, vol_id2]}, } self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_create_snapshot_force(self): """Test snapshot in use can be created forcibly.""" instance_uuid = '12345678-1234-5678-1234-567812345678' # create volume and attach to the instance volume = tests_utils.create_volume(self.context, **self.volume_params) self.volume.create_volume(self.context, volume) values = {'volume_id': volume['id'], 'instance_uuid': instance_uuid, 'attach_status': fields.VolumeAttachStatus.ATTACHING, } attachment = db.volume_attach(self.context, values) db.volume_attached(self.context, attachment['id'], instance_uuid, None, '/dev/sda1') volume_api = cinder.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') snapshot_ref.destroy() db.volume_destroy(self.context, volume['id']) # create volume and attach to the host volume = tests_utils.create_volume(self.context, **self.volume_params) self.volume.create_volume(self.context, volume) values = {'volume_id': volume['id'], 'attached_host': 'fake_host', 'attach_status': fields.VolumeAttachStatus.ATTACHING, } attachment = db.volume_attach(self.context, values) db.volume_attached(self.context, attachment['id'], None, 'fake_host', '/dev/sda1') volume_api = cinder.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') snapshot_ref.destroy() db.volume_destroy(self.context, volume['id'])
def test_create_group_from_group_create_volume_failed( self, mock_volume_get_all, mock_rpc_create_group_from_src, mock_group_get, mock_volume_api_create, mock_mapping_create, mock_get_volume_type, mock_volume_delete): vol_type = fake_volume.fake_volume_type_obj( self.ctxt, id=fake.VOLUME_TYPE_ID, name='fake_volume_type') mock_get_volume_type.return_value = vol_type grp = utils.create_group(self.ctxt, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[vol_type['id']], availability_zone='nova', status=fields.GroupStatus.CREATING) mock_group_get.return_value = grp vol1 = utils.create_volume( self.ctxt, availability_zone=grp.availability_zone, volume_type_id=fake.VOLUME_TYPE_ID, group_id=grp.id) vol2 = utils.create_volume( self.ctxt, availability_zone=grp.availability_zone, volume_type_id=fake.VOLUME_TYPE_ID, group_id=grp.id) mock_volume_get_all.side_effect = [[vol1, vol2], [vol1]] grp2 = utils.create_group(self.ctxt, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[vol_type['id']], availability_zone='nova', source_group_id=grp.id, status=fields.GroupStatus.CREATING) mock_volume_api_create.side_effect = [None, exception.CinderException] self.assertRaises( exception.CinderException, self.group_api._create_group_from_source_group, self.ctxt, grp2, grp.id) mock_rpc_create_group_from_src.assert_not_called() mock_volume_delete.assert_called_once_with(self.ctxt, vol1) grp2.destroy() vol2.destroy() vol1.destroy() grp.destroy()
def test_update_migrated_volume(self, volume_update): fake_host = 'fake_host' fake_new_host = 'fake_new_host' fake_update = {'_name_id': fake.VOLUME2_NAME_ID, 'provider_location': 'updated_location'} fake_elevated = context.RequestContext(fake.USER_ID, self.project_id, is_admin=True) volume = tests_utils.create_volume(self.context, size=1, status='available', host=fake_host) new_volume = tests_utils.create_volume( self.context, size=1, status='available', provider_location='fake_provider_location', _name_id=fake.VOLUME_NAME_ID, host=fake_new_host) new_volume._name_id = fake.VOLUME_NAME_ID new_volume.provider_location = 'fake_provider_location' fake_update_error = {'_name_id': new_volume._name_id, 'provider_location': new_volume.provider_location} expected_update = {'_name_id': volume._name_id, 'provider_location': volume.provider_location} with mock.patch.object(self.volume.driver, 'update_migrated_volume') as migrate_update,\ mock.patch.object(self.context, 'elevated') as elevated: migrate_update.return_value = fake_update elevated.return_value = fake_elevated self.volume.update_migrated_volume(self.context, volume, new_volume, 'available') volume_update.assert_has_calls(( mock.call(fake_elevated, new_volume.id, expected_update), mock.call(fake_elevated, volume.id, fake_update))) # Test the case for update_migrated_volume not implemented # for the driver. migrate_update.reset_mock() volume_update.reset_mock() # Reset the volume objects to their original value, since they # were changed in the last call. new_volume._name_id = fake.VOLUME_NAME_ID new_volume.provider_location = 'fake_provider_location' migrate_update.side_effect = NotImplementedError self.volume.update_migrated_volume(self.context, volume, new_volume, 'available') volume_update.assert_has_calls(( mock.call(fake_elevated, new_volume.id, fake_update), mock.call(fake_elevated, volume.id, fake_update_error)))
def test_create_consistencygroup_from_src_cgsnapshot_empty(self): ctxt = context.RequestContext('fake', 'fake', auth_token=True) consistencygroup_id = utils.create_consistencygroup( ctxt)['id'] volume_id = utils.create_volume( ctxt, consistencygroup_id=consistencygroup_id)['id'] cgsnapshot_id = utils.create_cgsnapshot( ctxt, consistencygroup_id=consistencygroup_id)['id'] test_cg_name = 'test cg' body = {"consistencygroup-from-src": {"name": test_cg_name, "description": "Consistency Group 1", "cgsnapshot_id": cgsnapshot_id}} req = webob.Request.blank('/v2/fake/consistencygroups/create_from_src') req.method = 'POST' req.headers['Content-Type'] = 'application/json' req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) res_dict = json.loads(res.body) self.assertEqual(400, res.status_int) self.assertEqual(400, res_dict['badRequest']['code']) msg = _("Invalid ConsistencyGroup: Cgsnahost is empty. No " "consistency group will be created.") self.assertIn(msg, res_dict['badRequest']['message']) db.cgsnapshot_destroy(ctxt.elevated(), cgsnapshot_id) db.volume_destroy(ctxt.elevated(), volume_id) db.consistencygroup_destroy(ctxt.elevated(), consistencygroup_id)
def _test_migrate_volume_exception_returns_volume_state( self, _mock_volume_update, _mock_backend_passes, _mock_volume_get, status, fake_updates): volume = tests_utils.create_volume(self.context, status=status, previous_status='available') fake_volume_id = volume.id request_spec = {'volume_id': fake_volume_id} _mock_backend_passes.side_effect = exception.NoValidBackend(reason="") _mock_volume_get.return_value = volume self.manager.migrate_volume_to_host(self.context, volume, 'host', True, request_spec=request_spec, filter_properties={}) _mock_volume_update.assert_called_once_with(self.context, fake_volume_id, fake_updates) _mock_backend_passes.assert_called_once_with(self.context, 'host', request_spec, {})
def test_migrate_volume_error(self): with mock.patch.object(self.volume.driver, 'migrate_volume') as \ mock_migrate,\ mock.patch.object(self.volume.driver, 'create_export') as \ mock_create_export: # Exception case at self.driver.migrate_volume and create_export mock_migrate.side_effect = processutils.ProcessExecutionError mock_create_export.side_effect = processutils.ProcessExecutionError volume = tests_utils.create_volume(self.context, size=0, host=CONF.host) host_obj = {'host': 'newhost', 'capabilities': {}} self.assertRaises(processutils.ProcessExecutionError, self.volume.migrate_volume, self.context, volume, host_obj, False) volume = objects.Volume.get_by_id(context.get_admin_context(), volume.id) self.assertEqual('error', volume.migration_status) self.assertEqual('available', volume.status)
def test_migrate_volume_generic(self, volume_get, migrate_volume_completion, nova_api): fake_db_new_volume = {'status': 'available', 'id': fake.VOLUME_ID} fake_new_volume = fake_volume.fake_db_volume(**fake_db_new_volume) new_volume_obj = fake_volume.fake_volume_obj(self.context, **fake_new_volume) host_obj = {'host': 'newhost', 'capabilities': {}} volume_get.return_value = fake_new_volume update_server_volume = nova_api.return_value.update_server_volume volume = tests_utils.create_volume(self.context, size=1, host=CONF.host) with mock.patch.object(self.volume, '_copy_volume_data') as \ mock_copy_volume: self.volume._migrate_volume_generic(self.context, volume, host_obj, None) mock_copy_volume.assert_called_with(self.context, volume, new_volume_obj, remote='dest') migrate_volume_completion.assert_called_with( self.context, volume, new_volume_obj, error=False) self.assertFalse(update_server_volume.called)
def test_retype_setup_fail_volume_is_available(self, mock_notify): """Verify volume is still available if retype prepare failed.""" elevated = context.get_admin_context() project_id = self.context.project_id db.volume_type_create(elevated, {'name': 'old', 'extra_specs': {}}) old_vol_type = db.volume_type_get_by_name(elevated, 'old') db.volume_type_create(elevated, {'name': 'new', 'extra_specs': {}}) new_vol_type = db.volume_type_get_by_name(elevated, 'new') db.quota_create(elevated, project_id, 'volumes_new', 0) volume = tests_utils.create_volume(self.context, size=1, host=CONF.host, status='available', volume_type_id=old_vol_type['id']) api = cinder.volume.api.API() self.assertRaises(exception.VolumeLimitExceeded, api.retype, self.context, volume, new_vol_type['id']) volume = db.volume_get(elevated, volume.id) mock_notify.assert_not_called() self.assertEqual('available', volume['status'])
def test_delete_group_snapshot_with_Invalid_group_snapshot(self): group = utils.create_group( self.context, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[fake.VOLUME_TYPE_ID], ) volume_id = utils.create_volume( self.context, group_id=group.id, volume_type_id=fake.VOLUME_TYPE_ID)['id'] group_snapshot = utils.create_group_snapshot(self.context, group_id=group.id, status='invalid') req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, group_snapshot.id), version=GROUP_MICRO_VERSION) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete, req, group_snapshot.id) group_snapshot.destroy() db.volume_destroy(context.get_admin_context(), volume_id) group.destroy()
def test_retype_volume_exception_returns_volume_state( self, _mock_vol_get, _mock_vol_update): # Test NoValidHost exception behavior for retype. # Puts the volume in original state and eats the exception. volume = tests_utils.create_volume(self.context, status='retyping', previous_status='in-use') instance_uuid = '12345678-1234-5678-1234-567812345678' volume = tests_utils.attach_volume(self.context, volume['id'], instance_uuid, None, '/dev/fake') fake_volume_id = volume.id topic = 'fake_topic' request_spec = { 'volume_id': fake_volume_id, 'volume_type': { 'id': 3 }, 'migration_policy': 'on-demand' } _mock_vol_get.return_value = volume _mock_vol_update.return_value = {'status': 'in-use'} _mock_find_retype_host = mock.Mock(side_effect=exception.NoValidHost( reason="")) orig_retype = self.manager.driver.find_retype_host self.manager.driver.find_retype_host = _mock_find_retype_host self.manager.retype(self.context, topic, fake_volume_id, request_spec=request_spec, filter_properties={}) _mock_vol_get.assert_called_once_with(self.context, fake_volume_id) _mock_find_retype_host.assert_called_once_with(self.context, request_spec, {}, 'on-demand') _mock_vol_update.assert_called_once_with(self.context, fake_volume_id, {'status': 'in-use'}) self.manager.driver.find_retype_host = orig_retype
def test_create_snapshot_in_db_invalid_metadata(self, mock_get): test_volume = tests_utils.create_volume(self.context, status='available', host=CONF.host) mock_get.return_value = test_volume volume_api = cinder.volume.api.API() with mock.patch.object(QUOTAS, 'add_volume_type_opts'),\ mock.patch.object(QUOTAS, 'reserve') as mock_reserve,\ mock.patch.object(QUOTAS, 'commit') as mock_commit: self.assertRaises(exception.InvalidInput, volume_api.create_snapshot_in_db, self.context, test_volume, "fake_snapshot_name", "fake_description", False, "fake_metadata", None, commit_quota=True) mock_reserve.assert_not_called() mock_commit.assert_not_called()
def test_update_group_exception_leave(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': '<is> True'}) self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG) self.DPL_MOCK.leave_vg.return_value = -1, None volume = test_utils.create_volume( self.context, id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee', display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], host=DATA_IN_VOLUME_VG['host']) group = test_utils.create_group(self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) self.assertRaises(exception.VolumeBackendAPIException, self.dpldriver.update_group, context=None, group=group, add_volumes=None, remove_volumes=[volume])
def test_snapshot_create(self, mock_validate): volume = utils.create_volume(self.ctx) snapshot_name = 'Snapshot Test Name' snapshot_description = 'Snapshot Test Desc' snapshot = { "volume_id": volume.id, "force": False, "name": snapshot_name, "description": snapshot_description } body = dict(snapshot=snapshot) req = fakes.HTTPRequest.blank('/v2/snapshots') resp_dict = self.controller.create(req, body) self.assertIn('snapshot', resp_dict) self.assertEqual(snapshot_name, resp_dict['snapshot']['name']) self.assertEqual(snapshot_description, resp_dict['snapshot']['description']) self.assertTrue(mock_validate.called) self.assertIn('updated_at', resp_dict['snapshot']) db.volume_destroy(self.ctx, volume.id)
def test_show_cgsnapshot(self): consistencygroup = utils.create_consistencygroup(self.context) volume_id = utils.create_volume( self.context, consistencygroup_id=consistencygroup.id)['id'] cgsnapshot = utils.create_cgsnapshot( self.context, consistencygroup_id=consistencygroup.id) req = webob.Request.blank('/v2/fake/cgsnapshots/%s' % cgsnapshot.id) req.method = 'GET' req.headers['Content-Type'] = 'application/json' res = req.get_response(fakes.wsgi_app()) res_dict = jsonutils.loads(res.body) self.assertEqual(200, res.status_int) self.assertEqual('this is a test cgsnapshot', res_dict['cgsnapshot']['description']) self.assertEqual('test_cgsnapshot', res_dict['cgsnapshot']['name']) self.assertEqual('creating', res_dict['cgsnapshot']['status']) cgsnapshot.destroy() db.volume_destroy(context.get_admin_context(), volume_id) consistencygroup.destroy()
def test_transfer_accept_with_snapshots(self, mock_notify): svc = self.start_service('volume', host='test_host') self.addCleanup(svc.stop) tx_api = transfer_api.API() volume = utils.create_volume(self.ctxt, volume_type_id=fake.VOLUME_TYPE_ID, updated_at=self.updated_at) utils.create_volume_type(self.ctxt.elevated(), id=fake.VOLUME_TYPE_ID, name="test_type") utils.create_snapshot(self.ctxt, volume.id, status='available') transfer = tx_api.create(self.ctxt, volume.id, 'Description') # Get volume and snapshot quota before accept self.ctxt.user_id = fake.USER2_ID self.ctxt.project_id = fake.PROJECT2_ID usages = db.quota_usage_get_all_by_project(self.ctxt, self.ctxt.project_id) self.assertEqual(0, usages.get('volumes', {}).get('in_use', 0)) self.assertEqual(0, usages.get('snapshots', {}).get('in_use', 0)) tx_api.accept(self.ctxt, transfer['id'], transfer['auth_key']) volume = objects.Volume.get_by_id(self.ctxt, volume.id) self.assertEqual(fake.PROJECT2_ID, volume.project_id) self.assertEqual(fake.USER2_ID, volume.user_id) calls = [mock.call(self.ctxt, mock.ANY, "transfer.accept.start"), mock.call(self.ctxt, mock.ANY, "transfer.accept.end")] mock_notify.assert_has_calls(calls) # The notify_about_volume_usage is called twice at create(), # and twice at accept(). self.assertEqual(4, mock_notify.call_count) # Get volume and snapshot quota after accept self.ctxt.user_id = fake.USER2_ID self.ctxt.project_id = fake.PROJECT2_ID usages = db.quota_usage_get_all_by_project(self.ctxt, self.ctxt.project_id) self.assertEqual(1, usages.get('volumes', {}).get('in_use', 0)) self.assertEqual(1, usages.get('snapshots', {}).get('in_use', 0))
def test_delete_cgsnapshot_with_Invalidcgsnapshot(self): consistencygroup = utils.create_consistencygroup(self.context) volume_id = utils.create_volume( self.context, consistencygroup_id=consistencygroup.id)['id'] cgsnapshot = utils.create_cgsnapshot( self.context, consistencygroup_id=consistencygroup.id, status='invalid') req = webob.Request.blank('/v2/fake/cgsnapshots/%s' % cgsnapshot.id) req.method = 'DELETE' req.headers['Content-Type'] = 'application/json' res = req.get_response(fakes.wsgi_app()) res_dict = jsonutils.loads(res.body) self.assertEqual(400, res.status_int) self.assertEqual(400, res_dict['badRequest']['code']) self.assertEqual('Invalid cgsnapshot', res_dict['badRequest']['message']) cgsnapshot.destroy() db.volume_destroy(context.get_admin_context(), volume_id) consistencygroup.destroy()
def test_retype_volume_exception_returns_volume_state( self, quota_rollback, _mock_vol_attachment_get, _mock_vol_update): # Test NoValidBackend exception behavior for retype. # Puts the volume in original state and eats the exception. volume = tests_utils.create_volume(self.context, status='retyping', previous_status='in-use') instance_uuid = '12345678-1234-5678-1234-567812345678' volume_attach = tests_utils.attach_volume(self.context, volume.id, instance_uuid, None, '/dev/fake') _mock_vol_attachment_get.return_value = [volume_attach] reservations = mock.sentinel.reservations request_spec = { 'volume_id': volume.id, 'volume_type': { 'id': 3 }, 'migration_policy': 'on-demand', 'quota_reservations': reservations } _mock_vol_update.return_value = {'status': 'in-use'} _mock_find_retype_backend = mock.Mock( side_effect=exception.NoValidBackend(reason="")) orig_retype = self.manager.driver.find_retype_backend self.manager.driver.find_retype_backend = _mock_find_retype_backend self.manager.retype(self.context, volume, request_spec=request_spec, filter_properties={}) _mock_find_retype_backend.assert_called_once_with( self.context, request_spec, {}, 'on-demand') quota_rollback.assert_called_once_with(self.context, reservations) _mock_vol_update.assert_called_once_with(self.context, volume.id, {'status': 'in-use'}) self.manager.driver.find_retype_host = orig_retype
def test_backup_volume_inuse(self, mock_volume_get, mock_get_connector_properties, mock_file_open, mock_temporary_chown): vol = tests_utils.create_volume(self.context, status='backing-up', previous_status='in-use') self.context.user_id = fake.USER_ID self.context.project_id = fake.PROJECT_ID mock_volume_get.return_value = vol temp_snapshot = tests_utils.create_snapshot(self.context, vol['id']) backup_obj = tests_utils.create_backup(self.context, vol['id']) properties = {} attach_info = {'device': {'path': '/dev/null'}} backup_service = mock.Mock() self.volume.driver._detach_volume = mock.MagicMock() self.volume.driver._attach_volume = mock.MagicMock() self.volume.driver.terminate_connection = mock.MagicMock() self.volume.driver._create_temp_snapshot = mock.MagicMock() self.volume.driver._delete_temp_snapshot = mock.MagicMock() mock_get_connector_properties.return_value = properties f = mock_file_open.return_value = open('/dev/null', 'rb') backup_service.backup(backup_obj, f, None) self.volume.driver._attach_volume.return_value = attach_info self.volume.driver._create_temp_snapshot.return_value = temp_snapshot self.volume.driver.backup_volume(self.context, backup_obj, backup_service) mock_volume_get.assert_called_with(self.context, vol['id']) self.volume.driver._create_temp_snapshot.assert_called_once_with( self.context, vol) self.volume.driver._delete_temp_snapshot.assert_called_once_with( self.context, temp_snapshot)
def test_transfer_accept_over_quota(self, mock_quota_voltype, mock_quota_reserve): svc = self.start_service('volume', host='test_host') self.addCleanup(svc.stop) tx_api = transfer_api.API() volume = utils.create_volume(self.ctxt, volume_type_id=fake.VOLUME_TYPE_ID, updated_at=self.updated_at) with mock.patch('cinder.volume.volume_utils.notify_about_volume_usage' ) as mock_notify: transfer = tx_api.create(self.ctxt, volume.id, 'Description') self.assertEqual(2, mock_notify.call_count) fake_overs = ['volumes_lvmdriver-3'] fake_quotas = {'gigabytes_lvmdriver-3': 1, 'volumes_lvmdriver-3': 10} fake_usages = { 'gigabytes_lvmdriver-3': { 'reserved': 0, 'in_use': 1 }, 'volumes_lvmdriver-3': { 'reserved': 0, 'in_use': 1 } } mock_quota_reserve.side_effect = exception.OverQuota( overs=fake_overs, quotas=fake_quotas, usages=fake_usages) self.ctxt.user_id = fake.USER2_ID self.ctxt.project_id = fake.PROJECT2_ID with mock.patch('cinder.volume.volume_utils.notify_about_volume_usage' ) as mock_notify: self.assertRaises(exception.VolumeLimitExceeded, tx_api.accept, self.ctxt, transfer['id'], transfer['auth_key']) # notification of transfer.accept is sent only after quota check # passes self.assertEqual(0, mock_notify.call_count)
def test_list_cgsnapshots_xml(self): consistencygroup = utils.create_consistencygroup(self.context) volume_id = utils.create_volume(self.context, consistencygroup_id= consistencygroup.id)['id'] cgsnapshot_id1 = self._create_cgsnapshot(consistencygroup_id= consistencygroup.id) cgsnapshot_id2 = self._create_cgsnapshot(consistencygroup_id= consistencygroup.id) cgsnapshot_id3 = self._create_cgsnapshot(consistencygroup_id= consistencygroup.id) req = webob.Request.blank('/v2/fake/cgsnapshots') req.method = 'GET' req.headers['Content-Type'] = 'application/xml' req.headers['Accept'] = 'application/xml' res = req.get_response(fakes.wsgi_app()) self.assertEqual(200, res.status_int) dom = minidom.parseString(res.body) cgsnapshot_list = dom.getElementsByTagName('cgsnapshot') self.assertEqual(cgsnapshot_id1, cgsnapshot_list.item(0).getAttribute('id')) self.assertEqual(cgsnapshot_id2, cgsnapshot_list.item(1).getAttribute('id')) self.assertEqual(cgsnapshot_id3, cgsnapshot_list.item(2).getAttribute('id')) db.cgsnapshot_destroy(context.get_admin_context(), cgsnapshot_id3) db.cgsnapshot_destroy(context.get_admin_context(), cgsnapshot_id2) db.cgsnapshot_destroy(context.get_admin_context(), cgsnapshot_id1) db.volume_destroy(context.get_admin_context(), volume_id) consistencygroup.destroy()
def test_copy_image_to_encrypted_volume_failed_fetch( self, excep, mock_detach_encryptor, mock_attach_encryptor, mock_detach_volume, mock_attach_volume, mock_fetch_to_raw, mock_get_connector_properties): properties = {} volume = tests_utils.create_volume( self.context, status='available', size=2, encryption_key_id=fake.ENCRYPTION_KEY_ID) volume_id = volume['id'] volume = db.volume_get(context.get_admin_context(), volume_id) image_service = fake_image.FakeImageService() local_path = 'dev/sda' attach_info = {'device': {'path': local_path}, 'conn': {'driver_volume_type': 'iscsi', 'data': {}, }} mock_get_connector_properties.return_value = properties mock_attach_volume.return_value = [attach_info, volume] mock_fetch_to_raw.side_effect = excep encryption = {'encryption_key_id': fake.ENCRYPTION_KEY_ID} self.assertRaises(type(excep), self.volume.driver.copy_image_to_encrypted_volume, self.context, volume, image_service, fake.IMAGE_ID) mock_attach_volume.assert_called_once_with( self.context, volume, properties) mock_attach_encryptor.assert_called_once_with( self.context, attach_info, encryption) mock_fetch_to_raw.assert_called_once_with( self.context, image_service, fake.IMAGE_ID, local_path, '1M', size=2) mock_detach_encryptor.assert_called_once_with( attach_info, encryption) mock_detach_volume.assert_called_once_with( self.context, attach_info, volume, properties, force=True)
def test_create_consistencygroup_from_src_no_host(self): ctxt = context.RequestContext('fake', 'fake', auth_token=True) consistencygroup_id = utils.create_consistencygroup(ctxt, host=None)['id'] volume_id = utils.create_volume( ctxt, consistencygroup_id=consistencygroup_id)['id'] cgsnapshot_id = utils.create_cgsnapshot( ctxt, consistencygroup_id=consistencygroup_id)['id'] snapshot_id = utils.create_snapshot(ctxt, volume_id, cgsnapshot_id=cgsnapshot_id, status='available')['id'] test_cg_name = 'test cg' body = { "consistencygroup-from-src": { "name": test_cg_name, "description": "Consistency Group 1", "cgsnapshot_id": cgsnapshot_id } } req = webob.Request.blank('/v2/fake/consistencygroups/create_from_src') req.method = 'POST' req.headers['Content-Type'] = 'application/json' req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) res_dict = json.loads(res.body) self.assertEqual(400, res.status_int) self.assertEqual(400, res_dict['badRequest']['code']) msg = _('Invalid ConsistencyGroup: No host to create consistency ' 'group') self.assertIn(msg, res_dict['badRequest']['message']) db.snapshot_destroy(ctxt.elevated(), snapshot_id) db.cgsnapshot_destroy(ctxt.elevated(), cgsnapshot_id) db.volume_destroy(ctxt.elevated(), volume_id) db.consistencygroup_destroy(ctxt.elevated(), consistencygroup_id)
def test_create_cgsnapshot_when_volume_in_error_status( self, mock_validate): vol_type = utils.create_volume_type(context.get_admin_context(), self, name='my_vol_type') consistencygroup = utils.create_group(self.context, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[vol_type['id']]) volume_id = utils.create_volume(self.context, volume_type_id=vol_type['id'], group_id=consistencygroup.id, status='error')['id'] body = { "cgsnapshot": { "name": "cg1", "description": "CG Snapshot 1", "consistencygroup_id": consistencygroup.id } } req = webob.Request.blank('/v2/%s/cgsnapshots' % fake.PROJECT_ID) req.method = 'POST' req.headers['Content-Type'] = 'application/json' req.body = jsonutils.dump_as_bytes(body) res = req.get_response( fakes.wsgi_app(fake_auth_context=self.user_ctxt)) res_dict = jsonutils.loads(res.body) self.assertEqual(http_client.BAD_REQUEST, res.status_int) self.assertEqual(http_client.BAD_REQUEST, res_dict['badRequest']['code']) self.assertEqual( "Invalid volume: The snapshot cannot be created when the volume " "is in error status.", res_dict['badRequest']['message']) self.assertTrue(mock_validate.called) db.volume_destroy(context.get_admin_context(), volume_id) consistencygroup.destroy()
def test_attachment_create_update_and_delete(self, mock_rpc_attachment_update, mock_rpc_attachment_delete, mock_policy): """Test attachment_delete.""" volume_params = {'status': 'available'} connection_info = { 'fake_key': 'fake_value', 'fake_key2': ['fake_value1', 'fake_value2'] } mock_rpc_attachment_update.return_value = connection_info vref = tests_utils.create_volume(self.context, **volume_params) aref = self.volume_api.attachment_create(self.context, vref, fake.UUID2) aref = objects.VolumeAttachment.get_by_id(self.context, aref.id) vref = objects.Volume.get_by_id(self.context, vref.id) connector = {'fake': 'connector'} self.volume_api.attachment_update(self.context, aref, connector) aref = objects.VolumeAttachment.get_by_id(self.context, aref.id) self.assertEqual(connection_info, aref.connection_info) # We mock the actual call that updates the status # so force it here values = { 'volume_id': vref.id, 'volume_host': vref.host, 'attach_status': 'attached', 'instance_uuid': fake.UUID2 } aref = db.volume_attach(self.context, values) aref = objects.VolumeAttachment.get_by_id(self.context, aref.id) self.assertEqual(vref.id, aref.volume_id) self.volume_api.attachment_delete(self.context, aref) mock_rpc_attachment_delete.assert_called_once_with( self.context, aref.id, mock.ANY)
def test_transfer_volume_create_delete(self, mock_notify): tx_api = transfer_api.API() volume = utils.create_volume(self.ctxt, updated_at=self.updated_at) response = tx_api.create(self.ctxt, volume.id, 'Description') volume = objects.Volume.get_by_id(self.ctxt, volume.id) self.assertEqual('awaiting-transfer', volume['status'], 'Unexpected state') calls = [ mock.call(self.ctxt, mock.ANY, "transfer.create.start"), mock.call(self.ctxt, mock.ANY, "transfer.create.end") ] mock_notify.assert_has_calls(calls) self.assertEqual(2, mock_notify.call_count) tx_api.delete(self.ctxt, response['id']) volume = objects.Volume.get_by_id(self.ctxt, volume.id) self.assertEqual('available', volume['status'], 'Unexpected state') calls = [ mock.call(self.ctxt, mock.ANY, "transfer.delete.start"), mock.call(self.ctxt, mock.ANY, "transfer.delete.end") ] mock_notify.assert_has_calls(calls) self.assertEqual(4, mock_notify.call_count)
def setUp(self): super(GroupSnapshotsAPITestCase, self).setUp() self.controller = v3_group_snapshots.GroupSnapshotsController() self.volume_api = cinder.volume.API() self.context = context.get_admin_context() self.context.project_id = fake.PROJECT_ID self.context.user_id = fake.USER_ID self.user_ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, auth_token=True) self.group = utils.create_group(self.context, group_type_id=fake.GROUP_TYPE_ID, volume_type_ids=[fake.VOLUME_TYPE_ID]) self.volume = utils.create_volume(self.context, group_id=self.group.id, volume_type_id=fake.VOLUME_TYPE_ID) self.g_snapshots_array = [ utils.create_group_snapshot(self.context, group_id=self.group.id, group_type_id=self.group.group_type_id) for _ in range(3) ] self.addCleanup(self._cleanup)
def test_create_snapshot_during_encryption_key_migration(self): fixed_key_id = '00000000-0000-0000-0000-000000000000' volume = tests_utils.create_volume(self.context, **self.volume_params) volume['encryption_key_id'] = fixed_key_id volume_id = volume['id'] self.volume.create_volume(self.context, volume) kwargs = {'encryption_key_id': fixed_key_id} snapshot = create_snapshot(volume['id'], **kwargs) self.assertEqual(fixed_key_id, snapshot.encryption_key_id) db.volume_update(self.context, volume_id, {'encryption_key_id': fake.ENCRYPTION_KEY_ID}) self.volume.create_snapshot(self.context, snapshot) snap_db = db.snapshot_get(self.context, snapshot.id) self.assertEqual(fake.ENCRYPTION_KEY_ID, snap_db.encryption_key_id) # cleanup resource snapshot.destroy() db.volume_destroy(self.context, volume_id)
def test_update_group_add_volume_invalid_state(self): self.group1.status = fields.GroupStatus.AVAILABLE self.group1.save() add_volume = utils.create_volume(self.ctxt, volume_type_id=fake.VOLUME_TYPE_ID, status='wrong_status') req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), version=GROUP_MICRO_VERSION) add_volumes = add_volume.id body = { "group": { "name": "group1", "description": "", "add_volumes": add_volumes, "remove_volumes": None, } } self.assertRaises(exception.InvalidVolume, self.controller.update, req, self.group1.id, body) add_volume.destroy()
def test_delete_image_volume(self): volume_params = { 'status': 'creating', 'host': 'some_host', 'cluster_name': 'some_cluster', 'size': 1 } volume_api = cinder.volume.api.API() volume = tests_utils.create_volume(self.context, **volume_params) volume.status = 'available' volume.save() image_id = '70a599e0-31e7-49b7-b260-868f441e862b' db.image_volume_cache_create(self.context, volume['host'], volume_params['cluster_name'], image_id, datetime.datetime.utcnow(), volume['id'], volume['size']) volume_api.delete(self.context, volume) entry = db.image_volume_cache_get_by_volume_id(self.context, volume['id']) self.assertIsNone(entry)
def test_delete_cgsnapshot_available(self): consistencygroup = utils.create_consistencygroup(self.context) volume_id = utils.create_volume( self.context, consistencygroup_id=consistencygroup.id)['id'] cgsnapshot_id = self._create_cgsnapshot( consistencygroup_id=consistencygroup.id, status='available') req = webob.Request.blank('/v2/fake/cgsnapshots/%s' % cgsnapshot_id) req.method = 'DELETE' req.headers['Content-Type'] = 'application/json' res = req.get_response(fakes.wsgi_app()) self.assertEqual(202, res.status_int) self.assertEqual('deleting', self._get_cgsnapshot_attrib(cgsnapshot_id, 'status')) db.cgsnapshot_destroy(context.get_admin_context(), cgsnapshot_id) db.volume_destroy(context.get_admin_context(), volume_id) consistencygroup.destroy()
def test_show_cgsnapshot(self): consistencygroup_id = utils.create_consistencygroup(self.context)['id'] volume_id = utils.create_volume( self.context, consistencygroup_id=consistencygroup_id)['id'] cgsnapshot_id = self._create_cgsnapshot( consistencygroup_id=consistencygroup_id) LOG.debug('Created cgsnapshot with id %s' % cgsnapshot_id) req = webob.Request.blank('/v2/fake/cgsnapshots/%s' % cgsnapshot_id) req.method = 'GET' req.headers['Content-Type'] = 'application/json' res = req.get_response(fakes.wsgi_app()) res_dict = json.loads(res.body) self.assertEqual(res.status_int, 200) self.assertEqual(res_dict['cgsnapshot']['description'], 'this is a test cgsnapshot') self.assertEqual(res_dict['cgsnapshot']['name'], 'test_cgsnapshot') self.assertEqual(res_dict['cgsnapshot']['status'], 'creating') db.cgsnapshot_destroy(context.get_admin_context(), cgsnapshot_id) db.volume_destroy(context.get_admin_context(), volume_id) db.consistencygroup_destroy(context.get_admin_context(), consistencygroup_id)
def test_delete_volume_of_group(self): group_type = group_types.create( self.context, 'group', {'consistent_group_snapshot_enabled': '<is> True'}) group = test_utils.create_group(self.context, id=fake_constants.CONSISTENCY_GROUP_ID, host='host@backend#unit_test_pool', group_type_id=group_type.id) volume = test_utils.create_volume( self.context, id=DATA_IN_VOLUME_VG['id'], display_name=DATA_IN_VOLUME_VG['display_name'], size=DATA_IN_VOLUME_VG['size'], group_id=group.id, host=DATA_IN_VOLUME_VG['host']) self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT self.DPL_MOCK.leave_vg.return_volume = DATA_OUTPUT self.dpldriver.delete_volume(volume) self.DPL_MOCK.leave_vg.assert_called_once_with( self._conver_uuid2hex(volume.id), self._conver_uuid2hex(volume.group_id)) self.DPL_MOCK.delete_vdev.assert_called_once_with( self._conver_uuid2hex(volume.id))
def test_delete_transfer_with_deleted_volume(self): # create a volume volume = utils.create_volume(self.ctxt, updated_at=self.updated_at) # create a transfer tx_api = transfer_api.API() with mock.patch('cinder.volume.volume_utils.notify_about_volume_usage' ) as mock_notify: transfer = tx_api.create(self.ctxt, volume['id'], 'Description') t = tx_api.get(self.ctxt, transfer['id']) calls = [ mock.call(self.ctxt, mock.ANY, "transfer.create.start"), mock.call(self.ctxt, mock.ANY, "transfer.create.end") ] mock_notify.assert_has_calls(calls) self.assertEqual(2, mock_notify.call_count) self.assertEqual(t['id'], transfer['id'], 'Unexpected transfer id') # force delete volume volume.destroy() # Make sure transfer has been deleted. self.assertRaises(exception.TransferNotFound, tx_api.get, self.ctxt, transfer['id'])
def test_snapshot_create_force(self, force_param): volume = utils.create_volume(self.ctx, status='in-use', volume_type_id=None) snapshot_name = 'Snapshot Test Name' snapshot_description = 'Snapshot Test Desc' snapshot = { "volume_id": volume.id, "force": force_param, "name": snapshot_name, "description": snapshot_description } body = dict(snapshot=snapshot) req = fakes.HTTPRequest.blank('/v2/snapshots') resp_dict = self.controller.create(req, body=body) self.assertIn('snapshot', resp_dict) self.assertEqual(snapshot_name, resp_dict['snapshot']['name']) self.assertEqual(snapshot_description, resp_dict['snapshot']['description']) self.assertIn('updated_at', resp_dict['snapshot']) db.volume_destroy(self.ctx, volume.id)