From 813c786dc7e5c8bdd3cb7711f4c6b69c6f3d2f61 Mon Sep 17 00:00:00 2001 From: Aaron Tan Date: Wed, 26 Oct 2016 14:53:22 -0400 Subject: [PATCH 1/4] Add destory sanity checks to prevent UJ deletion during underlying workflow run. --- awx/api/views.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/awx/api/views.py b/awx/api/views.py index 66980e141d..ea38018267 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1087,6 +1087,14 @@ class ProjectUpdateDetail(RetrieveDestroyAPIView): serializer_class = ProjectUpdateSerializer new_in_13 = True + def destroy(self, request, *args, **kwargs): + obj = self.get_object() + for unified_job_node in obj.unified_job_nodes.all(): + if unified_job_node.workflow_job.status in ('new', 'pending', 'waiting', + 'running', 'updating'): + raise PermissionDenied() + return super(ProjectUpdateDetail, self).destroy(request, *args, **kwargs) + class ProjectUpdateCancel(RetrieveAPIView): model = ProjectUpdate @@ -2166,6 +2174,14 @@ class InventoryUpdateDetail(RetrieveDestroyAPIView): serializer_class = InventoryUpdateSerializer new_in_14 = True + def destroy(self, request, *args, **kwargs): + obj = self.get_object() + for unified_job_node in obj.unified_job_nodes.all(): + if unified_job_node.workflow_job.status in ('new', 'pending', 'waiting', + 'running', 'updating'): + raise PermissionDenied() + return super(InventoryUpdateDetail, self).destroy(request, *args, **kwargs) + class InventoryUpdateCancel(RetrieveAPIView): model = InventoryUpdate @@ -2869,6 +2885,14 @@ class JobDetail(RetrieveUpdateDestroyAPIView): return self.http_method_not_allowed(request, *args, **kwargs) return super(JobDetail, self).update(request, *args, **kwargs) + def destroy(self, request, *args, **kwargs): + obj = self.get_object() + for unified_job_node in obj.unified_job_nodes.all(): + if unified_job_node.workflow_job.status in ('new', 'pending', 'waiting', + 'running', 'updating'): + raise PermissionDenied() + return super(JobDetail, self).destroy(request, *args, **kwargs) + class JobLabelList(SubListAPIView): model = Label From 6ecd45681ab57581cb3564cd0bde3ec9720bb1ab Mon Sep 17 00:00:00 2001 From: Aaron Tan Date: Thu, 27 Oct 2016 15:55:05 -0400 Subject: [PATCH 2/4] Use ACTIVE_STATES and change error message text. --- awx/api/views.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index ea38018267..154df98306 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -69,6 +69,7 @@ from awx.api.renderers import * # noqa from awx.api.serializers import * # noqa from awx.api.metadata import RoleMetadata from awx.main.consumers import emit_channel_notification +from awx.main.models.unified_jobs import ACTIVE_STATES logger = logging.getLogger('awx.api.views') @@ -1090,9 +1091,8 @@ class ProjectUpdateDetail(RetrieveDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() for unified_job_node in obj.unified_job_nodes.all(): - if unified_job_node.workflow_job.status in ('new', 'pending', 'waiting', - 'running', 'updating'): - raise PermissionDenied() + if unified_job_node.workflow_job.status in ACTIVE_STATES: + raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') return super(ProjectUpdateDetail, self).destroy(request, *args, **kwargs) class ProjectUpdateCancel(RetrieveAPIView): @@ -2177,9 +2177,8 @@ class InventoryUpdateDetail(RetrieveDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() for unified_job_node in obj.unified_job_nodes.all(): - if unified_job_node.workflow_job.status in ('new', 'pending', 'waiting', - 'running', 'updating'): - raise PermissionDenied() + if unified_job_node.workflow_job.status in ACTIVE_STATES: + raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') return super(InventoryUpdateDetail, self).destroy(request, *args, **kwargs) class InventoryUpdateCancel(RetrieveAPIView): @@ -2888,9 +2887,8 @@ class JobDetail(RetrieveUpdateDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() for unified_job_node in obj.unified_job_nodes.all(): - if unified_job_node.workflow_job.status in ('new', 'pending', 'waiting', - 'running', 'updating'): - raise PermissionDenied() + if unified_job_node.workflow_job.status in ACTIVE_STATES: + raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') return super(JobDetail, self).destroy(request, *args, **kwargs) class JobLabelList(SubListAPIView): From 62e0291f863146ad471fea06b7e2c292ab317778 Mon Sep 17 00:00:00 2001 From: Aaron Tan Date: Fri, 28 Oct 2016 15:03:17 -0400 Subject: [PATCH 3/4] Integrate unnecessary queries for better performance. --- awx/api/views.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index 154df98306..b1912021eb 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1090,9 +1090,8 @@ class ProjectUpdateDetail(RetrieveDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() - for unified_job_node in obj.unified_job_nodes.all(): - if unified_job_node.workflow_job.status in ACTIVE_STATES: - raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') + if obj.unified_job_nodes.filter(workflow_job__status__in=ACTIVE_STATES).exists(): + raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') return super(ProjectUpdateDetail, self).destroy(request, *args, **kwargs) class ProjectUpdateCancel(RetrieveAPIView): @@ -2176,9 +2175,8 @@ class InventoryUpdateDetail(RetrieveDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() - for unified_job_node in obj.unified_job_nodes.all(): - if unified_job_node.workflow_job.status in ACTIVE_STATES: - raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') + if obj.unified_job_nodes.filter(workflow_job__status__in=ACTIVE_STATES).exists(): + raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') return super(InventoryUpdateDetail, self).destroy(request, *args, **kwargs) class InventoryUpdateCancel(RetrieveAPIView): @@ -2886,9 +2884,8 @@ class JobDetail(RetrieveUpdateDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() - for unified_job_node in obj.unified_job_nodes.all(): - if unified_job_node.workflow_job.status in ACTIVE_STATES: - raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') + if obj.unified_job_nodes.filter(workflow_job__status__in=ACTIVE_STATES).exists(): + raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') return super(JobDetail, self).destroy(request, *args, **kwargs) class JobLabelList(SubListAPIView): From ba1dedf2c3841eb8f9be54dbc0414e240a57624b Mon Sep 17 00:00:00 2001 From: Aaron Tan Date: Mon, 31 Oct 2016 15:09:01 -0400 Subject: [PATCH 4/4] i18n support added. --- awx/api/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index b1912021eb..8c677b7890 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1091,7 +1091,7 @@ class ProjectUpdateDetail(RetrieveDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() if obj.unified_job_nodes.filter(workflow_job__status__in=ACTIVE_STATES).exists(): - raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') + raise PermissionDenied(detail=_('Can not delete job resource when associated workflow job is running.')) return super(ProjectUpdateDetail, self).destroy(request, *args, **kwargs) class ProjectUpdateCancel(RetrieveAPIView): @@ -2176,7 +2176,7 @@ class InventoryUpdateDetail(RetrieveDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() if obj.unified_job_nodes.filter(workflow_job__status__in=ACTIVE_STATES).exists(): - raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') + raise PermissionDenied(detail=_('Can not delete job resource when associated workflow job is running.')) return super(InventoryUpdateDetail, self).destroy(request, *args, **kwargs) class InventoryUpdateCancel(RetrieveAPIView): @@ -2885,7 +2885,7 @@ class JobDetail(RetrieveUpdateDestroyAPIView): def destroy(self, request, *args, **kwargs): obj = self.get_object() if obj.unified_job_nodes.filter(workflow_job__status__in=ACTIVE_STATES).exists(): - raise PermissionDenied(detail='Can not delete job resource when associated workflow job is running.') + raise PermissionDenied(detail=_('Can not delete job resource when associated workflow job is running.')) return super(JobDetail, self).destroy(request, *args, **kwargs) class JobLabelList(SubListAPIView):