From a803cedd7ce3d5534ae9be524e7b098678f17dab Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Thu, 10 Oct 2019 16:07:08 -0400 Subject: [PATCH] Break out a new reusable truncate_stdout utility function --- awx/api/serializers.py | 42 ++++++++++++-------------------------- awx/main/utils/common.py | 44 +++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 14d8944dc1..a5bdad1c39 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -45,7 +45,6 @@ from polymorphic.models import PolymorphicModel from awx.main.access import get_user_capabilities from awx.main.constants import ( SCHEDULEABLE_PROVIDERS, - ANSI_SGR_PATTERN, ACTIVE_STATES, CENSOR_VALUE, ) @@ -70,7 +69,8 @@ from awx.main.utils import ( get_type_for_model, get_model_for_type, camelcase_to_underscore, getattrd, parse_yaml_or_json, has_model_field_prefetched, extract_ansible_vars, encrypt_dict, - prefetch_page_capabilities, get_external_account) + prefetch_page_capabilities, get_external_account, truncate_stdout, +) from awx.main.utils.filters import SmartFilter from awx.main.redact import UriCleaner, REPLACE_STR @@ -3851,25 +3851,17 @@ class JobEventSerializer(BaseSerializer): return d def to_representation(self, obj): - ret = super(JobEventSerializer, self).to_representation(obj) + data = super(JobEventSerializer, self).to_representation(obj) # Show full stdout for event detail view, truncate only for list view. if hasattr(self.context.get('view', None), 'retrieve'): - return ret + return data # Show full stdout for playbook_on_* events. if obj and obj.event.startswith('playbook_on'): - return ret + return data max_bytes = settings.EVENT_STDOUT_MAX_BYTES_DISPLAY - if max_bytes > 0 and 'stdout' in ret and len(ret['stdout']) >= max_bytes: - ret['stdout'] = ret['stdout'][:(max_bytes - 1)] + u'\u2026' - set_count = 0 - reset_count = 0 - for m in ANSI_SGR_PATTERN.finditer(ret['stdout']): - if m.string[m.start():m.end()] == u'\u001b[0m': - reset_count += 1 - else: - set_count += 1 - ret['stdout'] += u'\u001b[0m' * (set_count - reset_count) - return ret + if 'stdout' in data: + data['stdout'] = truncate_stdout(data['stdout'], max_bytes) + return data class JobEventWebSocketSerializer(JobEventSerializer): @@ -3964,22 +3956,14 @@ class AdHocCommandEventSerializer(BaseSerializer): return res def to_representation(self, obj): - ret = super(AdHocCommandEventSerializer, self).to_representation(obj) + data = super(AdHocCommandEventSerializer, self).to_representation(obj) # Show full stdout for event detail view, truncate only for list view. if hasattr(self.context.get('view', None), 'retrieve'): - return ret + return data max_bytes = settings.EVENT_STDOUT_MAX_BYTES_DISPLAY - if max_bytes > 0 and 'stdout' in ret and len(ret['stdout']) >= max_bytes: - ret['stdout'] = ret['stdout'][:(max_bytes - 1)] + u'\u2026' - set_count = 0 - reset_count = 0 - for m in ANSI_SGR_PATTERN.finditer(ret['stdout']): - if m.string[m.start():m.end()] == u'\u001b[0m': - reset_count += 1 - else: - set_count += 1 - ret['stdout'] += u'\u001b[0m' * (set_count - reset_count) - return ret + if 'stdout' in data: + data['stdout'] = truncate_stdout(data['stdout'], max_bytes) + return data class AdHocCommandEventWebSocketSerializer(AdHocCommandEventSerializer): diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index d36dfa272b..11e4722f5f 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -38,18 +38,22 @@ from django.apps import apps logger = logging.getLogger('awx.main.utils') -__all__ = ['get_object_or_400', 'camelcase_to_underscore', 'underscore_to_camelcase', 'memoize', 'memoize_delete', - 'get_ansible_version', 'get_ssh_version', 'get_licenser', 'get_awx_version', 'update_scm_url', - 'get_type_for_model', 'get_model_for_type', 'copy_model_by_class', 'region_sorting', - 'copy_m2m_relationships', 'prefetch_page_capabilities', 'to_python_boolean', - 'ignore_inventory_computed_fields', 'ignore_inventory_group_removal', - '_inventory_updates', 'get_pk_from_dict', 'getattrd', 'getattr_dne', 'NoDefaultProvided', - 'get_current_apps', 'set_current_apps', - 'extract_ansible_vars', 'get_search_fields', 'get_system_task_capacity', 'get_cpu_capacity', 'get_mem_capacity', - 'wrap_args_with_proot', 'build_proot_temp_dir', 'check_proot_installed', 'model_to_dict', - 'NullablePromptPseudoField', 'model_instance_diff', 'parse_yaml_or_json', 'RequireDebugTrueOrTest', - 'has_model_field_prefetched', 'set_environ', 'IllegalArgumentError', 'get_custom_venv_choices', 'get_external_account', - 'task_manager_bulk_reschedule', 'schedule_task_manager', 'classproperty', 'create_temporary_fifo'] +__all__ = [ + 'get_object_or_400', 'camelcase_to_underscore', 'underscore_to_camelcase', 'memoize', + 'memoize_delete', 'get_ansible_version', 'get_ssh_version', 'get_licenser', + 'get_awx_version', 'update_scm_url', 'get_type_for_model', 'get_model_for_type', + 'copy_model_by_class', 'region_sorting', 'copy_m2m_relationships', + 'prefetch_page_capabilities', 'to_python_boolean', 'ignore_inventory_computed_fields', + 'ignore_inventory_group_removal', '_inventory_updates', 'get_pk_from_dict', 'getattrd', + 'getattr_dne', 'NoDefaultProvided', 'get_current_apps', 'set_current_apps', + 'extract_ansible_vars', 'get_search_fields', 'get_system_task_capacity', + 'get_cpu_capacity', 'get_mem_capacity', 'wrap_args_with_proot', 'build_proot_temp_dir', + 'check_proot_installed', 'model_to_dict', 'NullablePromptPseudoField', + 'model_instance_diff', 'parse_yaml_or_json', 'RequireDebugTrueOrTest', + 'has_model_field_prefetched', 'set_environ', 'IllegalArgumentError', + 'get_custom_venv_choices', 'get_external_account', 'task_manager_bulk_reschedule', + 'schedule_task_manager', 'classproperty', 'create_temporary_fifo', 'truncate_stdout', +] def get_object_or_400(klass, *args, **kwargs): @@ -1088,3 +1092,19 @@ def create_temporary_fifo(data): ).start() return path + +def truncate_stdout(stdout, size): + from awx.main.constants import ANSI_SGR_PATTERN + + if size <= 0 or len(stdout) <= size: + return stdout + + stdout = stdout[:(size - 1)] + u'\u2026' + set_count, reset_count = 0, 0 + for m in ANSI_SGR_PATTERN.finditer(stdout): + if m.group() == u'\u001b[0m': + reset_count += 1 + else: + set_count += 1 + + return stdout + u'\u001b[0m' * (set_count - reset_count)