From 13450fdbf950d239b85025dd88d98d34344588a3 Mon Sep 17 00:00:00 2001 From: beeankha Date: Wed, 4 Sep 2019 18:04:43 -0400 Subject: [PATCH] Set up approval notifications to send --- awx/api/serializers.py | 2 +- awx/api/views/__init__.py | 4 +- awx/api/views/organization.py | 2 +- .../0088_v360_approval_node_notifications.py | 10 +-- awx/main/models/notifications.py | 1 - awx/main/models/workflow.py | 73 +++++++------------ awx/main/scheduler/task_manager.py | 7 +- 7 files changed, 35 insertions(+), 64 deletions(-) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 84e1ed4051..c09c9a1ddc 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -3495,7 +3495,7 @@ class WorkflowApprovalTemplateSerializer(UnifiedJobTemplateSerializer): # Placeholder... res.update(dict( jobs = self.reverse('api:workflow_approval_template_jobs_list', kwargs={'pk': obj.pk}), - approval_notifications = self.reverse('api:workflow_approval_template_notification_list', kwargs={'pk': obj.pk}), + approval_notification_templates = self.reverse('api:workflow_approval_template_notification_list', kwargs={'pk': obj.pk}), )) return res diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index 8719ac7be4..92674b1d7d 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -3291,7 +3291,7 @@ class WorkflowJobTemplateNotificationTemplatesSuccessList(WorkflowJobTemplateNot class WorkflowJobTemplateNotificationTemplatesApprovalList(WorkflowJobTemplateNotificationTemplatesAnyList): - relationship = 'approval_notifications' + relationship = 'notification_templates_approvals' class WorkflowJobTemplateAccessList(ResourceAccessList): @@ -4473,7 +4473,7 @@ class WorkflowApprovalTemplateNotificationTemplatesList(SubListCreateAttachDetac class WorkflowApprovalNotificationTemplatesList(WorkflowApprovalTemplateNotificationTemplatesList): - relationship = 'approval_notifications' + relationship = 'notification_templates_approvals' class WorkflowApprovalList(ListCreateAPIView): diff --git a/awx/api/views/organization.py b/awx/api/views/organization.py index 2f3fed49ac..e1af4c67b1 100644 --- a/awx/api/views/organization.py +++ b/awx/api/views/organization.py @@ -197,7 +197,7 @@ class OrganizationNotificationTemplatesSuccessList(OrganizationNotificationTempl class OrganizationNotificationTemplatesApprovalList(OrganizationNotificationTemplatesAnyList): - relationship = 'approval_notifications' + relationship = 'notification_templates_approvals' class OrganizationInstanceGroupsList(SubListAttachDetachAPIView): diff --git a/awx/main/migrations/0088_v360_approval_node_notifications.py b/awx/main/migrations/0088_v360_approval_node_notifications.py index bb11b93b0d..d24051c18e 100644 --- a/awx/main/migrations/0088_v360_approval_node_notifications.py +++ b/awx/main/migrations/0088_v360_approval_node_notifications.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-09-03 19:25 +# Generated by Django 2.2.4 on 2019-09-04 18:23 from django.db import migrations, models @@ -12,13 +12,13 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name='organization', - name='approval_notifications', - field=models.ManyToManyField(blank=True, related_name='organization_approval_notifications', to='main.NotificationTemplate'), + name='notification_templates_approvals', + field=models.ManyToManyField(blank=True, related_name='organization_notification_templates_for_approvals', to='main.NotificationTemplate'), ), migrations.AddField( model_name='unifiedjobtemplate', - name='approval_notifications', - field=models.ManyToManyField(blank=True, related_name='unifiedjobtemplate_approval_notifications', to='main.NotificationTemplate'), + name='notification_templates_approvals', + field=models.ManyToManyField(blank=True, related_name='unifiedjobtemplate_notification_templates_for_approvals', to='main.NotificationTemplate'), ), migrations.AlterField( model_name='workflowjobnode', diff --git a/awx/main/models/notifications.py b/awx/main/models/notifications.py index 588e97db3b..2d2a692824 100644 --- a/awx/main/models/notifications.py +++ b/awx/main/models/notifications.py @@ -463,7 +463,6 @@ class JobNotificationMixin(object): def send_notification_templates(self, status): from awx.main.tasks import send_notifications # avoid circular import - # Placeholder... Adding "pending" status here for approvals. if status not in ['pending', 'running', 'succeeded', 'failed']: raise ValueError(_("status must be either pending, running, succeeded or failed")) try: diff --git a/awx/main/models/workflow.py b/awx/main/models/workflow.py index 6d8bf14019..d92a21b394 100644 --- a/awx/main/models/workflow.py +++ b/awx/main/models/workflow.py @@ -5,7 +5,7 @@ import logging # Django -from django.db import models +from django.db import connection, models from django.conf import settings from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ObjectDoesNotExist @@ -577,6 +577,13 @@ class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificatio for node in self.workflow_job_nodes.all().select_related('job'): if node.job is None: node_job_description = 'no job.' + elif type(node.unified_job_template) is WorkflowApprovalTemplate: + if node.job.status == 'pending': + node_job_description = 'APPROVE THIS!!!' + if node.job.status == 'successful': + node_job_description = 'THIS GOT APPROVED!!!' + if node.job.status == 'failed': + node_job_description = 'DENIED!!!' else: node_job_description = ('job #{0}, "{1}", which finished with status {2}.' .format(node.job.id, node.job.name, node.job.status)) @@ -647,40 +654,6 @@ class WorkflowApprovalTemplate(UnifiedJobTemplate): def get_absolute_url(self, request=None): return reverse('api:workflow_approval_template_detail', kwargs={'pk': self.pk}, request=request) - @property - def notification_templates(self): - base_notification_templates = NotificationTemplate.objects.all() - error_notification_templates = list(base_notification_templates - .filter(unifiedjobtemplate_notification_templates_for_errors__in=[self])) - started_notification_templates = list(base_notification_templates - .filter(unifiedjobtemplate_notification_templates_for_started__in=[self])) - success_notification_templates = list(base_notification_templates - .filter(unifiedjobtemplate_notification_templates_for_success__in=[self])) - return dict(error=list(error_notification_templates), - started=list(started_notification_templates), - success=list(success_notification_templates)) - - # base_notification_templates = NotificationTemplate.objects.all() - # approval_notification_templates = list(base_notification_templates - # .filter(unifiedjobtemplate_notification_templates_for_errors__in=[self]), - # base_notification_templates - # .filter(unifiedjobtemplate_notification_templates_for_started__in=[self]), - # base_notification_templates - # .filter(unifiedjobtemplate_notification_templates_for_success__in=[self])) - # return dict(approval=list(approval_notification_templates)) -# Placeholder... Approval nodes don't have orgs! - # if self.project is not None and self.project.organization is None: - # error_notification_templates = set(error_notification_templates + list(base_notification_templates.filter( - # organization_notification_templates_for_errors=self.project.organization))) - # started_notification_templates = set(started_notification_templates + list(base_notification_templates.filter( - # organization_notification_templates_for_started=self.project.organization))) - # success_notification_templates = set(success_notification_templates + list(base_notification_templates.filter( - # organization_notification_templates_for_success=self.project.organization))) - # return dict(error=list(error_notification_templates), - # approval_notification_templates=list(needs_approval_notification_templates), - # success=list(success_notification_templates)) - - @property def workflow_job_template(self): return self.workflowjobtemplatenodes.first().workflow_job_template @@ -726,6 +699,7 @@ class WorkflowApproval(UnifiedJob, JobNotificationMixin): def approve(self, request=None): self.status = 'successful' self.save() + self.send_approval_notification(self.status) self.websocket_emit_status(self.status) schedule_task_manager() return reverse('api:workflow_approval_approve', kwargs={'pk': self.pk}, request=request) @@ -733,24 +707,27 @@ class WorkflowApproval(UnifiedJob, JobNotificationMixin): def deny(self, request=None): self.status = 'failed' self.save() + self.send_approval_notification(self.status) self.websocket_emit_status(self.status) schedule_task_manager() return reverse('api:workflow_approval_deny', kwargs={'pk': self.pk}, request=request) - # Placeholder... - def approval_notification_data(self): - result = super(WorkflowApproval, self).approval_notification_data() - str_arr = ['Approval summary:', ''] - for node in self.workflow_job_nodes.all().select_related('job'): - if node.job is None: - node_job_description = 'no job.' - else: - node_job_description = ('job #{0}, "{1}", which finished with status {2}.' - .format(node.job.id, node.job.name, node.job.status)) - str_arr.append("- node #{0} spawns {1}".format(node.id, node_job_description)) - result['body'] = '\n'.join(str_arr) - return result + def signal_start(self, **kwargs): + can_start = super(WorkflowApproval, self).signal_start(**kwargs) + self.send_approval_notification('running') + return can_start + def send_approval_notification(self, status): + from awx.main.tasks import send_notifications # avoid circular import + for nt in self.workflow_job_template.notification_templates["approvals"]: + (notification_subject, notification_body) = self.workflow_job.build_notification_message(nt, status) + + def send_it(local_nt=nt, local_subject=notification_subject, local_body=notification_body): + def _func(): + send_notifications.delay([local_nt.generate_notification(local_subject, local_body).id], + job_id=self.id) + return _func + connection.on_commit(send_it()) @property def workflow_job_template(self): diff --git a/awx/main/scheduler/task_manager.py b/awx/main/scheduler/task_manager.py index fbd2edd1ea..609ba163e0 100644 --- a/awx/main/scheduler/task_manager.py +++ b/awx/main/scheduler/task_manager.py @@ -239,12 +239,6 @@ class TaskManager(): task.send_notification_templates('running') logger.debug('Transitioning %s to running status.', task.log_format) schedule_task_manager() - # Placeholder... - elif type(task) is WorkflowApproval: - task.status = 'pending' - task.send_notification_templates('pending') - logger.debug('Transitioning %s to pending status.', task.log_format) - schedule_task_manager() elif not task.supports_isolation() and rampart_group.controller_id: # non-Ansible jobs on isolated instances run on controller task.instance_group = rampart_group.controller @@ -539,6 +533,7 @@ class TaskManager(): logger.warn(timeout_message) task.timed_out = True task.status = 'failed' + self.send_approval_notification(task.status) task.websocket_emit_status(task.status) task.job_explanation = timeout_message task.save(update_fields=['status', 'job_explanation', 'timed_out'])