1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

impersonate requesting user in inventory deletion task

This commit is contained in:
AlanCoding 2017-07-25 10:54:37 -04:00
parent faa40b23e2
commit 55cc23a712
5 changed files with 39 additions and 13 deletions

View File

@ -1848,7 +1848,7 @@ class InventoryDetail(ControlledByScmMixin, RetrieveUpdateDestroyAPIView):
if not request.user.can_access(self.model, 'delete', obj): if not request.user.can_access(self.model, 'delete', obj):
raise PermissionDenied() raise PermissionDenied()
try: try:
obj.schedule_deletion() obj.schedule_deletion(getattr(request.user, 'id', None))
return Response(status=status.HTTP_202_ACCEPTED) return Response(status=status.HTTP_202_ACCEPTED)
except RuntimeError, e: except RuntimeError, e:
return Response(dict(error=_("{0}".format(e))), status=status.HTTP_400_BAD_REQUEST) return Response(dict(error=_("{0}".format(e))), status=status.HTTP_400_BAD_REQUEST)

View File

@ -376,14 +376,14 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin):
return self.insights_credential return self.insights_credential
@transaction.atomic @transaction.atomic
def schedule_deletion(self): def schedule_deletion(self, user_id=None):
from awx.main.tasks import delete_inventory from awx.main.tasks import delete_inventory
if self.pending_deletion is True: if self.pending_deletion is True:
raise RuntimeError("Inventory is already pending deletion.") raise RuntimeError("Inventory is already pending deletion.")
self.pending_deletion = True self.pending_deletion = True
self.save(update_fields=['pending_deletion']) self.save(update_fields=['pending_deletion'])
self.websocket_emit_status('pending_deletion') self.websocket_emit_status('pending_deletion')
delete_inventory.delay(self.pk) delete_inventory.delay(self.pk, user_id)
def _update_host_smart_inventory_memeberships(self): def _update_host_smart_inventory_memeberships(self):
if self.kind == 'smart' and settings.AWX_REBUILD_SMART_MEMBERSHIP: if self.kind == 'smart' and settings.AWX_REBUILD_SMART_MEMBERSHIP:

View File

@ -13,7 +13,7 @@ from django.db.models.signals import post_save, pre_delete, post_delete, m2m_cha
from django.dispatch import receiver from django.dispatch import receiver
# Django-CRUM # Django-CRUM
from crum import get_current_request from crum import get_current_request, get_current_user
from crum.signals import current_user_getter from crum.signals import current_user_getter
# AWX # AWX
@ -385,7 +385,8 @@ def activity_stream_create(sender, instance, created, **kwargs):
activity_entry = ActivityStream( activity_entry = ActivityStream(
operation='create', operation='create',
object1=object1, object1=object1,
changes=json.dumps(changes)) changes=json.dumps(changes),
actor=get_current_user())
activity_entry.save() activity_entry.save()
#TODO: Weird situation where cascade SETNULL doesn't work #TODO: Weird situation where cascade SETNULL doesn't work
# it might actually be a good idea to remove all of these FK references since # it might actually be a good idea to remove all of these FK references since
@ -412,7 +413,8 @@ def activity_stream_update(sender, instance, **kwargs):
activity_entry = ActivityStream( activity_entry = ActivityStream(
operation='update', operation='update',
object1=object1, object1=object1,
changes=json.dumps(changes)) changes=json.dumps(changes),
actor=get_current_user())
activity_entry.save() activity_entry.save()
if instance._meta.model_name != 'setting': # Is not conf.Setting instance if instance._meta.model_name != 'setting': # Is not conf.Setting instance
getattr(activity_entry, object1).add(instance) getattr(activity_entry, object1).add(instance)
@ -430,7 +432,8 @@ def activity_stream_delete(sender, instance, **kwargs):
activity_entry = ActivityStream( activity_entry = ActivityStream(
operation='delete', operation='delete',
changes=json.dumps(changes), changes=json.dumps(changes),
object1=object1) object1=object1,
actor=get_current_user())
activity_entry.save() activity_entry.save()
@ -477,7 +480,8 @@ def activity_stream_associate(sender, instance, **kwargs):
operation=action, operation=action,
object1=object1, object1=object1,
object2=object2, object2=object2,
object_relationship_type=obj_rel) object_relationship_type=obj_rel,
actor=get_current_user())
activity_entry.save() activity_entry.save()
getattr(activity_entry, object1).add(obj1) getattr(activity_entry, object1).add(obj1)
getattr(activity_entry, object2).add(obj2_actual) getattr(activity_entry, object2).add(obj2_actual)
@ -515,8 +519,9 @@ def get_current_user_from_drf_request(sender, **kwargs):
@receiver(pre_delete, sender=Organization) @receiver(pre_delete, sender=Organization)
def delete_inventory_for_org(sender, instance, **kwargs): def delete_inventory_for_org(sender, instance, **kwargs):
inventories = Inventory.objects.filter(organization__pk=instance.pk) inventories = Inventory.objects.filter(organization__pk=instance.pk)
user = get_current_user()
for inventory in inventories: for inventory in inventories:
try: try:
inventory.schedule_deletion() inventory.schedule_deletion(user_id=getattr(user, 'id', None))
except RuntimeError, e: except RuntimeError, e:
logger.debug(e) logger.debug(e)

View File

@ -42,6 +42,9 @@ from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
# Django-CRUM
from crum import impersonate
# AWX # AWX
from awx import __version__ as awx_application_version from awx import __version__ as awx_application_version
from awx.main.constants import CLOUD_PROVIDERS, PRIVILEGE_ESCALATION_METHODS from awx.main.constants import CLOUD_PROVIDERS, PRIVILEGE_ESCALATION_METHODS
@ -410,9 +413,16 @@ def update_host_smart_inventory_memberships():
@task(bind=True, queue='tower', base=LogErrorsTask, max_retries=5) @task(bind=True, queue='tower', base=LogErrorsTask, max_retries=5)
def delete_inventory(self, inventory_id): def delete_inventory(self, inventory_id, user_id):
with ignore_inventory_computed_fields(), \ # Delete inventory as user
ignore_inventory_group_removal(): if user_id is None:
user = None
else:
try:
user = User.objects.get(id=user_id)
except:
user = None
with ignore_inventory_computed_fields(), ignore_inventory_group_removal(), impersonate(user):
try: try:
i = Inventory.objects.get(id=inventory_id) i = Inventory.objects.get(id=inventory_id)
i.delete() i.delete()
@ -420,7 +430,7 @@ def delete_inventory(self, inventory_id):
'inventories-status_changed', 'inventories-status_changed',
{'group_name': 'inventories', 'inventory_id': inventory_id, 'status': 'deleted'} {'group_name': 'inventories', 'inventory_id': inventory_id, 'status': 'deleted'}
) )
logger.debug('Deleted inventory: %s' % inventory_id) logger.debug('Deleted inventory %s as user %s.' % (inventory_id, user_id))
except OperationalError: except OperationalError:
logger.warning('Database error deleting inventory {}, but will retry.'.format(inventory_id)) logger.warning('Database error deleting inventory {}, but will retry.'.format(inventory_id))
self.retry(countdown=10) self.retry(countdown=10)

View File

@ -16,6 +16,9 @@ from awx.main.models import (
from awx.main.utils import model_to_dict from awx.main.utils import model_to_dict
from awx.api.serializers import InventorySourceSerializer from awx.api.serializers import InventorySourceSerializer
# Django-CRUM
from crum import impersonate
model_serializer_mapping = { model_serializer_mapping = {
InventorySource: InventorySourceSerializer InventorySource: InventorySourceSerializer
@ -157,3 +160,11 @@ def test_missing_related_on_delete(inventory_source):
inventory_source.inventory.delete() inventory_source.inventory.delete()
d = model_to_dict(old_is, serializer_mapping=model_serializer_mapping) d = model_to_dict(old_is, serializer_mapping=model_serializer_mapping)
assert d['inventory'] == '<missing inventory source>-{}'.format(old_is.inventory_id) assert d['inventory'] == '<missing inventory source>-{}'.format(old_is.inventory_id)
@pytest.mark.django_db
def test_activity_stream_actor(admin_user):
with impersonate(admin_user):
o = Organization.objects.create(name='test organization')
entry = o.activitystream_set.get(operation='create')
assert entry.actor == admin_user