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:
parent
faa40b23e2
commit
55cc23a712
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user