From bb3b19e17480effdd12712b768c2ef972c60f1c4 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Mon, 14 May 2018 13:59:44 -0400 Subject: [PATCH] truncate certain event fields when they are overly long see: https://github.com/ansible/tower/issues/1775 --- awx/main/models/events.py | 38 ++++++++++++++--------- awx/main/tests/unit/models/test_events.py | 15 +++++++++ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/awx/main/models/events.py b/awx/main/models/events.py index 21dcd90a24..a6e2c67c74 100644 --- a/awx/main/models/events.py +++ b/awx/main/models/events.py @@ -4,9 +4,11 @@ import logging from django.conf import settings from django.db import models, DatabaseError from django.utils.dateparse import parse_datetime +from django.utils.text import Truncator from django.utils.timezone import utc from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import force_text +import six from awx.api.versioning import reverse from awx.main.fields import JSONField @@ -22,6 +24,22 @@ __all__ = ['JobEvent', 'ProjectUpdateEvent', 'AdHocCommandEvent', 'InventoryUpdateEvent', 'SystemJobEvent'] +def sanitize_event_keys(kwargs, valid_keys): + # Sanity check: Don't honor keys that we don't recognize. + for key in kwargs.keys(): + if key not in valid_keys: + kwargs.pop(key) + + # Truncate certain values over 1k + for key in [ + 'play', 'role', 'task', 'playbook' + ]: + if isinstance(kwargs.get(key), six.string_types): + if len(kwargs[key]) > 1024: + kwargs[key] = Truncator(kwargs[key]).chars(1024) + + + class BasePlaybookEvent(CreatedModifiedModel): ''' An event/message logged from a playbook callback for each host. @@ -257,7 +275,7 @@ class BasePlaybookEvent(CreatedModifiedModel): return updated_fields @classmethod - def create_from_data(self, **kwargs): + def create_from_data(cls, **kwargs): pk = None for key in ('job_id', 'project_update_id'): if key in kwargs: @@ -279,12 +297,8 @@ class BasePlaybookEvent(CreatedModifiedModel): except (KeyError, ValueError): kwargs.pop('created', None) - # Sanity check: Don't honor keys that we don't recognize. - for key in kwargs.keys(): - if key not in self.VALID_KEYS: - kwargs.pop(key) - - job_event = self.objects.create(**kwargs) + sanitize_event_keys(kwargs, cls.VALID_KEYS) + job_event = cls.objects.create(**kwargs) analytics_logger.info('Event data saved.', extra=dict(python_objects=dict(job_event=job_event))) return job_event @@ -551,7 +565,7 @@ class BaseCommandEvent(CreatedModifiedModel): return u'%s @ %s' % (self.get_event_display(), self.created.isoformat()) @classmethod - def create_from_data(self, **kwargs): + def create_from_data(cls, **kwargs): # Convert the datetime for the event's creation # appropriately, and include a time zone for it. # @@ -565,12 +579,8 @@ class BaseCommandEvent(CreatedModifiedModel): except (KeyError, ValueError): kwargs.pop('created', None) - # Sanity check: Don't honor keys that we don't recognize. - for key in kwargs.keys(): - if key not in self.VALID_KEYS: - kwargs.pop(key) - - return self.objects.create(**kwargs) + sanitize_event_keys(kwargs, cls.VALID_KEYS) + return cls.objects.create(**kwargs) def get_event_display(self): ''' diff --git a/awx/main/tests/unit/models/test_events.py b/awx/main/tests/unit/models/test_events.py index 71be98a167..47a7f30c55 100644 --- a/awx/main/tests/unit/models/test_events.py +++ b/awx/main/tests/unit/models/test_events.py @@ -44,3 +44,18 @@ def test_playbook_event_strip_invalid_keys(job_identifier, cls): 'extra_key': 'extra_value' }) manager.create.assert_called_with(**{job_identifier: 123}) + + +@pytest.mark.parametrize('field', [ + 'play', 'role', 'task', 'playbook' +]) +def test_really_long_event_fields(field): + with mock.patch.object(JobEvent, 'objects') as manager: + JobEvent.create_from_data(**{ + 'job_id': 123, + field: 'X' * 4096 + }) + manager.create.assert_called_with(**{ + 'job_id': 123, + field: 'X' * 1021 + '...' + })