mirror of
https://github.com/ansible/awx.git
synced 2026-05-12 11:57:37 -02:30
Efficient stdout downloader implementation
* Temporarily dump stdout contents to a configurable temp location * Implement file streaming to the host via a new format specifier in the api view
This commit is contained in:
@@ -25,6 +25,8 @@ from django.utils.safestring import mark_safe
|
|||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
from django.core.servers.basehttp import FileWrapper
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.exceptions import PermissionDenied, ParseError
|
from rest_framework.exceptions import PermissionDenied, ParseError
|
||||||
@@ -2844,9 +2846,10 @@ class UnifiedJobStdout(RetrieveAPIView):
|
|||||||
elif request.accepted_renderer.format == 'ansi':
|
elif request.accepted_renderer.format == 'ansi':
|
||||||
return Response(unified_job.result_stdout_raw)
|
return Response(unified_job.result_stdout_raw)
|
||||||
elif request.accepted_renderer.format == 'txt_download':
|
elif request.accepted_renderer.format == 'txt_download':
|
||||||
content = unified_job.result_stdout
|
content_fd = open(unified_job.dump_result_stdout(), 'r')
|
||||||
headers = {"Content-Disposition": 'attachment; filename="job_%s.txt"' % str(unified_job.id)}
|
response = HttpResponse(FileWrapper(content_fd), content_type='text/plain')
|
||||||
return Response(content, headers=headers)
|
response["Content-Disposition"] = 'attachment; filename="job_%s.txt"' % str(unified_job.id)
|
||||||
|
return response
|
||||||
else:
|
else:
|
||||||
return super(UnifiedJobStdout, self).retrieve(request, *args, **kwargs)
|
return super(UnifiedJobStdout, self).retrieve(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import codecs
|
import codecs
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import uuid
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
@@ -664,6 +665,15 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
|||||||
record_size = cursor.fetchone()[0]
|
record_size = cursor.fetchone()[0]
|
||||||
return record_size
|
return record_size
|
||||||
|
|
||||||
|
def dump_result_stdout(self):
|
||||||
|
tower_file = "towerjob-%s" % str(uuid.uuid1())[:8]
|
||||||
|
out_path = os.path.join(settings.STDOUT_TEMP_DIR, tower_file)
|
||||||
|
tower_fd = open(out_path, 'w')
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.copy_expert("copy (select result_stdout_text from main_unifiedjob where id = %d) to stdout" % (self.pk), tower_fd)
|
||||||
|
tower_fd.close()
|
||||||
|
return out_path
|
||||||
|
|
||||||
def _result_stdout_raw_limited(self, start_line=0, end_line=None, redact_sensitive=True, escape_ascii=False):
|
def _result_stdout_raw_limited(self, start_line=0, end_line=None, redact_sensitive=True, escape_ascii=False):
|
||||||
return_buffer = u""
|
return_buffer = u""
|
||||||
if end_line is not None:
|
if end_line is not None:
|
||||||
|
|||||||
@@ -563,6 +563,7 @@ FACT_CACHE_PORT = 6564
|
|||||||
ORG_ADMINS_CAN_SEE_ALL_USERS = True
|
ORG_ADMINS_CAN_SEE_ALL_USERS = True
|
||||||
|
|
||||||
STDOUT_MAX_BYTES_DISPLAY = 1000000
|
STDOUT_MAX_BYTES_DISPLAY = 1000000
|
||||||
|
STDOUT_TEMP_DIR = "/tmp"
|
||||||
|
|
||||||
# Logging configuration.
|
# Logging configuration.
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
|
|||||||
Reference in New Issue
Block a user