diff --git a/awx/api/urls/analytics.py b/awx/api/urls/analytics.py new file mode 100644 index 0000000000..17078c32c3 --- /dev/null +++ b/awx/api/urls/analytics.py @@ -0,0 +1,32 @@ +# Copyright (c) 2017 Ansible, Inc. +# All Rights Reserved. + +from django.urls import re_path + +import awx.api.views.analytics as analytics + + +urls = [ + re_path(r'^$', analytics.AnalyticsRootView.as_view(), name='analytics_root_view'), + re_path(r'^test/$', analytics.AnalyticsTestList.as_view(), name='analytics_test_list'), + re_path(r'^authorized/$', analytics.AnalyticsAuthorizedView.as_view(), name='analytics_authorized'), + re_path(r'^reports/$', analytics.AnalyticsReportsList.as_view(), name='analytics_reports_list'), + re_path(r'^report/(?P[\w-]+)/$', analytics.AnalyticsReportDetail.as_view(), name='analytics_report_detail'), + re_path(r'^report_options/$', analytics.AnalyticsReportOptionsList.as_view(), name='analytics_report_options_list'), + re_path(r'^adoption_rate/$', analytics.AnalyticsAdoptionRateList.as_view(), name='analytics_adoption_rate'), + re_path(r'^adoption_rate_options/$', analytics.AnalyticsAdoptionRateList.as_view(), name='analytics_adoption_rate_options'), + re_path(r'^event_explorer/$', analytics.AnalyticsEventExplorerList.as_view(), name='analytics_event_explorer'), + re_path(r'^event_explorer_options/$', analytics.AnalyticsEventExplorerList.as_view(), name='analytics_event_explorer_options'), + re_path(r'^host_explorer/$', analytics.AnalyticsHostExplorerList.as_view(), name='analytics_host_explorer'), + re_path(r'^host_explorer_options/$', analytics.AnalyticsHostExplorerList.as_view(), name='analytics_host_explorer_options'), + re_path(r'^job_explorer/$', analytics.AnalyticsJobExplorerList.as_view(), name='analytics_job_explorer'), + re_path(r'^job_explorer_options/$', analytics.AnalyticsJobExplorerList.as_view(), name='analytics_job_explorer_options'), + re_path(r'^probe_templates/$', analytics.AnalyticsProbeTemplatesList.as_view(), name='analytics_probe_templates_explorer'), + re_path(r'^probe_templates_options/$', analytics.AnalyticsProbeTemplatesList.as_view(), name='analytics_probe_templates_options'), + re_path(r'^probe_template_for_hosts/$', analytics.AnalyticsProbeTemplateForHostsList.as_view(), name='analytics_probe_template_for_hosts_explorer'), + re_path(r'^probe_template_for_hosts_options/$', analytics.AnalyticsProbeTemplateForHostsList.as_view(), name='analytics_probe_template_for_hosts_options'), + re_path(r'^roi_templates/$', analytics.AnalyticsRoiTemplatesList.as_view(), name='analytics_roi_templates_explorer'), + re_path(r'^roi_templates_options/$', analytics.AnalyticsRoiTemplatesList.as_view(), name='analytics_roi_templates_options'), +] + +__all__ = ['urls'] diff --git a/awx/api/urls/urls.py b/awx/api/urls/urls.py index bb27710dcc..673a1b11cd 100644 --- a/awx/api/urls/urls.py +++ b/awx/api/urls/urls.py @@ -82,7 +82,7 @@ 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 - +from .analytics import urls as analytics_urls v2_urls = [ re_path(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'), @@ -147,6 +147,7 @@ v2_urls = [ re_path(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'), re_path(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'), re_path(r'^activity_stream/', include(activity_stream_urls)), + re_path(r'^analytics/', include(analytics_urls)), re_path(r'^workflow_approval_templates/', include(workflow_approval_template_urls)), re_path(r'^workflow_approvals/', include(workflow_approval_urls)), re_path(r'^bulk/$', BulkView.as_view(), name='bulk'), diff --git a/awx/api/views/analytics.py b/awx/api/views/analytics.py new file mode 100644 index 0000000000..ded72f7018 --- /dev/null +++ b/awx/api/views/analytics.py @@ -0,0 +1,173 @@ +import requests +import logging + +from django.utils.translation import gettext_lazy as _ + +from awx.api.generics import APIView, Response +from awx.api.permissions import IsSystemAdminOrAuditor +from awx.api.versioning import reverse +from rest_framework.permissions import AllowAny +from rest_framework import status + +from collections import OrderedDict + +# docker-docker API request requires: +# ``` +# docker network connect koku_default tools_awx_1 +# ``` +AUTOMATION_ANALYTICS_API_URL = "http://automation-analytics-backend_fastapi_1:8080/api/tower-analytics/v1" +# AUTOMATION_ANALYTICS_API_URL = "http://localhost:8004/api/tower-analytics/v1" + +logger = logging.getLogger('awx.api.views') + + +class GetNotAllowedMixin(object): + def get(self, request, format=None): + return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) + + +class AnalyticsRootView(APIView): + permission_classes = (AllowAny,) + name = _('Automation Analytics') + swagger_topic = 'Automation Analytics' + + def get(self, request, format=None): + data = OrderedDict() + data['reports'] = reverse('analytics_reports_list') + return Response(data) + + +class AnalyticsTestList(APIView): + name = _("Testing") + permission_classes = (IsSystemAdminOrAuditor,) + swagger_topic = "AA" + + def get(self, request, format=None): + logger.info(f"TEST: {type(request.headers)}") + new_headers = request.headers.copy() + + data = { + 'get': { + 'method': request.method, + 'content-type': request.content_type, + 'data': request.data, + 'query_params': request.query_params, + 'headers': new_headers, + 'path': request.path, + } + } + return Response(data) + + def post(self, request, format=None): + return self.get(request, format) + + +class AnalyticsGenericView(APIView): + """ + Example: + headers = { + 'Content-Type': 'application/json', + } + + params = { + 'limit': '20', + 'offset': '0', + 'sort_by': 'name:asc', + } + + json_data = { + 'limit': '20', + 'offset': '0', + 'sort_options': 'name', + 'sort_order': 'asc', + 'tags': [], + 'slug': [], + 'name': [], + 'description': '', + } + + response = requests.post(f'{AUTOMATION_ANALYTICS_API_URL}/reports/', params=params, + headers=headers, json=json_data) + + return Response(response.json(), status=response.status_code) + """ + + permission_classes = (IsSystemAdminOrAuditor,) + + def _remove_api_path_prefix(self, request_path): + parts = request_path.split('analytics/') + return parts[len(parts) - 1] + + def _forward_get(self, request, format=None): + headers = {'Content-Type': 'application/json'} + analytics_path = self._remove_api_path_prefix(request.path) + response = requests.get(f'{AUTOMATION_ANALYTICS_API_URL}/{analytics_path}', params=request.query_params, headers=headers) + return Response(response.json(), status=response.status_code) + + def _forward_post(self, request, format=None): + analytics_path = self._remove_api_path_prefix(request.path) + response = requests.post(f'{AUTOMATION_ANALYTICS_API_URL}/{analytics_path}', params=request.query_params, headers=request.headers, json=request.data) + return Response(response.json(), status=response.status_code) + + +class AnalyticsGenericListView(AnalyticsGenericView): + def get(self, request, format=None): + return self._forward_get(request, format) + + def post(self, request, format=None): + return self._forward_post(request, format) + + +class AnalyticsGenericDetailView(AnalyticsGenericView): + def get(self, request, slug, format=None): + return self._forward_get(request, format) + + def post(self, request, slug, format=None): + return self._forward_post(request, format) + + +class AnalyticsAuthorizedView(AnalyticsGenericListView): + name = _("Authorized") + + +class AnalyticsReportsList(AnalyticsGenericListView): + name = _("Reports") + swagger_topic = "Automation Analytics" + + +class AnalyticsReportDetail(AnalyticsGenericDetailView): + name = _("Report") + + +class AnalyticsReportOptionsList(AnalyticsGenericListView): + name = _("Report Options") + + +class AnalyticsAdoptionRateList(GetNotAllowedMixin, AnalyticsGenericListView): + name = _("Adoption Rate") + + +class AnalyticsEventExplorerList(GetNotAllowedMixin, AnalyticsGenericListView): + name = _("Event Explorer") + + +class AnalyticsHostExplorerList(GetNotAllowedMixin, AnalyticsGenericListView): + name = _("Host Explorer") + + +class AnalyticsJobExplorerList(GetNotAllowedMixin, AnalyticsGenericListView): + """TODO: Allow Http GET?""" + + name = _("Job Explorer") + + +class AnalyticsProbeTemplatesList(GetNotAllowedMixin, AnalyticsGenericListView): + name = _("Probe Templates") + + +class AnalyticsProbeTemplateForHostsList(GetNotAllowedMixin, AnalyticsGenericListView): + name = _("Probe Template For Hosts") + + +class AnalyticsRoiTemplatesList(GetNotAllowedMixin, AnalyticsGenericListView): + name = _("ROI Templates")