diff --git a/awx/api/filters.py b/awx/api/filters.py index e7974ec259..59d85b785d 100644 --- a/awx/api/filters.py +++ b/awx/api/filters.py @@ -118,6 +118,12 @@ class FieldLookupBackend(BaseFilterBackend): for key, values in request.QUERY_PARAMS.lists(): if key in self.RESERVED_NAMES: continue + + # HACK: Make job event filtering by host name mostly work even + # when not capturing job event hosts M2M. + if queryset.model._meta.object_name == 'JobEvent' and key.startswith('hosts__name'): + key = key.replace('hosts__name', 'or__host__name') + or_filters.append((False, 'host__name__isnull', True)) # Custom __int filter suffix (internal use only). q_int = False diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index d0a8a7acfc..36fb326588 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -756,7 +756,8 @@ class JobEvent(BaseModel): self.update_parent_failed_and_changed() # FIXME: The update_hosts() call (and its queries) are the current # performance bottleneck.... - #self.update_hosts() + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + self.update_hosts() self.update_host_summary_from_stats() def update_parent_failed_and_changed(self): diff --git a/awx/main/tests/jobs.py b/awx/main/tests/jobs.py index a73be07ab6..1ccf853888 100644 --- a/awx/main/tests/jobs.py +++ b/awx/main/tests/jobs.py @@ -931,14 +931,15 @@ class JobStartCancelTest(BaseJobTestMixin, django.test.LiveServerTestCase): response = self.get(url) # Also test job event list for each host. - for host in Host.objects.filter(pk__in=host_ids): - url = reverse('api:host_job_events_list', args=(host.pk,)) - with self.current_user(self.user_sue): - response = self.get(url) - qs = host.job_events.all() - self.assertTrue(qs.count()) - self.check_pagination_and_size(response, qs.count()) - self.check_list_ids(response, qs) + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + for host in Host.objects.filter(pk__in=host_ids): + url = reverse('api:host_job_events_list', args=(host.pk,)) + with self.current_user(self.user_sue): + response = self.get(url) + qs = host.job_events.all() + self.assertTrue(qs.count()) + self.check_pagination_and_size(response, qs.count()) + self.check_list_ids(response, qs) # Test job event list for groups. for group in self.inv_ops_east.groups.all(): diff --git a/awx/main/tests/tasks.py b/awx/main/tests/tasks.py index 63936c23d1..13aa44ec09 100644 --- a/awx/main/tests/tasks.py +++ b/awx/main/tests/tasks.py @@ -319,8 +319,9 @@ class RunJobTest(BaseCeleryTest): self.assertEqual(evt.failed, should_be_failed) if not async: self.assertEqual(evt.changed, should_be_changed) - self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), - host_pks) + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), + host_pks) qs = job_events.filter(event='playbook_on_play_start') self.assertEqual(qs.count(), plays) for evt in qs: @@ -330,8 +331,9 @@ class RunJobTest(BaseCeleryTest): self.assertEqual(evt.failed, should_be_failed) if not async: self.assertEqual(evt.changed, should_be_changed) - self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), - host_pks) + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), + host_pks) qs = job_events.filter(event='playbook_on_task_start') self.assertEqual(qs.count(), tasks) for evt in qs: @@ -341,8 +343,9 @@ class RunJobTest(BaseCeleryTest): self.assertEqual(evt.failed, should_be_failed) if not async: self.assertEqual(evt.changed, should_be_changed) - self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), - host_pks) + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), + host_pks) if check_ignore_errors: qs = job_events.filter(event='runner_on_failed') else: @@ -360,8 +363,9 @@ class RunJobTest(BaseCeleryTest): self.assertEqual(evt.failed, should_be_failed) if not async: self.assertEqual(evt.changed, should_be_changed) - self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), - host_pks) + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), + host_pks) if async: qs = job_events.filter(event='runner_on_async_poll') if not async_nowait: @@ -371,8 +375,9 @@ class RunJobTest(BaseCeleryTest): self.assertTrue(evt.play, evt) self.assertTrue(evt.task, evt) self.assertEqual(evt.failed, False)#should_be_failed) - self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), - host_pks) + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), + host_pks) qs = job_events.filter(event=('runner_on_async_%s' % runner_status)) # Ansible 1.2 won't call the on_runner_async_failed callback when a # timeout occurs, so skip this check for now. @@ -383,8 +388,9 @@ class RunJobTest(BaseCeleryTest): self.assertTrue(evt.play, evt) self.assertTrue(evt.task, evt) self.assertEqual(evt.failed, should_be_failed) - self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), - host_pks) + if getattr(settings, 'CAPTURE_JOB_EVENT_HOSTS', False): + self.assertEqual(set(evt.hosts.values_list('pk', flat=True)), + host_pks) qs = job_events.filter(event__startswith='runner_') if check_ignore_errors: qs = qs.exclude(event='runner_on_failed') diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 77a94c5b89..8cf4444f84 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -300,6 +300,9 @@ ANSIBLE_PARAMIKO_RECORD_HOST_KEYS = False # the celery task. AWX_TASK_ENV = {} +# Flag to enable/disable updating hosts M2M when saving job events. +CAPTURE_JOB_EVENT_HOSTS = False + # Not possible to get list of regions without authenticating, so use this list # instead (based on docs from: # http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/Service_Access_Endpoints-d1e517.html)