diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 871eb88f4c..c381f43b3b 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -464,7 +464,8 @@ class UnifiedJobTemplateSerializer(BaseSerializer): class UnifiedJobSerializer(BaseSerializer): - result_stdout = serializers.CharField(source='result_stdout', label='result stdout', read_only=True) + #result_stdout = serializers.CharField(source='result_stdout', label='result stdout', read_only=True) + result_stdout = serializers.SerializerMethodField('get_result_stdout') unified_job_template = serializers.Field(source='unified_job_template_id', label='unified job template') job_env = serializers.CharField(source='job_env', label='job env', read_only=True) @@ -475,6 +476,13 @@ class UnifiedJobSerializer(BaseSerializer): 'job_cwd', 'job_env', 'job_explanation', 'result_stdout', 'result_traceback') + + def get_result_stdout(self, obj): + obj_size = obj.result_stdout_size + if obj_size > settings.STDOUT_MAX_BYTES_DISPLAY: + return "Standard Output too large to display (%d bytes), only download supported for sizes over %d bytes" % (obj_size, settings.STDOUT_MAX_BYTES_DISPLAY) + return obj.result_stdout + def get_types(self): if type(self) is UnifiedJobSerializer: return ['project_update', 'inventory_update', 'job', 'ad_hoc_command', 'system_job'] diff --git a/awx/api/views.py b/awx/api/views.py index 3e5b7c89a2..69eed277b0 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -2109,11 +2109,20 @@ class JobList(ListCreateAPIView): model = Job serializer_class = JobListSerializer + def get_queryset(self): + qs = self.request.user.get_queryset(self.model).defer('result_stdout_text') + return qs + class JobDetail(RetrieveUpdateDestroyAPIView): model = Job serializer_class = JobSerializer + + def get_queryset(self): + qs = super(JobDetail, self).get_queryset().defer('result_stdout_text') + return qs + def update(self, request, *args, **kwargs): obj = self.get_object() # Only allow changes (PUT/PATCH) when job status is "new". @@ -2783,6 +2792,11 @@ class UnifiedJobList(ListAPIView): model = UnifiedJob serializer_class = UnifiedJobListSerializer new_in_148 = True + + def get_queryset(self): + qs = self.request.user.get_queryset(self.model).defer('result_stdout_text') + return qs + class UnifiedJobStdout(RetrieveAPIView): @@ -2793,8 +2807,17 @@ class UnifiedJobStdout(RetrieveAPIView): filter_backends = () new_in_148 = True + def get_queryset(self): + qs = super(UnifiedJobStdout, self).get_queryset().defer('result_stdout_text') + return qs + def retrieve(self, request, *args, **kwargs): unified_job = self.get_object() + obj_size = unified_job.result_stdout_size + if request.accepted_renderer.format != 'txt_download' and obj_size > settings.STDOUT_MAX_BYTES_DISPLAY: + return Response("Standard Output too large to display (%d bytes), " + "only download supported for sizes over %d bytes" % (obj_size, settings.STDOUT_MAX_BYTES_DISPLAY)) + if request.accepted_renderer.format in ('html', 'api', 'json'): start_line = request.QUERY_PARAMS.get('start_line', 0) end_line = request.QUERY_PARAMS.get('end_line', None) diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index a04ac2bdb0..f496c91afd 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -12,7 +12,7 @@ from StringIO import StringIO # Django from django.conf import settings -from django.db import models +from django.db import models, connection from django.core.exceptions import NON_FIELD_ERRORS from django.utils.datastructures import SortedDict from django.utils.translation import ugettext_lazy as _ @@ -657,6 +657,13 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique def result_stdout(self): return self._result_stdout_raw(escape_ascii=True) + @property + def result_stdout_size(self): + cursor = connection.cursor() + cursor.execute("select length(result_stdout_text) from main_unifiedjob where id = %d" % self.pk) + record_size = cursor.fetchone()[0] + return record_size + def _result_stdout_raw_limited(self, start_line=0, end_line=None, redact_sensitive=True, escape_ascii=False): return_buffer = u"" if end_line is not None: diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index dcfdebe2a2..88b184346f 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -562,6 +562,8 @@ FACT_CACHE_PORT = 6564 ORG_ADMINS_CAN_SEE_ALL_USERS = True +STDOUT_MAX_BYTES_DISPLAY = 1000000 + # Logging configuration. LOGGING = { 'version': 1,