mirror of
https://github.com/ansible/awx.git
synced 2026-01-09 15:02:07 -03:30
Add x-ai-description to schema (#16186)
Adding ansible_base.api_documentation to the INSTALL_APPS which extends the schema to include an LLM-friendly description to each endpoint --------- Signed-off-by: Seth Foster <fosterbseth@gmail.com> Co-authored-by: Peter Braun <pbraun@redhat.com>
This commit is contained in:
parent
4f41b50a09
commit
a20f299cd6
@ -1023,6 +1023,9 @@ class GenericCancelView(RetrieveAPIView):
|
||||
# In subclass set model, serializer_class
|
||||
obj_permission_type = 'cancel'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return super(GenericCancelView, self).get(request, *args, **kwargs)
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(GenericCancelView, self).dispatch(*args, **kwargs)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,8 @@ from rest_framework import status
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
AUTOMATION_ANALYTICS_API_URL_PATH = "/api/tower-analytics/v1"
|
||||
AWX_ANALYTICS_API_PREFIX = 'analytics'
|
||||
|
||||
@ -38,6 +40,8 @@ class MissingSettings(Exception):
|
||||
|
||||
|
||||
class GetNotAllowedMixin(object):
|
||||
skip_ai_description = True
|
||||
|
||||
def get(self, request, format=None):
|
||||
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||
|
||||
@ -46,7 +50,11 @@ class AnalyticsRootView(APIView):
|
||||
permission_classes = (AnalyticsPermission,)
|
||||
name = _('Automation Analytics')
|
||||
swagger_topic = 'Automation Analytics'
|
||||
resource_purpose = 'automation analytics endpoints'
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'Retrieve list of available analytics endpoints'},
|
||||
)
|
||||
def get(self, request, format=None):
|
||||
data = OrderedDict()
|
||||
data['authorized'] = reverse('api:analytics_authorized', request=request)
|
||||
@ -99,6 +107,8 @@ class AnalyticsGenericView(APIView):
|
||||
return Response(response.json(), status=response.status_code)
|
||||
"""
|
||||
|
||||
resource_purpose = 'base view for analytics api proxy'
|
||||
|
||||
permission_classes = (AnalyticsPermission,)
|
||||
|
||||
@staticmethod
|
||||
@ -257,67 +267,91 @@ class AnalyticsGenericView(APIView):
|
||||
|
||||
|
||||
class AnalyticsGenericListView(AnalyticsGenericView):
|
||||
resource_purpose = 'analytics api proxy list view'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get analytics data from Red Hat Insights"})
|
||||
def get(self, request, format=None):
|
||||
return self._send_to_analytics(request, method="GET")
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Post query to Red Hat Insights analytics"})
|
||||
def post(self, request, format=None):
|
||||
return self._send_to_analytics(request, method="POST")
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get analytics endpoint options"})
|
||||
def options(self, request, format=None):
|
||||
return self._send_to_analytics(request, method="OPTIONS")
|
||||
|
||||
|
||||
class AnalyticsGenericDetailView(AnalyticsGenericView):
|
||||
resource_purpose = 'analytics api proxy detail view'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get specific analytics resource from Red Hat Insights"})
|
||||
def get(self, request, slug, format=None):
|
||||
return self._send_to_analytics(request, method="GET")
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Post query for specific analytics resource to Red Hat Insights"})
|
||||
def post(self, request, slug, format=None):
|
||||
return self._send_to_analytics(request, method="POST")
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get options for specific analytics resource"})
|
||||
def options(self, request, slug, format=None):
|
||||
return self._send_to_analytics(request, method="OPTIONS")
|
||||
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'Check if the user has access to Red Hat Insights'},
|
||||
)
|
||||
class AnalyticsAuthorizedView(AnalyticsGenericListView):
|
||||
name = _("Authorized")
|
||||
resource_purpose = 'red hat insights authorization status'
|
||||
|
||||
|
||||
class AnalyticsReportsList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("Reports")
|
||||
swagger_topic = "Automation Analytics"
|
||||
resource_purpose = 'automation analytics reports'
|
||||
|
||||
|
||||
class AnalyticsReportDetail(AnalyticsGenericDetailView):
|
||||
name = _("Report")
|
||||
resource_purpose = 'automation analytics report detail'
|
||||
|
||||
|
||||
class AnalyticsReportOptionsList(AnalyticsGenericListView):
|
||||
name = _("Report Options")
|
||||
resource_purpose = 'automation analytics report options'
|
||||
|
||||
|
||||
class AnalyticsAdoptionRateList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("Adoption Rate")
|
||||
resource_purpose = 'automation analytics adoption rate data'
|
||||
|
||||
|
||||
class AnalyticsEventExplorerList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("Event Explorer")
|
||||
resource_purpose = 'automation analytics event explorer data'
|
||||
|
||||
|
||||
class AnalyticsHostExplorerList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("Host Explorer")
|
||||
resource_purpose = 'automation analytics host explorer data'
|
||||
|
||||
|
||||
class AnalyticsJobExplorerList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("Job Explorer")
|
||||
resource_purpose = 'automation analytics job explorer data'
|
||||
|
||||
|
||||
class AnalyticsProbeTemplatesList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("Probe Templates")
|
||||
resource_purpose = 'automation analytics probe templates'
|
||||
|
||||
|
||||
class AnalyticsProbeTemplateForHostsList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("Probe Template For Hosts")
|
||||
resource_purpose = 'automation analytics probe templates for hosts'
|
||||
|
||||
|
||||
class AnalyticsRoiTemplatesList(GetNotAllowedMixin, AnalyticsGenericListView):
|
||||
name = _("ROI Templates")
|
||||
resource_purpose = 'automation analytics roi templates'
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
@ -30,6 +32,7 @@ class BulkView(APIView):
|
||||
]
|
||||
allowed_methods = ['GET', 'OPTIONS']
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Retrieves a list of available bulk actions"})
|
||||
def get(self, request, format=None):
|
||||
'''List top level resources'''
|
||||
data = OrderedDict()
|
||||
@ -45,11 +48,13 @@ class BulkJobLaunchView(GenericAPIView):
|
||||
serializer_class = serializers.BulkJobLaunchSerializer
|
||||
allowed_methods = ['GET', 'POST', 'OPTIONS']
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get information about bulk job launch endpoint"})
|
||||
def get(self, request):
|
||||
data = OrderedDict()
|
||||
data['detail'] = "Specify a list of unified job templates to launch alongside their launchtime parameters"
|
||||
return Response(data, status=status.HTTP_200_OK)
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Bulk launch job templates"})
|
||||
def post(self, request):
|
||||
bulkjob_serializer = serializers.BulkJobLaunchSerializer(data=request.data, context={'request': request})
|
||||
if bulkjob_serializer.is_valid():
|
||||
@ -64,9 +69,11 @@ class BulkHostCreateView(GenericAPIView):
|
||||
serializer_class = serializers.BulkHostCreateSerializer
|
||||
allowed_methods = ['GET', 'POST', 'OPTIONS']
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get information about bulk host create endpoint"})
|
||||
def get(self, request):
|
||||
return Response({"detail": "Bulk create hosts with this endpoint"}, status=status.HTTP_200_OK)
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Bulk create hosts"})
|
||||
def post(self, request):
|
||||
serializer = serializers.BulkHostCreateSerializer(data=request.data, context={'request': request})
|
||||
if serializer.is_valid():
|
||||
@ -81,9 +88,11 @@ class BulkHostDeleteView(GenericAPIView):
|
||||
serializer_class = serializers.BulkHostDeleteSerializer
|
||||
allowed_methods = ['GET', 'POST', 'OPTIONS']
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get information about bulk host delete endpoint"})
|
||||
def get(self, request):
|
||||
return Response({"detail": "Bulk delete hosts with this endpoint"}, status=status.HTTP_200_OK)
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Bulk delete hosts"})
|
||||
def post(self, request):
|
||||
serializer = serializers.BulkHostDeleteSerializer(data=request.data, context={'request': request})
|
||||
if serializer.is_valid():
|
||||
|
||||
@ -5,6 +5,7 @@ from django.conf import settings
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.response import Response
|
||||
from awx.api.generics import APIView
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
from awx.main.scheduler import TaskManager, DependencyManager, WorkflowManager
|
||||
|
||||
@ -14,7 +15,9 @@ class TaskManagerDebugView(APIView):
|
||||
exclude_from_schema = True
|
||||
permission_classes = [AllowAny]
|
||||
prefix = 'Task'
|
||||
resource_purpose = 'debug task manager'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Trigger task manager scheduling"})
|
||||
def get(self, request):
|
||||
TaskManager().schedule()
|
||||
if not settings.AWX_DISABLE_TASK_MANAGERS:
|
||||
@ -29,7 +32,9 @@ class DependencyManagerDebugView(APIView):
|
||||
exclude_from_schema = True
|
||||
permission_classes = [AllowAny]
|
||||
prefix = 'Dependency'
|
||||
resource_purpose = 'debug dependency manager'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Trigger dependency manager scheduling"})
|
||||
def get(self, request):
|
||||
DependencyManager().schedule()
|
||||
if not settings.AWX_DISABLE_TASK_MANAGERS:
|
||||
@ -44,7 +49,9 @@ class WorkflowManagerDebugView(APIView):
|
||||
exclude_from_schema = True
|
||||
permission_classes = [AllowAny]
|
||||
prefix = 'Workflow'
|
||||
resource_purpose = 'debug workflow manager'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Trigger workflow manager scheduling"})
|
||||
def get(self, request):
|
||||
WorkflowManager().schedule()
|
||||
if not settings.AWX_DISABLE_TASK_MANAGERS:
|
||||
@ -58,7 +65,9 @@ class DebugRootView(APIView):
|
||||
_ignore_model_permissions = True
|
||||
exclude_from_schema = True
|
||||
permission_classes = [AllowAny]
|
||||
resource_purpose = 'debug endpoints root'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "List available debug endpoints"})
|
||||
def get(self, request, format=None):
|
||||
'''List of available debug urls'''
|
||||
data = OrderedDict()
|
||||
|
||||
@ -10,6 +10,7 @@ import time
|
||||
import re
|
||||
|
||||
import asn1
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
from awx.api import serializers
|
||||
from awx.api.generics import GenericAPIView, Response
|
||||
from awx.api.permissions import IsSystemAdmin
|
||||
@ -49,7 +50,9 @@ class InstanceInstallBundle(GenericAPIView):
|
||||
model = models.Instance
|
||||
serializer_class = serializers.InstanceSerializer
|
||||
permission_classes = (IsSystemAdmin,)
|
||||
resource_purpose = 'install bundle'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Generate and download install bundle for an instance"})
|
||||
def get(self, request, *args, **kwargs):
|
||||
instance_obj = self.get_object()
|
||||
|
||||
|
||||
@ -19,6 +19,8 @@ from rest_framework import serializers
|
||||
# AWX
|
||||
from awx.main.models import ActivityStream, Inventory, JobTemplate, Role, User, InstanceGroup, InventoryUpdateEvent, InventoryUpdate
|
||||
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
from awx.api.generics import (
|
||||
ListCreateAPIView,
|
||||
RetrieveUpdateDestroyAPIView,
|
||||
@ -55,6 +57,7 @@ class InventoryUpdateEventsList(SubListAPIView):
|
||||
name = _('Inventory Update Events List')
|
||||
search_fields = ('stdout',)
|
||||
pagination_class = UnifiedJobEventPagination
|
||||
resource_purpose = 'events of an inventory update'
|
||||
|
||||
def get_queryset(self):
|
||||
iu = self.get_parent_object()
|
||||
@ -69,11 +72,13 @@ class InventoryUpdateEventsList(SubListAPIView):
|
||||
class InventoryList(ListCreateAPIView):
|
||||
model = Inventory
|
||||
serializer_class = InventorySerializer
|
||||
resource_purpose = 'inventories'
|
||||
|
||||
|
||||
class InventoryDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAPIView):
|
||||
model = Inventory
|
||||
serializer_class = InventorySerializer
|
||||
resource_purpose = 'inventory detail'
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
@ -100,33 +105,39 @@ class InventoryDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAPIVie
|
||||
|
||||
class ConstructedInventoryDetail(InventoryDetail):
|
||||
serializer_class = ConstructedInventorySerializer
|
||||
resource_purpose = 'constructed inventory detail'
|
||||
|
||||
|
||||
class ConstructedInventoryList(InventoryList):
|
||||
serializer_class = ConstructedInventorySerializer
|
||||
resource_purpose = 'constructed inventories'
|
||||
|
||||
def get_queryset(self):
|
||||
r = super().get_queryset()
|
||||
return r.filter(kind='constructed')
|
||||
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get or create input inventory inventory"})
|
||||
class InventoryInputInventoriesList(SubListAttachDetachAPIView):
|
||||
model = Inventory
|
||||
serializer_class = InventorySerializer
|
||||
parent_model = Inventory
|
||||
relationship = 'input_inventories'
|
||||
resource_purpose = 'input inventories of a constructed inventory'
|
||||
|
||||
def is_valid_relation(self, parent, sub, created=False):
|
||||
if sub.kind == 'constructed':
|
||||
raise serializers.ValidationError({'error': 'You cannot add a constructed inventory to another constructed inventory.'})
|
||||
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get activity stream for an inventory"})
|
||||
class InventoryActivityStreamList(SubListAPIView):
|
||||
model = ActivityStream
|
||||
serializer_class = ActivityStreamSerializer
|
||||
parent_model = Inventory
|
||||
relationship = 'activitystream_set'
|
||||
search_fields = ('changes',)
|
||||
resource_purpose = 'activity stream for an inventory'
|
||||
|
||||
def get_queryset(self):
|
||||
parent = self.get_parent_object()
|
||||
@ -140,11 +151,13 @@ class InventoryInstanceGroupsList(SubListAttachDetachAPIView):
|
||||
serializer_class = InstanceGroupSerializer
|
||||
parent_model = Inventory
|
||||
relationship = 'instance_groups'
|
||||
resource_purpose = 'instance groups of an inventory'
|
||||
|
||||
|
||||
class InventoryAccessList(ResourceAccessList):
|
||||
model = User # needs to be User for AccessLists's
|
||||
parent_model = Inventory
|
||||
resource_purpose = 'users who can access the inventory'
|
||||
|
||||
|
||||
class InventoryObjectRolesList(SubListAPIView):
|
||||
@ -153,6 +166,7 @@ class InventoryObjectRolesList(SubListAPIView):
|
||||
parent_model = Inventory
|
||||
search_fields = ('role_field', 'content_type__model')
|
||||
deprecated = True
|
||||
resource_purpose = 'roles of an inventory'
|
||||
|
||||
def get_queryset(self):
|
||||
po = self.get_parent_object()
|
||||
@ -165,6 +179,7 @@ class InventoryJobTemplateList(SubListAPIView):
|
||||
serializer_class = JobTemplateSerializer
|
||||
parent_model = Inventory
|
||||
relationship = 'jobtemplates'
|
||||
resource_purpose = 'job templates using an inventory'
|
||||
|
||||
def get_queryset(self):
|
||||
parent = self.get_parent_object()
|
||||
@ -175,8 +190,10 @@ class InventoryJobTemplateList(SubListAPIView):
|
||||
|
||||
class InventoryLabelList(LabelSubListCreateAttachDetachView):
|
||||
parent_model = Inventory
|
||||
resource_purpose = 'labels of an inventory'
|
||||
|
||||
|
||||
class InventoryCopy(CopyAPIView):
|
||||
model = Inventory
|
||||
copy_return_serializer_class = InventorySerializer
|
||||
resource_purpose = 'copy of an inventory'
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
from awx.api.generics import SubListCreateAttachDetachAPIView, RetrieveUpdateAPIView, ListCreateAPIView
|
||||
from awx.main.models import Label
|
||||
from awx.api.serializers import LabelSerializer
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
# Django
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -24,6 +25,7 @@ class LabelSubListCreateAttachDetachView(SubListCreateAttachDetachAPIView):
|
||||
model = Label
|
||||
serializer_class = LabelSerializer
|
||||
relationship = 'labels'
|
||||
resource_purpose = 'labels of a resource'
|
||||
|
||||
def unattach(self, request, *args, **kwargs):
|
||||
(sub_id, res) = super().unattach_validate(request)
|
||||
@ -39,6 +41,7 @@ class LabelSubListCreateAttachDetachView(SubListCreateAttachDetachAPIView):
|
||||
|
||||
return res
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Create or attach a label to a resource"})
|
||||
def post(self, request, *args, **kwargs):
|
||||
# If a label already exists in the database, attach it instead of erroring out
|
||||
# that it already exists
|
||||
@ -61,9 +64,11 @@ class LabelSubListCreateAttachDetachView(SubListCreateAttachDetachAPIView):
|
||||
class LabelDetail(RetrieveUpdateAPIView):
|
||||
model = Label
|
||||
serializer_class = LabelSerializer
|
||||
resource_purpose = 'label detail'
|
||||
|
||||
|
||||
class LabelList(ListCreateAPIView):
|
||||
name = _("Labels")
|
||||
model = Label
|
||||
serializer_class = LabelSerializer
|
||||
resource_purpose = 'labels'
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
# All Rights Reserved.
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
from awx.api.generics import APIView, Response
|
||||
from awx.api.permissions import IsSystemAdminOrAuditor
|
||||
@ -13,7 +14,9 @@ class MeshVisualizer(APIView):
|
||||
name = _("Mesh Visualizer")
|
||||
permission_classes = (IsSystemAdminOrAuditor,)
|
||||
swagger_topic = "System Configuration"
|
||||
resource_purpose = 'mesh network topology visualization data'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get mesh network topology visualization data"})
|
||||
def get(self, request, format=None):
|
||||
data = {
|
||||
'nodes': InstanceNodeSerializer(Instance.objects.all(), many=True).data,
|
||||
|
||||
@ -7,6 +7,7 @@ import logging
|
||||
# Django
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
# Django REST Framework
|
||||
from rest_framework.permissions import AllowAny
|
||||
@ -29,6 +30,7 @@ logger = logging.getLogger('awx.analytics')
|
||||
class MetricsView(APIView):
|
||||
name = _('Metrics')
|
||||
swagger_topic = 'Metrics'
|
||||
resource_purpose = 'prometheus metrics data'
|
||||
|
||||
renderer_classes = [renderers.PlainTextRenderer, renderers.PrometheusJSONRenderer, renderers.BrowsableAPIRenderer]
|
||||
|
||||
@ -37,6 +39,7 @@ class MetricsView(APIView):
|
||||
self.permission_classes = (AllowAny,)
|
||||
return super(APIView, self).initialize_request(request, *args, **kwargs)
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get Prometheus metrics data"})
|
||||
def get(self, request):
|
||||
'''Show Metrics Details'''
|
||||
if settings.ALLOW_METRICS_FOR_ANONYMOUS_USERS or request.user.is_superuser or request.user.is_system_auditor:
|
||||
|
||||
@ -60,11 +60,13 @@ logger = logging.getLogger('awx.api.views.organization')
|
||||
class OrganizationList(OrganizationCountsMixin, ListCreateAPIView):
|
||||
model = Organization
|
||||
serializer_class = OrganizationSerializer
|
||||
resource_purpose = 'organizations'
|
||||
|
||||
|
||||
class OrganizationDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAPIView):
|
||||
model = Organization
|
||||
serializer_class = OrganizationSerializer
|
||||
resource_purpose = 'organization detail'
|
||||
|
||||
def get_serializer_context(self, *args, **kwargs):
|
||||
full_context = super(OrganizationDetail, self).get_serializer_context(*args, **kwargs)
|
||||
@ -102,6 +104,7 @@ class OrganizationInventoriesList(SubListAPIView):
|
||||
serializer_class = InventorySerializer
|
||||
parent_model = Organization
|
||||
relationship = 'inventories'
|
||||
resource_purpose = 'inventories of an organization'
|
||||
|
||||
|
||||
class OrganizationUsersList(BaseUsersList):
|
||||
@ -110,6 +113,7 @@ class OrganizationUsersList(BaseUsersList):
|
||||
parent_model = Organization
|
||||
relationship = 'member_role.members'
|
||||
ordering = ('username',)
|
||||
resource_purpose = 'users of an organization'
|
||||
|
||||
|
||||
class OrganizationAdminsList(BaseUsersList):
|
||||
@ -118,6 +122,7 @@ class OrganizationAdminsList(BaseUsersList):
|
||||
parent_model = Organization
|
||||
relationship = 'admin_role.members'
|
||||
ordering = ('username',)
|
||||
resource_purpose = 'administrators of an organization'
|
||||
|
||||
|
||||
class OrganizationProjectsList(SubListCreateAPIView):
|
||||
@ -125,6 +130,7 @@ class OrganizationProjectsList(SubListCreateAPIView):
|
||||
serializer_class = ProjectSerializer
|
||||
parent_model = Organization
|
||||
parent_key = 'organization'
|
||||
resource_purpose = 'projects of an organization'
|
||||
|
||||
|
||||
class OrganizationExecutionEnvironmentsList(SubListCreateAttachDetachAPIView):
|
||||
@ -134,6 +140,7 @@ class OrganizationExecutionEnvironmentsList(SubListCreateAttachDetachAPIView):
|
||||
relationship = 'executionenvironments'
|
||||
parent_key = 'organization'
|
||||
swagger_topic = "Execution Environments"
|
||||
resource_purpose = 'execution environments of an organization'
|
||||
|
||||
|
||||
class OrganizationJobTemplatesList(SubListCreateAPIView):
|
||||
@ -141,6 +148,7 @@ class OrganizationJobTemplatesList(SubListCreateAPIView):
|
||||
serializer_class = JobTemplateSerializer
|
||||
parent_model = Organization
|
||||
parent_key = 'organization'
|
||||
resource_purpose = 'job templates of an organization'
|
||||
|
||||
|
||||
class OrganizationWorkflowJobTemplatesList(SubListCreateAPIView):
|
||||
@ -148,6 +156,7 @@ class OrganizationWorkflowJobTemplatesList(SubListCreateAPIView):
|
||||
serializer_class = WorkflowJobTemplateSerializer
|
||||
parent_model = Organization
|
||||
parent_key = 'organization'
|
||||
resource_purpose = 'workflow job templates of an organization'
|
||||
|
||||
|
||||
class OrganizationTeamsList(SubListCreateAttachDetachAPIView):
|
||||
@ -156,6 +165,7 @@ class OrganizationTeamsList(SubListCreateAttachDetachAPIView):
|
||||
parent_model = Organization
|
||||
relationship = 'teams'
|
||||
parent_key = 'organization'
|
||||
resource_purpose = 'teams of an organization'
|
||||
|
||||
|
||||
class OrganizationActivityStreamList(SubListAPIView):
|
||||
@ -164,6 +174,7 @@ class OrganizationActivityStreamList(SubListAPIView):
|
||||
parent_model = Organization
|
||||
relationship = 'activitystream_set'
|
||||
search_fields = ('changes',)
|
||||
resource_purpose = 'activity stream for an organization'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesList(SubListCreateAttachDetachAPIView):
|
||||
@ -172,28 +183,34 @@ class OrganizationNotificationTemplatesList(SubListCreateAttachDetachAPIView):
|
||||
parent_model = Organization
|
||||
relationship = 'notification_templates'
|
||||
parent_key = 'organization'
|
||||
resource_purpose = 'notification templates of an organization'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView):
|
||||
model = NotificationTemplate
|
||||
serializer_class = NotificationTemplateSerializer
|
||||
parent_model = Organization
|
||||
resource_purpose = 'base view for notification templates of an organization'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesStartedList(OrganizationNotificationTemplatesAnyList):
|
||||
relationship = 'notification_templates_started'
|
||||
resource_purpose = 'notification templates for job started events of an organization'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesErrorList(OrganizationNotificationTemplatesAnyList):
|
||||
relationship = 'notification_templates_error'
|
||||
resource_purpose = 'notification templates for job error events of an organization'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesSuccessList(OrganizationNotificationTemplatesAnyList):
|
||||
relationship = 'notification_templates_success'
|
||||
resource_purpose = 'notification templates for job success events of an organization'
|
||||
|
||||
|
||||
class OrganizationNotificationTemplatesApprovalList(OrganizationNotificationTemplatesAnyList):
|
||||
relationship = 'notification_templates_approvals'
|
||||
resource_purpose = 'notification templates for workflow approval events of an organization'
|
||||
|
||||
|
||||
class OrganizationInstanceGroupsList(OrganizationInstanceGroupMembershipMixin, SubListAttachDetachAPIView):
|
||||
@ -202,6 +219,7 @@ class OrganizationInstanceGroupsList(OrganizationInstanceGroupMembershipMixin, S
|
||||
parent_model = Organization
|
||||
relationship = 'instance_groups'
|
||||
filter_read_permission = False
|
||||
resource_purpose = 'instance groups of an organization'
|
||||
|
||||
|
||||
class OrganizationGalaxyCredentialsList(SubListAttachDetachAPIView):
|
||||
@ -210,6 +228,7 @@ class OrganizationGalaxyCredentialsList(SubListAttachDetachAPIView):
|
||||
parent_model = Organization
|
||||
relationship = 'galaxy_credentials'
|
||||
filter_read_permission = False
|
||||
resource_purpose = 'galaxy credentials of an organization'
|
||||
|
||||
def is_valid_relation(self, parent, sub, created=False):
|
||||
if sub.kind != 'galaxy_api_token':
|
||||
@ -219,6 +238,7 @@ class OrganizationGalaxyCredentialsList(SubListAttachDetachAPIView):
|
||||
class OrganizationAccessList(ResourceAccessList):
|
||||
model = User # needs to be User for AccessLists's
|
||||
parent_model = Organization
|
||||
resource_purpose = 'users who can access the organization'
|
||||
|
||||
|
||||
class OrganizationObjectRolesList(SubListAPIView):
|
||||
@ -227,6 +247,7 @@ class OrganizationObjectRolesList(SubListAPIView):
|
||||
parent_model = Organization
|
||||
search_fields = ('role_field', 'content_type__model')
|
||||
deprecated = True
|
||||
resource_purpose = 'roles of an organization'
|
||||
|
||||
def get_queryset(self):
|
||||
po = self.get_parent_object()
|
||||
|
||||
@ -23,6 +23,8 @@ from rest_framework import status
|
||||
|
||||
import requests
|
||||
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
from awx import MODE
|
||||
from awx.api.generics import APIView
|
||||
from awx.conf.registry import settings_registry
|
||||
@ -46,8 +48,10 @@ class ApiRootView(APIView):
|
||||
name = _('REST API')
|
||||
versioning_class = URLPathVersioning
|
||||
swagger_topic = 'Versioning'
|
||||
resource_purpose = 'api root and version information'
|
||||
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "List supported API versions"})
|
||||
def get(self, request, format=None):
|
||||
'''List supported API versions'''
|
||||
v2 = reverse('api:api_v2_root_view', request=request, kwargs={'version': 'v2'})
|
||||
@ -66,7 +70,9 @@ class ApiRootView(APIView):
|
||||
class ApiVersionRootView(APIView):
|
||||
permission_classes = (AllowAny,)
|
||||
swagger_topic = 'Versioning'
|
||||
resource_purpose = 'api top-level resources'
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "List top-level API resources"})
|
||||
def get(self, request, format=None):
|
||||
'''List top level resources'''
|
||||
data = OrderedDict()
|
||||
@ -126,6 +132,7 @@ class ApiVersionRootView(APIView):
|
||||
|
||||
class ApiV2RootView(ApiVersionRootView):
|
||||
name = _('Version 2')
|
||||
resource_purpose = 'api v2 root'
|
||||
|
||||
|
||||
class ApiV2PingView(APIView):
|
||||
@ -137,7 +144,11 @@ class ApiV2PingView(APIView):
|
||||
authentication_classes = ()
|
||||
name = _('Ping')
|
||||
swagger_topic = 'System Configuration'
|
||||
resource_purpose = 'basic instance information'
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'Return basic information about this instance'},
|
||||
)
|
||||
def get(self, request, format=None):
|
||||
"""Return some basic information about this instance
|
||||
|
||||
@ -172,12 +183,16 @@ class ApiV2SubscriptionView(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
name = _('Subscriptions')
|
||||
swagger_topic = 'System Configuration'
|
||||
resource_purpose = 'aap subscription validation'
|
||||
|
||||
def check_permissions(self, request):
|
||||
super(ApiV2SubscriptionView, self).check_permissions(request)
|
||||
if not request.user.is_superuser and request.method.lower() not in {'options', 'head'}:
|
||||
self.permission_denied(request) # Raises PermissionDenied exception.
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'List valid AAP subscriptions'},
|
||||
)
|
||||
def post(self, request):
|
||||
data = request.data.copy()
|
||||
|
||||
@ -244,12 +259,16 @@ class ApiV2AttachView(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
name = _('Attach Subscription')
|
||||
swagger_topic = 'System Configuration'
|
||||
resource_purpose = 'subscription attachment'
|
||||
|
||||
def check_permissions(self, request):
|
||||
super(ApiV2AttachView, self).check_permissions(request)
|
||||
if not request.user.is_superuser and request.method.lower() not in {'options', 'head'}:
|
||||
self.permission_denied(request) # Raises PermissionDenied exception.
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'Attach a subscription'},
|
||||
)
|
||||
def post(self, request):
|
||||
data = request.data.copy()
|
||||
subscription_id = data.get('subscription_id', None)
|
||||
@ -299,12 +318,16 @@ class ApiV2ConfigView(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
name = _('Configuration')
|
||||
swagger_topic = 'System Configuration'
|
||||
resource_purpose = 'system configuration and license management'
|
||||
|
||||
def check_permissions(self, request):
|
||||
super(ApiV2ConfigView, self).check_permissions(request)
|
||||
if not request.user.is_superuser and request.method.lower() not in {'options', 'head', 'get'}:
|
||||
self.permission_denied(request) # Raises PermissionDenied exception.
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'Return various configuration settings'},
|
||||
)
|
||||
def get(self, request, format=None):
|
||||
'''Return various sitewide configuration settings'''
|
||||
|
||||
@ -343,6 +366,9 @@ class ApiV2ConfigView(APIView):
|
||||
|
||||
return Response(data)
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'Upload a subscription manifest'},
|
||||
)
|
||||
def post(self, request):
|
||||
if not isinstance(request.data, dict):
|
||||
return Response({"error": _("Invalid subscription data")}, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -388,6 +414,9 @@ class ApiV2ConfigView(APIView):
|
||||
logger.warning(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
||||
return Response({"error": _("Invalid subscription")}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@extend_schema_if_available(
|
||||
extensions={'x-ai-description': 'Remove the current subscription'},
|
||||
)
|
||||
def delete(self, request):
|
||||
try:
|
||||
settings.LICENSE = {}
|
||||
|
||||
@ -11,6 +11,7 @@ from rest_framework import status
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.response import Response
|
||||
from ansible_base.lib.utils.schema import extend_schema_if_available
|
||||
|
||||
from awx.api import serializers
|
||||
from awx.api.generics import APIView, GenericAPIView
|
||||
@ -24,6 +25,7 @@ logger = logging.getLogger('awx.api.views.webhooks')
|
||||
class WebhookKeyView(GenericAPIView):
|
||||
serializer_class = serializers.EmptySerializer
|
||||
permission_classes = (WebhookKeyPermission,)
|
||||
resource_purpose = 'webhook key management'
|
||||
|
||||
def get_queryset(self):
|
||||
qs_models = {'job_templates': JobTemplate, 'workflow_job_templates': WorkflowJobTemplate}
|
||||
@ -31,11 +33,13 @@ class WebhookKeyView(GenericAPIView):
|
||||
|
||||
return super().get_queryset()
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Get the webhook key for a template"})
|
||||
def get(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
|
||||
return Response({'webhook_key': obj.webhook_key})
|
||||
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Rotate the webhook key for a template"})
|
||||
def post(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
obj.rotate_webhook_key()
|
||||
@ -52,6 +56,7 @@ class WebhookReceiverBase(APIView):
|
||||
authentication_classes = ()
|
||||
|
||||
ref_keys = {}
|
||||
resource_purpose = 'webhook receiver for triggering jobs'
|
||||
|
||||
def get_queryset(self):
|
||||
qs_models = {'job_templates': JobTemplate, 'workflow_job_templates': WorkflowJobTemplate}
|
||||
@ -127,6 +132,7 @@ class WebhookReceiverBase(APIView):
|
||||
raise PermissionDenied
|
||||
|
||||
@csrf_exempt
|
||||
@extend_schema_if_available(extensions={"x-ai-description": "Receive a webhook event and trigger a job"})
|
||||
def post(self, request, *args, **kwargs):
|
||||
# Ensure that the full contents of the request are captured for multiple uses.
|
||||
request.body
|
||||
@ -175,6 +181,7 @@ class WebhookReceiverBase(APIView):
|
||||
|
||||
class GithubWebhookReceiver(WebhookReceiverBase):
|
||||
service = 'github'
|
||||
resource_purpose = 'github webhook receiver'
|
||||
|
||||
ref_keys = {
|
||||
'pull_request': 'pull_request.head.sha',
|
||||
@ -212,6 +219,7 @@ class GithubWebhookReceiver(WebhookReceiverBase):
|
||||
|
||||
class GitlabWebhookReceiver(WebhookReceiverBase):
|
||||
service = 'gitlab'
|
||||
resource_purpose = 'gitlab webhook receiver'
|
||||
|
||||
ref_keys = {'Push Hook': 'checkout_sha', 'Tag Push Hook': 'checkout_sha', 'Merge Request Hook': 'object_attributes.last_commit.id'}
|
||||
|
||||
@ -250,6 +258,7 @@ class GitlabWebhookReceiver(WebhookReceiverBase):
|
||||
|
||||
class BitbucketDcWebhookReceiver(WebhookReceiverBase):
|
||||
service = 'bitbucket_dc'
|
||||
resource_purpose = 'bitbucket data center webhook receiver'
|
||||
|
||||
ref_keys = {
|
||||
'repo:refs_changed': 'changes.0.toHash',
|
||||
|
||||
@ -352,6 +352,7 @@ INSTALLED_APPS = [
|
||||
'ansible_base.resource_registry',
|
||||
'ansible_base.rbac',
|
||||
'ansible_base.feature_flags',
|
||||
'ansible_base.api_documentation',
|
||||
'flags',
|
||||
]
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user