mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 09:27:36 -02:30
Merge pull request #3848 from jangsutsr/3528_workflow_job_cancel_endpoint
Implement workflow job cancel endpoint
This commit is contained in:
@@ -2232,17 +2232,22 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
|
|||||||
#res['notifications'] = reverse('api:system_job_notifications_list', args=(obj.pk,))
|
#res['notifications'] = reverse('api:system_job_notifications_list', args=(obj.pk,))
|
||||||
res['workflow_nodes'] = reverse('api:workflow_job_workflow_nodes_list', args=(obj.pk,))
|
res['workflow_nodes'] = reverse('api:workflow_job_workflow_nodes_list', args=(obj.pk,))
|
||||||
res['labels'] = reverse('api:workflow_job_label_list', args=(obj.pk,))
|
res['labels'] = reverse('api:workflow_job_label_list', args=(obj.pk,))
|
||||||
# TODO: Cancel job
|
|
||||||
'''
|
|
||||||
if obj.can_cancel or True:
|
if obj.can_cancel or True:
|
||||||
res['cancel'] = reverse('api:workflow_job_cancel', args=(obj.pk,))
|
res['cancel'] = reverse('api:workflow_job_cancel', args=(obj.pk,))
|
||||||
'''
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
class WorkflowJobListSerializer(WorkflowJobSerializer, UnifiedJobListSerializer):
|
class WorkflowJobListSerializer(WorkflowJobSerializer, UnifiedJobListSerializer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class WorkflowJobCancelSerializer(WorkflowJobSerializer):
|
||||||
|
|
||||||
|
can_cancel = serializers.BooleanField(read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
fields = ('can_cancel',)
|
||||||
|
|
||||||
|
|
||||||
class WorkflowNodeBaseSerializer(BaseSerializer):
|
class WorkflowNodeBaseSerializer(BaseSerializer):
|
||||||
job_type = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
job_type = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||||
job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ workflow_job_urls = patterns('awx.api.views',
|
|||||||
url(r'^(?P<pk>[0-9]+)/$', 'workflow_job_detail'),
|
url(r'^(?P<pk>[0-9]+)/$', 'workflow_job_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', 'workflow_job_workflow_nodes_list'),
|
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', 'workflow_job_workflow_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/labels/$', 'workflow_job_label_list'),
|
url(r'^(?P<pk>[0-9]+)/labels/$', 'workflow_job_label_list'),
|
||||||
# url(r'^(?P<pk>[0-9]+)/cancel/$', 'workflow_job_cancel'),
|
url(r'^(?P<pk>[0-9]+)/cancel/$', 'workflow_job_cancel'),
|
||||||
#url(r'^(?P<pk>[0-9]+)/notifications/$', 'workflow_job_notifications_list'),
|
#url(r'^(?P<pk>[0-9]+)/notifications/$', 'workflow_job_notifications_list'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ from awx.api.serializers import * # noqa
|
|||||||
from awx.api.metadata import RoleMetadata
|
from awx.api.metadata import RoleMetadata
|
||||||
from awx.main.consumers import emit_channel_notification
|
from awx.main.consumers import emit_channel_notification
|
||||||
from awx.main.models.unified_jobs import ACTIVE_STATES
|
from awx.main.models.unified_jobs import ACTIVE_STATES
|
||||||
|
from awx.main.scheduler.tasks import run_job_complete
|
||||||
|
|
||||||
logger = logging.getLogger('awx.api.views')
|
logger = logging.getLogger('awx.api.views')
|
||||||
|
|
||||||
@@ -2862,6 +2863,23 @@ class WorkflowJobWorkflowNodesList(SubListAPIView):
|
|||||||
parent_key = 'workflow_job'
|
parent_key = 'workflow_job'
|
||||||
new_in_310 = True
|
new_in_310 = True
|
||||||
|
|
||||||
|
class WorkflowJobCancel(RetrieveAPIView):
|
||||||
|
|
||||||
|
model = WorkflowJob
|
||||||
|
serializer_class = WorkflowJobCancelSerializer
|
||||||
|
is_job_cancel = True
|
||||||
|
new_in_310 = True
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
if obj.can_cancel:
|
||||||
|
obj.cancel()
|
||||||
|
#TODO: Figure out whether an immediate schedule is needed.
|
||||||
|
run_job_complete.delay(obj.id)
|
||||||
|
return Response(status=status.HTTP_202_ACCEPTED)
|
||||||
|
else:
|
||||||
|
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||||
|
|
||||||
class SystemJobTemplateList(ListAPIView):
|
class SystemJobTemplateList(ListAPIView):
|
||||||
|
|
||||||
model = SystemJobTemplate
|
model = SystemJobTemplate
|
||||||
|
|||||||
@@ -423,4 +423,3 @@ class WorkflowJob(UnifiedJob, WorkflowJobOptions, JobNotificationMixin, Workflow
|
|||||||
'''
|
'''
|
||||||
def start_celery_task(self, opts, error_callback, success_callback):
|
def start_celery_task(self, opts, error_callback, success_callback):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,12 @@ class TaskManager():
|
|||||||
def process_finished_workflow_jobs(self, workflow_jobs):
|
def process_finished_workflow_jobs(self, workflow_jobs):
|
||||||
for workflow_job in workflow_jobs:
|
for workflow_job in workflow_jobs:
|
||||||
dag = WorkflowDAG(workflow_job)
|
dag = WorkflowDAG(workflow_job)
|
||||||
if dag.is_workflow_done():
|
if workflow_job.cancel_flag:
|
||||||
|
workflow_job.status = 'canceled'
|
||||||
|
workflow_job.save()
|
||||||
|
dag.cancel_node_jobs()
|
||||||
|
connection.on_commit(lambda: workflow_job.websocket_emit_status(workflow_job.status))
|
||||||
|
elif dag.is_workflow_done():
|
||||||
if workflow_job._has_failed():
|
if workflow_job._has_failed():
|
||||||
workflow_job.status = 'failed'
|
workflow_job.status = 'failed'
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -48,6 +48,16 @@ class WorkflowDAG(SimpleDAG):
|
|||||||
nodes.extend(children_all)
|
nodes.extend(children_all)
|
||||||
return [n['node_object'] for n in nodes_found]
|
return [n['node_object'] for n in nodes_found]
|
||||||
|
|
||||||
|
def cancel_node_jobs(self):
|
||||||
|
for n in self.nodes:
|
||||||
|
obj = n['node_object']
|
||||||
|
job = obj.job
|
||||||
|
|
||||||
|
if not job:
|
||||||
|
continue
|
||||||
|
elif job.can_cancel:
|
||||||
|
job.cancel()
|
||||||
|
|
||||||
def is_workflow_done(self):
|
def is_workflow_done(self):
|
||||||
root_nodes = self.get_root_nodes()
|
root_nodes = self.get_root_nodes()
|
||||||
nodes = root_nodes
|
nodes = root_nodes
|
||||||
|
|||||||
Reference in New Issue
Block a user