From 12e0ec960c58ca8163b8c5914963f6601726d334 Mon Sep 17 00:00:00 2001 From: Chris Church Date: Thu, 2 Apr 2015 15:40:12 -0400 Subject: [PATCH] Add support for cleaning up ad hoc commands. --- awx/main/management/commands/cleanup_jobs.py | 44 ++++++++++++++------ awx/main/tests/commands.py | 43 ++++++++++++++++++- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/awx/main/management/commands/cleanup_jobs.py b/awx/main/management/commands/cleanup_jobs.py index 45e307ff9f..574f3c0069 100644 --- a/awx/main/management/commands/cleanup_jobs.py +++ b/awx/main/management/commands/cleanup_jobs.py @@ -12,7 +12,7 @@ from django.db import transaction from django.utils.timezone import now # AWX -from awx.main.models import Job, ProjectUpdate, InventoryUpdate, SystemJob +from awx.main.models import Job, AdHocCommand, ProjectUpdate, InventoryUpdate, SystemJob class Command(NoArgsCommand): ''' @@ -30,6 +30,9 @@ class Command(NoArgsCommand): make_option('--jobs', dest='only_jobs', action='store_true', default=False, help='Only remove jobs'), + make_option('--ad-hoc-commands', dest='only_ad_hoc_commands', + action='store_true', default=False, + help='Only remove ad hoc commands'), make_option('--project-updates', dest='only_project_updates', action='store_true', default=False, help='Only remove project updates'), @@ -60,6 +63,23 @@ class Command(NoArgsCommand): if not self.dry_run: job.delete() + def cleanup_ad_hoc_commands(self): + for ad_hoc_command in AdHocCommand.objects.all(): + ad_hoc_command_display = '"%s" (started %s, %d events)' % \ + (unicode(ad_hoc_command), unicode(ad_hoc_command.created), + ad_hoc_command.ad_hoc_command_events.count()) + if ad_hoc_command.status in ('pending', 'waiting', 'running'): + action_text = 'would skip' if self.dry_run else 'skipping' + self.logger.debug('%s %s ad hoc command %s', action_text, ad_hoc_command.status, ad_hoc_command_display) + elif ad_hoc_command.created >= self.cutoff: + action_text = 'would skip' if self.dry_run else 'skipping' + self.logger.debug('%s %s', action_text, ad_hoc_command_display) + else: + action_text = 'would delete' if self.dry_run else 'deleting' + self.logger.info('%s %s', action_text, ad_hoc_command_display) + if not self.dry_run: + ad_hoc_command.delete() + def cleanup_project_updates(self): for pu in ProjectUpdate.objects.all(): pu_display = '"%s" (started %s)' % (unicode(pu), unicode(pu.created)) @@ -131,15 +151,13 @@ class Command(NoArgsCommand): self.cutoff = now() - datetime.timedelta(days=self.days) except OverflowError: raise CommandError('--days specified is too large. Try something less than 99999 (about 270 years).') - self.only_jobs = bool(options.get('only_jobs', False)) - self.only_project_updates = bool(options.get('only_project_updates', False)) - self.only_inventory_updates = bool(options.get('only_inventory_updates', False)) - self.only_management_jobs = bool(options.get('only_management_jobs', False)) - if self.only_jobs or (not self.only_jobs and not self.only_project_updates and not self.only_inventory_updates and not self.only_management_jobs): - self.cleanup_jobs() - if self.only_project_updates or (not self.only_jobs and not self.only_project_updates and not self.only_inventory_updates and not self.only_management_jobs): - self.cleanup_project_updates() - if self.only_inventory_updates or (not self.only_jobs and not self.only_project_updates and not self.only_inventory_updates and not self.only_management_jobs): - self.cleanup_inventory_updates() - if self.only_management_jobs or (not self.only_jobs and not self.only_project_updates and not self.only_inventory_updates and not self.only_management_jobs): - self.cleanup_management_jobs() + model_names = ('jobs', 'ad_hoc_commands', 'project_updates', 'inventory_updates', 'management_jobs') + models_to_cleanup = set() + for m in model_names: + if options.get('only_%s' % m, False): + models_to_cleanup.add(m) + if not models_to_cleanup: + models_to_cleanup.update(model_names) + for m in model_names: + if m in models_to_cleanup: + getattr(self, 'cleanup_%s' % m)() diff --git a/awx/main/tests/commands.py b/awx/main/tests/commands.py index 2d52f4b574..7f78af5da3 100644 --- a/awx/main/tests/commands.py +++ b/awx/main/tests/commands.py @@ -362,14 +362,30 @@ class CleanupJobsTest(BaseCommandMixin, BaseLiveServerTest): self.job = Job.objects.create(**opts) return self.job + def create_test_ad_hoc_command(self, **kwargs): + opts = { + 'inventory': self.inventory, + 'credential': self.credential, + 'module_name': 'command', + 'module_args': 'uptime', + } + opts.update(kwargs) + self.ad_hoc_command = AdHocCommand.objects.create(**opts) + return self.ad_hoc_command + def test_cleanup_jobs(self): # Test with no jobs to be cleaned up. jobs_before = Job.objects.all().count() self.assertFalse(jobs_before) + ad_hoc_commands_before = AdHocCommand.objects.all().count() + self.assertFalse(ad_hoc_commands_before) result, stdout, stderr = self.run_command('cleanup_jobs') self.assertEqual(result, None) jobs_after = Job.objects.all().count() self.assertEqual(jobs_before, jobs_after) + ad_hoc_commands_after = AdHocCommand.objects.all().count() + self.assertEqual(ad_hoc_commands_before, ad_hoc_commands_after) + # Create and run job. self.create_test_project(TEST_PLAYBOOK) job_template = self.create_test_job_template() @@ -379,29 +395,54 @@ class CleanupJobsTest(BaseCommandMixin, BaseLiveServerTest): self.assertTrue(job.signal_start()) job = Job.objects.get(pk=job.pk) self.assertEqual(job.status, 'successful') + + # Create and run ad hoc command. + ad_hoc_command = self.create_test_ad_hoc_command() + self.assertEqual(ad_hoc_command.status, 'new') + self.assertFalse(ad_hoc_command.passwords_needed_to_start) + self.assertTrue(ad_hoc_command.signal_start()) + ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk) + self.assertEqual(ad_hoc_command.status, 'successful') + # With days=1, no jobs will be deleted. jobs_before = Job.objects.all().count() self.assertTrue(jobs_before) + ad_hoc_commands_before = AdHocCommand.objects.all().count() + self.assertTrue(ad_hoc_commands_before) result, stdout, stderr = self.run_command('cleanup_jobs', days=1) self.assertEqual(result, None) jobs_after = Job.objects.all().count() self.assertEqual(jobs_before, jobs_after) + ad_hoc_commands_after = AdHocCommand.objects.all().count() + self.assertEqual(ad_hoc_commands_before, ad_hoc_commands_after) + # With days=0 and dry_run=True, no jobs will be deleted. jobs_before = Job.objects.all().count() self.assertTrue(jobs_before) + ad_hoc_commands_before = AdHocCommand.objects.all().count() + self.assertTrue(ad_hoc_commands_before) result, stdout, stderr = self.run_command('cleanup_jobs', days=0, dry_run=True) self.assertEqual(result, None) jobs_after = Job.objects.all().count() self.assertEqual(jobs_before, jobs_after) - # With days=0, our job will be deleted. + ad_hoc_commands_after = AdHocCommand.objects.all().count() + self.assertEqual(ad_hoc_commands_before, ad_hoc_commands_after) + + # With days=0, our job and ad hoc command will be deleted. jobs_before = Job.objects.all().count() self.assertTrue(jobs_before) + ad_hoc_commands_before = AdHocCommand.objects.all().count() + self.assertTrue(ad_hoc_commands_before) result, stdout, stderr = self.run_command('cleanup_jobs', days=0) self.assertEqual(result, None) jobs_after = Job.objects.all().count() self.assertNotEqual(jobs_before, jobs_after) self.assertFalse(jobs_after) + ad_hoc_commands_after = AdHocCommand.objects.all().count() + self.assertNotEqual(ad_hoc_commands_before, ad_hoc_commands_after) + self.assertFalse(ad_hoc_commands_after) + class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest): '''