Add API endpoints for workflow approvals

This commit is contained in:
beeankha
2019-07-03 14:46:59 -04:00
committed by Ryan Petrello
parent 72a65f74fd
commit 9024a514a6
11 changed files with 304 additions and 17 deletions
+61 -10
View File
@@ -50,16 +50,16 @@ from awx.main.constants import (
CENSOR_VALUE,
)
from awx.main.models import (
ActivityStream, AdHocCommand, AdHocCommandEvent, Credential,
CredentialInputSource, CredentialType, CustomInventoryScript,
Group, Host, Instance, InstanceGroup, Inventory, InventorySource,
InventoryUpdate, InventoryUpdateEvent, Job, JobEvent, JobHostSummary,
JobLaunchConfig, JobNotificationMixin, JobTemplate, Label, Notification,
NotificationTemplate, OAuth2AccessToken, OAuth2Application, Organization,
Project, ProjectUpdate, ProjectUpdateEvent, RefreshToken, Role, Schedule,
StdoutMaxBytesExceeded, SystemJob, SystemJobEvent, SystemJobTemplate,
Team, UnifiedJob, UnifiedJobTemplate, WorkflowJob, WorkflowJobNode,
WorkflowJobTemplate, WorkflowJobTemplateNode
ActivityStream, AdHocCommand, AdHocCommandEvent, Credential, CredentialInputSource,
CredentialType, CustomInventoryScript, Group, Host, Instance,
InstanceGroup, Inventory, InventorySource, InventoryUpdate,
InventoryUpdateEvent, Job, JobEvent, JobHostSummary, JobLaunchConfig,
JobNotificationMixin, JobTemplate, Label, Notification, NotificationTemplate,
OAuth2AccessToken, OAuth2Application, Organization, Project,
ProjectUpdate, ProjectUpdateEvent, RefreshToken, Role, Schedule,
SystemJob, SystemJobEvent, SystemJobTemplate, Team, UnifiedJob,
UnifiedJobTemplate, WorkflowApproval, WorkflowApprovalTemplate, WorkflowJob,
WorkflowJobNode, WorkflowJobTemplate, WorkflowJobTemplateNode, StdoutMaxBytesExceeded
)
from awx.main.models.base import VERBOSITY_CHOICES, NEW_JOB_TYPE_CHOICES
from awx.main.models.rbac import (
@@ -681,6 +681,8 @@ class UnifiedJobTemplateSerializer(BaseSerializer):
serializer_class = SystemJobTemplateSerializer
elif isinstance(obj, WorkflowJobTemplate):
serializer_class = WorkflowJobTemplateSerializer
elif isinstance(obj, WorkflowApprovalTemplate):
serializer_class = WorkflowApprovalTemplateSerializer
return serializer_class
def to_representation(self, obj):
@@ -782,6 +784,8 @@ class UnifiedJobSerializer(BaseSerializer):
serializer_class = SystemJobSerializer
elif isinstance(obj, WorkflowJob):
serializer_class = WorkflowJobSerializer
elif isinstance(obj, WorkflowApproval):
serializer_class = WorkflowApprovalSerializer
return serializer_class
def to_representation(self, obj):
@@ -838,6 +842,8 @@ class UnifiedJobListSerializer(UnifiedJobSerializer):
serializer_class = SystemJobListSerializer
elif isinstance(obj, WorkflowJob):
serializer_class = WorkflowJobListSerializer
elif isinstance(obj, WorkflowApproval):
serializer_class = WorkflowApprovalListSerializer
return serializer_class
def to_representation(self, obj):
@@ -3395,6 +3401,51 @@ class WorkflowJobCancelSerializer(WorkflowJobSerializer):
fields = ('can_cancel',)
class WorkflowApprovalSerializer(UnifiedJobSerializer):
class Meta:
model = WorkflowApproval
fields = ('*', 'result_stdout', '-controller_node', '-execution_node',)
def get_related(self, obj):
res = super(WorkflowApprovalSerializer, self).get_related(obj)
if obj.workflow_approval_template:
res['workflow_approval_template'] = self.reverse('api:workflow_approval_template_detail',
kwargs={'pk': obj.workflow_approval_template.pk})
res['notifications'] = self.reverse('api:workflow_approval_notifications_list', kwargs={'pk': obj.pk})
return res
def get_result_stdout(self, obj):
return obj.result_stdout
class WorkflowApprovalListSerializer(WorkflowApprovalSerializer, UnifiedJobListSerializer):
class Meta:
fields = ('*', '-execution_node', '-controller_node',)
class WorkflowApprovalTemplateSerializer(UnifiedJobTemplateSerializer):
class Meta:
model = WorkflowApprovalTemplate
fields = ('*',)
def get_related(self, obj):
res = super(WorkflowApprovalTemplateSerializer, self).get_related(obj)
if 'last_job' in res:
del res['last_job']
res.update(dict(
jobs = self.reverse('api:workflow_approval_template_jobs_list', kwargs={'pk': obj.pk}),
notification_templates_started = self.reverse('api:workflow_approval_template_notification_templates_started_list', kwargs={'pk': obj.pk}),
notification_templates_success = self.reverse('api:workflow_approval_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
notification_templates_error = self.reverse('api:workflow_approval_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
))
return res
class LaunchConfigurationBaseSerializer(BaseSerializer):
scm_branch = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
job_type = serializers.ChoiceField(allow_blank=True, allow_null=True, required=False, default=None,
+5
View File
@@ -71,6 +71,8 @@ from .instance import urls as instance_urls
from .instance_group import urls as instance_group_urls
from .oauth2 import urls as oauth2_urls
from .oauth2_root import urls as oauth2_root_urls
from .workflow_approval_template import urls as workflow_approval_template_urls
from .workflow_approval import urls as workflow_approval_urls
v2_urls = [
@@ -131,8 +133,11 @@ v2_urls = [
url(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'),
url(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'),
url(r'^activity_stream/', include(activity_stream_urls)),
url(r'^workflow_approval_templates/', include(workflow_approval_template_urls)),
url(r'^workflow_approval/', include(workflow_approval_urls)),
]
app_name = 'api'
urlpatterns = [
url(r'^$', ApiRootView.as_view(), name='api_root_view'),
+21
View File
@@ -0,0 +1,21 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
WorkflowApprovalList,
WorkflowApprovalDetail,
WorkflowApprovalNotificationsList,
)
urls = [
url(r'^$', WorkflowApprovalList.as_view(), name='workflow_approval_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalDetail.as_view(), name='workflow_approval_detail'),
url(r'^(?P<pk>[0-9]+)/approve/$', WorkflowApprovalDetail.as_view(), name='approved_workflow'),
url(r'^(?P<pk>[0-9]+)/reject/$', WorkflowApprovalDetail.as_view(), name='rejected_workflow'),
url(r'^(?P<pk>[0-9]+)/notifications/$', WorkflowApprovalNotificationsList.as_view(), name='workflow_approval_notifications_list'),
]
__all__ = ['urls']
@@ -0,0 +1,28 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
WorfklowApprovalTemplateList,
WorfklowApprovalTemplateDetail,
WorkflowApprovalTemplateJobsList,
WorkflowApprovalTemplateNotificationTemplatesErrorList,
WorkflowApprovalTemplateNotificationTemplatesStartedList,
WorkflowApprovalTemplateNotificationTemplatesSuccessList,
)
urls = [
url(r'^$', WorfklowApprovalTemplateList.as_view(), name='workflow_approval_template_list'),
url(r'^(?P<pk>[0-9]+)/$', WorfklowApprovalTemplateDetail.as_view(), name='workflow_approval_template_detail'),
url(r'^(?P<pk>[0-9]+)/approvals/$', WorkflowApprovalTemplateJobsList.as_view(), name='workflow_approval_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', WorkflowApprovalTemplateNotificationTemplatesStartedList.as_view(),
name='workflow_approval_template_notification_templates_started_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', WorkflowApprovalTemplateNotificationTemplatesErrorList.as_view(),
name='workflow_approval_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', WorkflowApprovalTemplateNotificationTemplatesSuccessList.as_view(),
name='workflow_approval_template_notification_templates_success_list'),
]
__all__ = ['urls']
+94
View File
@@ -4405,3 +4405,97 @@ for attr, value in list(locals().items()):
name = camelcase_to_underscore(attr)
view = value.as_view()
setattr(this_module, name, view)
class WorfklowApprovalTemplateList(ListAPIView):
model = models.WorkflowApprovalTemplate
serializer_class = serializers.WorkflowApprovalTemplateSerializer
def get(self, request, *args, **kwargs):
if not request.user.is_superuser and not request.user.is_system_auditor:
raise PermissionDenied(_("Superuser privileges needed."))
return super(WorfklowApprovalTemplateList, self).get(request, *args, **kwargs)
class WorfklowApprovalTemplateDetail(RetrieveAPIView):
model = models.WorkflowApprovalTemplate
serializer_class = serializers.WorkflowApprovalTemplateSerializer
class WorkflowApprovalTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.WorkflowApprovalTemplate
class WorkflowApprovalTemplateNotificationTemplatesStartedList(WorkflowApprovalTemplateNotificationTemplatesAnyList):
relationship = 'notification_templates_started'
class WorkflowApprovalTemplateNotificationTemplatesErrorList(WorkflowApprovalTemplateNotificationTemplatesAnyList):
relationship = 'notification_templates_error'
class WorkflowApprovalTemplateNotificationTemplatesSuccessList(WorkflowApprovalTemplateNotificationTemplatesAnyList):
relationship = 'notification_templates_success'
class WorkflowApprovalTemplateLaunch(GenericAPIView):
model = models.WorkflowApprovalTemplate
obj_permission_type = 'start'
serializer_class = serializers.EmptySerializer
def get(self, request, *args, **kwargs):
return Response({})
def post(self, request, *args, **kwargs):
obj = self.get_object()
new_job = obj.create_unified_job(extra_vars=request.data.get('extra_vars', {}))
new_job.signal_start()
data = OrderedDict()
data['workflow_approval'] = new_job.id
data.update(serializers.WorkflowApprovalSerializer(new_job, context=self.get_serializer_context()).to_representation(new_job))
headers = {'Location': new_job.get_absolute_url(request)}
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
class WorkflowApprovalTemplateJobsList(SubListAPIView):
model = models.WorkflowApproval
serializer_class = serializers.WorkflowApprovalListSerializer
parent_model = models.WorkflowApprovalTemplate
relationship = 'approvals'
parent_key = 'workflow_approval_template'
class WorkflowApprovalList(ListCreateAPIView):
model = models.WorkflowApproval
serializer_class = serializers.WorkflowApprovalListSerializer
def get(self, request, *args, **kwargs):
if not request.user.is_superuser and not request.user.is_system_auditor:
raise PermissionDenied(_("Superuser privileges needed."))
return super(WorkflowApprovalList, self).get(request, *args, **kwargs)
class WorkflowApprovalDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
model = models.WorkflowApproval
serializer_class = serializers.WorkflowApprovalSerializer
class WorkflowApprovalNotificationsList(SubListAPIView):
model = models.Notification
serializer_class = serializers.NotificationSerializer
parent_model = models.WorkflowApproval
relationship = 'notifications'
search_fields = ('subject', 'notification_type', 'body',)
+2
View File
@@ -124,6 +124,8 @@ class ApiVersionRootView(APIView):
data['activity_stream'] = reverse('api:activity_stream_list', request=request)
data['workflow_job_templates'] = reverse('api:workflow_job_template_list', request=request)
data['workflow_jobs'] = reverse('api:workflow_job_list', request=request)
data['workflow_approval_templates'] = reverse('api:workflow_approval_template_list', request=request)
data['workflow_approval'] = reverse('api:workflow_approval_list', request=request)
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request)
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request)
return Response(data)