Add ability to see deleted and active records.

Fixes bug #900564

Changes `Context`.`read_deleted` from a bool to an enum string with values
"yes" (can read deleted records), "no" (cannot read deleted records), and
"only" (can only see deleted records, for backwards compatibility).

Change-Id: Ic81db3664c33f23f751b73973782efb06fce90d9
This commit is contained in:
Rick Harris 2011-12-07 16:06:31 -06:00
parent c3b7cce810
commit c40ee5cfe7
10 changed files with 718 additions and 971 deletions

View File

@ -1379,7 +1379,7 @@ class VsaCommands(object):
raise raise
is_admin = self.manager.is_admin(user_id) is_admin = self.manager.is_admin(user_id)
ctxt = context.RequestContext(user_id, project_id, is_admin) ctxt = context.RequestContext(user_id, project_id, is_admin=is_admin)
if not is_admin and \ if not is_admin and \
not self.manager.is_project_member(user_id, project_id): not self.manager.is_project_member(user_id, project_id):
msg = _("%(user_id)s must be an admin or a " msg = _("%(user_id)s must be an admin or a "

View File

@ -19,6 +19,7 @@
"""RequestContext: context for requests that persist through all of nova.""" """RequestContext: context for requests that persist through all of nova."""
import copy
import uuid import uuid
from nova import local from nova import local
@ -32,9 +33,14 @@ class RequestContext(object):
""" """
def __init__(self, user_id, project_id, is_admin=None, read_deleted=False, def __init__(self, user_id, project_id, is_admin=None, read_deleted="no",
roles=None, remote_address=None, timestamp=None, roles=None, remote_address=None, timestamp=None,
request_id=None, auth_token=None, strategy='noauth'): request_id=None, auth_token=None, strategy='noauth'):
"""
:param read_deleted: 'no' indicates deleted records are hidden, 'yes'
indicates deleted records are visible, 'only' indicates that
*only* deleted records are visible.
"""
self.user_id = user_id self.user_id = user_id
self.project_id = project_id self.project_id = project_id
self.roles = roles or [] self.roles = roles or []
@ -73,18 +79,17 @@ class RequestContext(object):
def elevated(self, read_deleted=None): def elevated(self, read_deleted=None):
"""Return a version of this context with admin flag set.""" """Return a version of this context with admin flag set."""
rd = self.read_deleted if read_deleted is None else read_deleted context = copy.copy(self)
return RequestContext(user_id=self.user_id, context.is_admin = True
project_id=self.project_id,
is_admin=True, if read_deleted is not None:
read_deleted=rd, context.read_deleted = read_deleted
roles=self.roles,
remote_address=self.remote_address, return context
timestamp=self.timestamp,
request_id=self.request_id,
auth_token=self.auth_token,
strategy=self.strategy)
def get_admin_context(read_deleted=False): def get_admin_context(read_deleted="no"):
return RequestContext(None, None, True, read_deleted) return RequestContext(user_id=None,
project_id=None,
is_admin=True,
read_deleted=read_deleted)

File diff suppressed because it is too large Load Diff

View File

@ -106,7 +106,7 @@ class CloudTestCase(test.TestCase):
self.project_id = 'fake' self.project_id = 'fake'
self.context = context.RequestContext(self.user_id, self.context = context.RequestContext(self.user_id,
self.project_id, self.project_id,
True) is_admin=True)
def fake_show(meh, context, id): def fake_show(meh, context, id):
return {'id': id, return {'id': id,
@ -1564,12 +1564,12 @@ class CloudTestCase(test.TestCase):
self.cloud.terminate_instances(self.context, [ec2_instance_id]) self.cloud.terminate_instances(self.context, [ec2_instance_id])
admin_ctxt = context.get_admin_context(read_deleted=False) admin_ctxt = context.get_admin_context(read_deleted="no")
vol = db.volume_get(admin_ctxt, vol1['id']) vol = db.volume_get(admin_ctxt, vol1['id'])
self.assertFalse(vol['deleted']) self.assertFalse(vol['deleted'])
db.volume_destroy(self.context, vol1['id']) db.volume_destroy(self.context, vol1['id'])
admin_ctxt = context.get_admin_context(read_deleted=True) admin_ctxt = context.get_admin_context(read_deleted="only")
vol = db.volume_get(admin_ctxt, vol2['id']) vol = db.volume_get(admin_ctxt, vol2['id'])
self.assertTrue(vol['deleted']) self.assertTrue(vol['deleted'])
@ -1689,13 +1689,13 @@ class CloudTestCase(test.TestCase):
self.cloud.terminate_instances(self.context, [ec2_instance_id]) self.cloud.terminate_instances(self.context, [ec2_instance_id])
admin_ctxt = context.get_admin_context(read_deleted=False) admin_ctxt = context.get_admin_context(read_deleted="no")
vol = db.volume_get(admin_ctxt, vol1_id) vol = db.volume_get(admin_ctxt, vol1_id)
self._assert_volume_detached(vol) self._assert_volume_detached(vol)
self.assertFalse(vol['deleted']) self.assertFalse(vol['deleted'])
db.volume_destroy(self.context, vol1_id) db.volume_destroy(self.context, vol1_id)
admin_ctxt = context.get_admin_context(read_deleted=True) admin_ctxt = context.get_admin_context(read_deleted="only")
vol = db.volume_get(admin_ctxt, vol2_id) vol = db.volume_get(admin_ctxt, vol2_id)
self.assertTrue(vol['deleted']) self.assertTrue(vol['deleted'])

View File

@ -312,7 +312,7 @@ class SimpleDriverTestCase(test.TestCase):
FLAGS.compute_manager) FLAGS.compute_manager)
compute1.start() compute1.start()
_create_instance() _create_instance()
ctxt = context.RequestContext('fake', 'fake', False) ctxt = context.RequestContext('fake', 'fake', is_admin=False)
global instance_uuids global instance_uuids
instance_uuids = [] instance_uuids = []
self.stubs.Set(SimpleScheduler, self.stubs.Set(SimpleScheduler,

View File

@ -52,7 +52,7 @@ class AdminApiTestCase(test.TestCase):
self.project_id = 'admin' self.project_id = 'admin'
self.context = context.RequestContext(self.user_id, self.context = context.RequestContext(self.user_id,
self.project_id, self.project_id,
True) is_admin=True)
def fake_show(meh, context, id): def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,

View File

@ -222,7 +222,7 @@ class ComputeTestCase(BaseTestCase):
self.assertEqual(instance['deleted_at'], None) self.assertEqual(instance['deleted_at'], None)
terminate = utils.utcnow() terminate = utils.utcnow()
self.compute.terminate_instance(self.context, instance['uuid']) self.compute.terminate_instance(self.context, instance['uuid'])
context = self.context.elevated(True) context = self.context.elevated(read_deleted="only")
instance = db.instance_get_by_uuid(context, instance['uuid']) instance = db.instance_get_by_uuid(context, instance['uuid'])
self.assert_(instance['launched_at'] < terminate) self.assert_(instance['launched_at'] < terminate)
self.assert_(instance['deleted_at'] > terminate) self.assert_(instance['deleted_at'] > terminate)
@ -674,7 +674,7 @@ class ComputeTestCase(BaseTestCase):
instance_uuid = instance['uuid'] instance_uuid = instance['uuid']
self.compute.run_instance(self.context, instance_uuid) self.compute.run_instance(self.context, instance_uuid)
non_admin_context = context.RequestContext(None, None, False, False) non_admin_context = context.RequestContext(None, None, is_admin=False)
# decorator should return False (fail) with locked nonadmin context # decorator should return False (fail) with locked nonadmin context
self.compute.lock_instance(self.context, instance_uuid) self.compute.lock_instance(self.context, instance_uuid)
@ -1230,8 +1230,9 @@ class ComputeAPITestCase(BaseTestCase):
try: try:
db.security_group_destroy(self.context, group['id']) db.security_group_destroy(self.context, group['id'])
group = db.security_group_get(context.get_admin_context( admin_deleted_context = context.get_admin_context(
read_deleted=True), group['id']) read_deleted="only")
group = db.security_group_get(admin_deleted_context, group['id'])
self.assert_(len(group.instances) == 0) self.assert_(len(group.instances) == 0)
finally: finally:
db.instance_destroy(self.context, ref[0]['id']) db.instance_destroy(self.context, ref[0]['id'])

View File

@ -53,7 +53,7 @@ class QuotaTestCase(test.TestCase):
self.project_id = 'admin' self.project_id = 'admin'
self.context = context.RequestContext(self.user_id, self.context = context.RequestContext(self.user_id,
self.project_id, self.project_id,
True) is_admin=True)
orig_rpc_call = rpc.call orig_rpc_call = rpc.call
def rpc_call_wrapper(context, topic, msg): def rpc_call_wrapper(context, topic, msg):

View File

@ -40,7 +40,7 @@ class VMWareAPIVMTestCase(test.TestCase):
def setUp(self): def setUp(self):
super(VMWareAPIVMTestCase, self).setUp() super(VMWareAPIVMTestCase, self).setUp()
self.context = context.RequestContext('fake', 'fake', False) self.context = context.RequestContext('fake', 'fake', is_admin=False)
self.flags(vmwareapi_host_ip='test_url', self.flags(vmwareapi_host_ip='test_url',
vmwareapi_host_username='test_username', vmwareapi_host_username='test_username',
vmwareapi_host_password='test_pass') vmwareapi_host_password='test_pass')

View File

@ -129,8 +129,7 @@ def get_instance_id_from_name_label(name_label, template):
def find_orphaned_instances(session, verbose=False): def find_orphaned_instances(session, verbose=False):
"""Find and return a list of orphaned instances.""" """Find and return a list of orphaned instances."""
ctxt = context.get_admin_context() ctxt = context.get_admin_context(read_deleted="only")
ctxt.read_deleted = True
orphaned_instances = [] orphaned_instances = []