diff --git a/awx/main/conf.py b/awx/main/conf.py index 55b12970a3..aff1be27f4 100644 --- a/awx/main/conf.py +++ b/awx/main/conf.py @@ -175,19 +175,34 @@ register( ) register( - 'DEFAULT_JOB_TIMEOUTS', - field_class=fields.DictField, - default={ - 'Job': 0, - 'InventoryUpdate': 0, - 'ProjectUpdate': 0, - }, - label=_('Default Job Timeouts'), - help_text=_('Maximum time to allow jobs to run. Use sub-keys of Job, ' - 'InventoryUpdate, and ProjectUpdate to configure this value ' - 'for each job type. Use value of 0 to indicate that no ' - 'timeout should be imposed. A timeout set on an individual ' - 'job template will override this.'), + 'DEFAULT_JOB_TIMEOUT', + field_class=fields.IntegerField, + min_value=0, + label=_('Default Job Timeout'), + help_text=_('Maximum time to allow jobs to run. Use value of 0 to indicate that no ' + 'timeout should be imposed. A timeout set on an individual job template will override this.'), + category=_('Jobs'), + category_slug='jobs', +) + +register( + 'DEFAULT_INVENTORY_UPDATE_TIMEOUT', + field_class=fields.IntegerField, + min_value=0, + label=_('Default Inventory Update Timeout'), + help_text=_('Maximum time to allow inventory updates to run. Use value of 0 to indicate that no ' + 'timeout should be imposed. A timeout set on an individual inventory source will override this.'), + category=_('Jobs'), + category_slug='jobs', +) + +register( + 'DEFAULT_PROJECT_UPDATE_TIMEOUT', + field_class=fields.IntegerField, + min_value=0, + label=_('Default Project Update Timeout'), + help_text=_('Maximum time to allow project updates to run. Use value of 0 to indicate that no ' + 'timeout should be imposed. A timeout set on an individual project will override this.'), category=_('Jobs'), category_slug='jobs', ) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 662b1702f9..551efa732b 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -1226,6 +1226,9 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin): from awx.main.tasks import RunInventoryUpdate return RunInventoryUpdate + def _global_timeout_setting(self): + return 'DEFAULT_INVENTORY_UPDATE_TIMEOUT' + def websocket_emit_data(self): if self.inventory_source.group is not None: return dict(group_id=self.inventory_source.group.id) diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index 8ed723626b..8a4d6c07ae 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -583,6 +583,9 @@ class Job(UnifiedJob, JobOptions, JobNotificationMixin): from awx.main.tasks import RunJob return RunJob + def _global_timeout_setting(self): + return 'DEFAULT_JOB_TIMEOUT' + def get_absolute_url(self): return reverse('api:job_detail', args=(self.pk,)) diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index c3763ff34f..aa8e726b64 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -423,6 +423,18 @@ class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin): from awx.main.tasks import RunProjectUpdate return RunProjectUpdate + def _global_timeout_setting(self): + return 'DEFAULT_PROJECT_UPDATE_TIMEOUT' + + def is_blocked_by(self, obj): + if type(obj) == ProjectUpdate: + if self.project == obj.project: + return True + if type(obj) == Job: + if self.project == obj.project: + return True + return False + def websocket_emit_data(self): return dict(project_id=self.project.id) diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index fa989ad60c..1fab5fcbb3 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -554,6 +554,10 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique def _get_parent_field_name(cls): return 'unified_job_template' # Override in subclasses. + def _global_timeout_setting(self): + "Override in child classes, None value indicates this is not configurable" + return None + def __unicode__(self): return u'%s-%s-%s' % (self.created, self.id, self.status) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 7f187c7bce..6b98a12b22 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -508,11 +508,11 @@ class BaseTask(Task): if pexpect_sleep is not None: logger.info("Suspending Job Execution for QA Work") time.sleep(pexpect_sleep) - global_timeout = getattr(settings, 'DEFAULT_JOB_TIMEOUTS', {}) - cls_name = instance.__class__.__name__ - if cls_name in global_timeout: + global_timeout_setting_name = instance._global_timeout_setting() + if global_timeout_setting_name: + global_timeout = getattr(settings, global_timeout_setting_name, 0) local_timeout = getattr(instance, 'timeout', 0) - job_timeout = global_timeout[cls_name] if local_timeout == 0 else local_timeout + job_timeout = global_timeout if local_timeout == 0 else local_timeout else: job_timeout = 0 child = pexpect.spawnu(args[0], args[1:], cwd=cwd, env=env) diff --git a/awx/settings/local_settings.py.docker_compose b/awx/settings/local_settings.py.docker_compose index 033bef6038..540490c813 100644 --- a/awx/settings/local_settings.py.docker_compose +++ b/awx/settings/local_settings.py.docker_compose @@ -276,10 +276,3 @@ TEST_OPENSTACK_PROJECT = '' # Azure credentials. TEST_AZURE_USERNAME = '' TEST_AZURE_KEY_DATA = '' - -# Exemplary global job timeout settings -# DEFAULT_JOB_TIMEOUTS = { -# 'Job': 10, -# 'InventoryUpdate': 15, -# 'ProjectUpdate': 20, -# }