AC-1040 Model cleanup/refactor, add and use job_explanation field.

This commit is contained in:
Chris Church
2014-03-30 22:57:45 -04:00
parent e5054eeb65
commit e1d3da731e
10 changed files with 601 additions and 146 deletions

View File

@@ -338,7 +338,8 @@ class UnifiedJobSerializer(BaseSerializer):
model = UnifiedJob model = UnifiedJob
fields = ('*', 'unified_job_template', 'launch_type', 'status', fields = ('*', 'unified_job_template', 'launch_type', 'status',
'failed', 'started', 'finished', 'elapsed', 'job_args', 'failed', 'started', 'finished', 'elapsed', 'job_args',
'job_cwd', 'job_env', 'result_stdout', 'result_traceback') 'job_cwd', 'job_env', 'job_explanation', 'result_stdout',
'result_traceback')
def get_types(self): def get_types(self):
if type(self) is UnifiedJobSerializer: if type(self) is UnifiedJobSerializer:

View File

@@ -173,7 +173,7 @@ def rebuild_graph(message):
if task.celery_task_id not in active_tasks and not hasattr(settings, 'IGNORE_CELERY_INSPECTOR'): if task.celery_task_id not in active_tasks and not hasattr(settings, 'IGNORE_CELERY_INSPECTOR'):
# NOTE: Pull status again and make sure it didn't finish in the meantime? # NOTE: Pull status again and make sure it didn't finish in the meantime?
task.status = 'failed' task.status = 'failed'
task.result_traceback += "Task was marked as running in Tower but was not present in Celery so it has been marked as failed" task.job_explanation += "Task was marked as running in Tower but was not present in Celery so it has been marked as failed"
task.save() task.save()
running_tasks.pop(running_tasks.index(task)) running_tasks.pop(running_tasks.index(task))
print("Task %s appears orphaned... marking as failed" % task) print("Task %s appears orphaned... marking as failed" % task)
@@ -237,7 +237,7 @@ def process_graph(graph, task_capacity):
start_status = node_obj.start(error_callback=error_handler) start_status = node_obj.start(error_callback=error_handler)
if not start_status: if not start_status:
node_obj.status = 'failed' node_obj.status = 'failed'
node_obj.result_traceback += "Task failed pre-start check" node_obj.job_explanation += "Task failed pre-start check"
node_obj.save() node_obj.save()
# TODO: Run error handler # TODO: Run error handler
continue continue

View File

@@ -0,0 +1,452 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
from django.utils.timezone import now
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'UnifiedJob.job_explanation'
db.add_column(u'main_unifiedjob', 'job_explanation',
self.gf('django.db.models.fields.TextField')(default='', blank=True),
keep_default=False)
# Deleting field 'Credential.ssh_key_path'
db.delete_column(u'main_credential', 'ssh_key_path')
# Changing field 'Schedule.dtstart'
db.alter_column(u'main_schedule', 'dtstart', self.gf('django.db.models.fields.DateTimeField')(null=True))
def backwards(self, orm):
# Deleting field 'UnifiedJob.job_explanation'
db.delete_column(u'main_unifiedjob', 'job_explanation')
# Adding field 'Credential.ssh_key_path'
db.add_column(u'main_credential', 'ssh_key_path',
self.gf('django.db.models.fields.CharField')(default='', max_length=1024, blank=True),
keep_default=False)
# Changing field 'Schedule.dtstart'
db.alter_column(u'main_schedule', 'dtstart', self.gf('django.db.models.fields.DateTimeField')(default=now))
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'main.activitystream': {
'Meta': {'object_name': 'ActivityStream'},
'actor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_stream'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'changes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'credential': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Credential']", 'symmetrical': 'False', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'host': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Host']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inventory': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Inventory']", 'symmetrical': 'False', 'blank': 'True'}),
'inventory_source': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.InventorySource']", 'symmetrical': 'False', 'blank': 'True'}),
'inventory_update': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.InventoryUpdate']", 'symmetrical': 'False', 'blank': 'True'}),
'job': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Job']", 'symmetrical': 'False', 'blank': 'True'}),
'job_template': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.JobTemplate']", 'symmetrical': 'False', 'blank': 'True'}),
'object1': ('django.db.models.fields.TextField', [], {}),
'object2': ('django.db.models.fields.TextField', [], {}),
'object_relationship_type': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'operation': ('django.db.models.fields.CharField', [], {'max_length': '13'}),
'organization': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Organization']", 'symmetrical': 'False', 'blank': 'True'}),
'permission': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'project': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Project']", 'symmetrical': 'False', 'blank': 'True'}),
'project_update': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.ProjectUpdate']", 'symmetrical': 'False', 'blank': 'True'}),
'schedule': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Schedule']", 'symmetrical': 'False', 'blank': 'True'}),
'team': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Team']", 'symmetrical': 'False', 'blank': 'True'}),
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'unified_job': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'activity_stream_as_unified_job+'", 'blank': 'True', 'to': "orm['main.UnifiedJob']"}),
'unified_job_template': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'activity_stream_as_unified_job_template+'", 'blank': 'True', 'to': "orm['main.UnifiedJobTemplate']"}),
'user': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'})
},
'main.authtoken': {
'Meta': {'object_name': 'AuthToken'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'request_hash': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '40', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_tokens'", 'to': u"orm['auth.User']"})
},
'main.credential': {
'Meta': {'unique_together': "[('user', 'team', 'kind', 'name')]", 'object_name': 'Credential'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'cloud': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'credential\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'kind': ('django.db.models.fields.CharField', [], {'default': "'ssh'", 'max_length': '32'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'credential\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'ssh_key_data': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'ssh_key_unlock': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'sudo_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'sudo_username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'team': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'credentials'", 'null': 'True', 'blank': 'True', 'to': "orm['main.Team']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'credentials'", 'null': 'True', 'blank': 'True', 'to': u"orm['auth.User']"}),
'username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'vault_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'})
},
'main.group': {
'Meta': {'unique_together': "(('name', 'inventory'),)", 'object_name': 'Group'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'group\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'groups_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'groups'", 'blank': 'True', 'to': "orm['main.Host']"}),
'hosts_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'groups'", 'to': "orm['main.Inventory']"}),
'inventory_sources': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'groups'", 'symmetrical': 'False', 'to': "orm['main.InventorySource']"}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'group\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'parents': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'children'", 'blank': 'True', 'to': "orm['main.Group']"}),
'total_groups': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'total_hosts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
},
'main.host': {
'Meta': {'unique_together': "(('name', 'inventory'),)", 'object_name': 'Host'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'host\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'instance_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts'", 'to': "orm['main.Inventory']"}),
'inventory_sources': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'hosts'", 'symmetrical': 'False', 'to': "orm['main.InventorySource']"}),
'last_job': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'hosts_as_last_job+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Job']"}),
'last_job_host_summary': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts_as_last_job_summary+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobHostSummary']", 'blank': 'True', 'null': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'host\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
},
'main.inventory': {
'Meta': {'unique_together': "[('name', 'organization')]", 'object_name': 'Inventory'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventory\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'groups_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'hosts_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inventory_sources_with_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventory\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
'organization': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventories'", 'to': "orm['main.Organization']"}),
'total_groups': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'total_hosts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'total_inventory_sources': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
},
'main.inventorysource': {
'Meta': {'object_name': 'InventorySource', '_ormbases': ['main.UnifiedJobTemplate']},
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventorysources'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'group': ('awx.main.fields.AutoOneToOneField', [], {'default': 'None', 'related_name': "'inventory_source'", 'unique': 'True', 'null': 'True', 'to': "orm['main.Group']"}),
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_sources'", 'null': 'True', 'to': "orm['main.Inventory']"}),
'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'overwrite_vars': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'source': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
'source_path': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'source_regions': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'source_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
u'unifiedjobtemplate_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJobTemplate']", 'unique': 'True', 'primary_key': 'True'}),
'update_cache_timeout': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
},
'main.inventoryupdate': {
'Meta': {'object_name': 'InventoryUpdate', '_ormbases': ['main.UnifiedJob']},
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventoryupdates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'inventory_source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventory_updates'", 'to': "orm['main.InventorySource']"}),
'license_error': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'overwrite_vars': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'source': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
'source_path': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'source_regions': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'source_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'})
},
'main.job': {
'Meta': {'object_name': 'Job', '_ormbases': ['main.UnifiedJob']},
'cloud_credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs_as_cloud_credential+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'jobs'", 'symmetrical': 'False', 'through': "orm['main.JobHostSummary']", 'to': "orm['main.Host']"}),
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
'job_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'job_template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobTemplate']", 'blank': 'True', 'null': 'True'}),
'job_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'playbook': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'}),
'verbosity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'})
},
'main.jobevent': {
'Meta': {'ordering': "('pk',)", 'object_name': 'JobEvent'},
'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'event': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'event_data': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'host': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'job_events_as_primary_host'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Host']"}),
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'job_events'", 'symmetrical': 'False', 'to': "orm['main.Host']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_events'", 'to': "orm['main.Job']"}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.JobEvent']"}),
'play': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
'role': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
'task': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'})
},
'main.jobhostsummary': {
'Meta': {'ordering': "('-pk',)", 'unique_together': "[('job', 'host')]", 'object_name': 'JobHostSummary'},
'changed': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'dark': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'host': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_host_summaries'", 'to': "orm['main.Host']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_host_summaries'", 'to': "orm['main.Job']"}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'ok': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'processed': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'skipped': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
},
'main.jobtemplate': {
'Meta': {'object_name': 'JobTemplate', '_ormbases': ['main.UnifiedJobTemplate']},
'cloud_credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates_as_cloud_credential+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
'host_config_key': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
'job_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'job_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'playbook': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
u'unifiedjobtemplate_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJobTemplate']", 'unique': 'True', 'primary_key': 'True'}),
'verbosity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'})
},
'main.organization': {
'Meta': {'object_name': 'Organization'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'admins': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'admin_of_organizations'", 'blank': 'True', 'to': u"orm['auth.User']"}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'organization\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'organization\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
'projects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organizations'", 'blank': 'True', 'to': "orm['main.Project']"}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organizations'", 'blank': 'True', 'to': u"orm['auth.User']"})
},
'main.permission': {
'Meta': {'object_name': 'Permission'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'permission\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'permission\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'permission_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
'team': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Team']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"})
},
'main.profile': {
'Meta': {'object_name': 'Profile'},
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ldap_dn': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'user': ('awx.main.fields.AutoOneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': u"orm['auth.User']"})
},
'main.project': {
'Meta': {'object_name': 'Project', '_ormbases': ['main.UnifiedJobTemplate']},
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
'scm_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'blank': 'True'}),
'scm_clean': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'scm_delete_on_next_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'scm_delete_on_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'scm_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8', 'blank': 'True'}),
'scm_update_cache_timeout': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'scm_update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'scm_url': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
u'unifiedjobtemplate_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJobTemplate']", 'unique': 'True', 'primary_key': 'True'})
},
'main.projectupdate': {
'Meta': {'object_name': 'ProjectUpdate', '_ormbases': ['main.UnifiedJob']},
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projectupdates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'project_updates'", 'to': "orm['main.Project']"}),
'scm_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'blank': 'True'}),
'scm_clean': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'scm_delete_on_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'scm_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8', 'blank': 'True'}),
'scm_url': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'})
},
'main.schedule': {
'Meta': {'ordering': "['-next_run']", 'object_name': 'Schedule'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'schedule\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'dtend': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
'dtstart': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'schedule\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
'next_run': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
'rrule': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'unified_job_template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'schedules'", 'to': "orm['main.UnifiedJobTemplate']"})
},
'main.team': {
'Meta': {'unique_together': "[('organization', 'name')]", 'object_name': 'Team'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'team\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'team\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'organization': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'teams'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Organization']"}),
'projects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': "orm['main.Project']"}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': u"orm['auth.User']"})
},
'main.unifiedjob': {
'Meta': {'object_name': 'UnifiedJob'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'cancel_flag': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'celery_task_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjob\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'dependent_jobs': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'dependent_jobs_rel_+'", 'to': "orm['main.UnifiedJob']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'elapsed': ('django.db.models.fields.DecimalField', [], {'max_digits': '12', 'decimal_places': '3'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'finished': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'job_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'job_cwd': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'job_env': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
'job_explanation': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'launch_type': ('django.db.models.fields.CharField', [], {'default': "'manual'", 'max_length': '20'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjob\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'old_pk': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'null': 'True'}),
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_main.unifiedjob_set'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
'result_stdout_file': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'result_stdout_text': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'schedule': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['main.Schedule']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
'start_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'started': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'}),
'unified_job_template': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjob_unified_jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.UnifiedJobTemplate']"})
},
'main.unifiedjobtemplate': {
'Meta': {'unique_together': "[('polymorphic_ctype', 'name')]", 'object_name': 'UnifiedJobTemplate'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjobtemplate\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'current_job': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjobtemplate_as_current_job+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.UnifiedJob']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'has_schedules': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_job': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjobtemplate_as_last_job+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.UnifiedJob']"}),
'last_job_failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_job_run': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjobtemplate\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'next_job_run': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
'next_schedule': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjobtemplate_as_next_schedule+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Schedule']"}),
'old_pk': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'null': 'True'}),
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_main.unifiedjobtemplate_set'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
'status': ('django.db.models.fields.CharField', [], {'default': "'ok'", 'max_length': '32'})
},
u'taggit.tag': {
'Meta': {'object_name': 'Tag'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'})
},
u'taggit.taggeditem': {
'Meta': {'object_name': 'TaggedItem'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_tagged_items'", 'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_items'", 'to': u"orm['taggit.Tag']"})
}
}
complete_apps = ['main']

View File

@@ -4,8 +4,6 @@
# Python # Python
import json import json
import shlex import shlex
import os
import os.path
# PyYAML # PyYAML
import yaml import yaml
@@ -13,9 +11,7 @@ import yaml
# Django # Django
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.db import transaction
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now from django.utils.timezone import now
@@ -31,12 +27,16 @@ from taggit.managers import TaggableManager
# Django-Celery # Django-Celery
from djcelery.models import TaskMeta from djcelery.models import TaskMeta
__all__ = ['VarsDictProperty', 'BaseModel', 'CreatedModifiedModel', 'PrimordialModel', 'CommonModel', # Ansible Tower
'CommonModelNameNotUnique', 'CommonTask', 'PERM_INVENTORY_ADMIN', from awx.main.utils import encrypt_field
'PERM_INVENTORY_READ', 'PERM_INVENTORY_WRITE',
'PERM_INVENTORY_DEPLOY', 'PERM_INVENTORY_CHECK', 'JOB_TYPE_CHOICES', __all__ = ['VarsDictProperty', 'BaseModel', 'CreatedModifiedModel',
'PERMISSION_TYPE_CHOICES', 'TASK_STATUS_CHOICES', 'PasswordFieldsModel', 'PrimordialModel', 'CommonModel',
'CLOUD_INVENTORY_SOURCES'] 'CommonModelNameNotUnique',
'PERM_INVENTORY_ADMIN', 'PERM_INVENTORY_READ',
'PERM_INVENTORY_WRITE', 'PERM_INVENTORY_DEPLOY',
'PERM_INVENTORY_CHECK', 'JOB_TYPE_CHOICES',
'PERMISSION_TYPE_CHOICES', 'CLOUD_INVENTORY_SOURCES']
PERM_INVENTORY_ADMIN = 'admin' PERM_INVENTORY_ADMIN = 'admin'
PERM_INVENTORY_READ = 'read' PERM_INVENTORY_READ = 'read'
@@ -57,17 +57,6 @@ PERMISSION_TYPE_CHOICES = [
(PERM_INVENTORY_CHECK, _('Deploy To Inventory (Dry Run)')), (PERM_INVENTORY_CHECK, _('Deploy To Inventory (Dry Run)')),
] ]
TASK_STATUS_CHOICES = [
('new', _('New')), # Job has been created, but not started.
('pending', _('Pending')), # Job has been queued, but is not yet running.
('waiting', _('Waiting')), # Job is waiting on an update/dependency.
('running', _('Running')), # Job is currently running.
('successful', _('Successful')), # Job completed successfully.
('failed', _('Failed')), # Job completed, but with failures.
('error', _('Error')), # The job was unable to run.
('canceled', _('Canceled')), # The job was canceled before completion.
]
CLOUD_INVENTORY_SOURCES = ['ec2', 'rax'] CLOUD_INVENTORY_SOURCES = ['ec2', 'rax']
@@ -140,7 +129,7 @@ class BaseModel(models.Model):
except ValidationError, e: except ValidationError, e:
errors[f.name] = e.messages errors[f.name] = e.messages
if errors: if errors:
raise ValidationError(errors) raise ValidationError(errors)
def update_fields(self, **kwargs): def update_fields(self, **kwargs):
save = kwargs.pop('save', True) save = kwargs.pop('save', True)
@@ -166,38 +155,85 @@ class BaseModel(models.Model):
class CreatedModifiedModel(BaseModel): class CreatedModifiedModel(BaseModel):
'''
Common model with created/modified timestamp fields. Allows explicitly
specifying created/modified timestamps in certain cases (migrations, job
events), calculates automatically if not specified.
'''
class Meta: class Meta:
abstract = True abstract = True
created = models.DateTimeField( created = models.DateTimeField(
#auto_now_add=True, # FIXME: Disabled temporarily for data migration.
default=None, default=None,
editable=False, editable=False,
) )
modified = models.DateTimeField( modified = models.DateTimeField(
#auto_now=True, # FIXME: Disabled temporarily for data migration.
#default=now,
default=None, default=None,
editable=False, editable=False,
) )
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
update_fields = kwargs.get('update_fields', []) update_fields = kwargs.get('update_fields', [])
# Manually perform auto_now_add and auto_now logic (for unified jobs migration). # Manually perform auto_now_add and auto_now logic.
if not self.pk and not self.created: if not self.pk and not self.created:
self.created = now() self.created = now()
if 'created' not in update_fields: if 'created' not in update_fields:
update_fields.append('created') update_fields.append('created')
if 'modified' not in update_fields or not self.modified: if 'modified' not in update_fields or not self.modified:
self.modified = now() # FIXME: Moved temporarily for unified jobs migration. self.modified = now()
update_fields.append('modified') update_fields.append('modified')
super(CreatedModifiedModel, self).save(*args, **kwargs) super(CreatedModifiedModel, self).save(*args, **kwargs)
class PasswordFieldsModel(BaseModel):
'''
Abstract base class for a model with password fields that should be stored
as encrypted values.
'''
PASSWORD_FIELDS = ()
class Meta:
abstract = True
def _password_field_allows_ask(self, field):
return False # Override in subclasses if needed.
def save(self, *args, **kwargs):
new_instance = not bool(self.pk)
# If update_fields has been specified, add our field names to it,
# if it hasn't been specified, then we're just doing a normal save.
update_fields = kwargs.get('update_fields', [])
# When first saving to the database, don't store any password field
# values, but instead save them until after the instance is created.
# Otherwise, store encrypted values to the database.
for field in self.PASSWORD_FIELDS:
if new_instance:
value = getattr(self, field, '')
setattr(self, '_saved_%s' % field, value)
setattr(self, field, '')
else:
ask = self._password_field_allows_ask(field)
encrypted = encrypt_field(self, field, ask)
setattr(self, field, encrypted)
if field not in update_fields:
update_fields.append(field)
super(PasswordFieldsModel, self).save(*args, **kwargs)
# After saving a new instance for the first time, set the password
# fields and save again.
if new_instance:
update_fields = []
for field in self.PASSWORD_FIELDS:
saved_value = getattr(self, '_saved_%s' % field, '')
setattr(self, field, saved_value)
update_fields.append(field)
self.save(update_fields=update_fields)
class PrimordialModel(CreatedModifiedModel): class PrimordialModel(CreatedModifiedModel):
''' '''
common model for all object types that have these standard fields Common model for all object types that have these standard fields
must use a subclass CommonModel or CommonModelNameNotUnique though must use a subclass CommonModel or CommonModelNameNotUnique though
as this lacks a name field. as this lacks a name field.
''' '''
@@ -275,9 +311,3 @@ class CommonModelNameNotUnique(PrimordialModel):
max_length=512, max_length=512,
unique=False, unique=False,
) )
class CommonTask(PrimordialModel):
class Meta:
abstract = True

View File

@@ -13,13 +13,13 @@ from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
# AWX # AWX
from awx.main.utils import encrypt_field, decrypt_field from awx.main.utils import decrypt_field
from awx.main.models.base import * from awx.main.models.base import *
__all__ = ['Credential'] __all__ = ['Credential']
class Credential(CommonModelNameNotUnique): class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
''' '''
A credential contains information about how to talk to a remote resource A credential contains information about how to talk to a remote resource
Usually this is a SSH key location, and possibly an unlock password. Usually this is a SSH key location, and possibly an unlock password.
@@ -86,14 +86,6 @@ class Credential(CommonModelNameNotUnique):
verbose_name=_('SSH private key'), verbose_name=_('SSH private key'),
help_text=_('RSA or DSA private key to be used instead of password.'), help_text=_('RSA or DSA private key to be used instead of password.'),
) )
ssh_key_path = models.CharField( # FIXME: No longer needed.
editable=False,
max_length=1024,
blank=True,
default='',
verbose_name=_('SSH key path'),
help_text=_('Path to SSH private key file.'),
)
ssh_key_unlock = models.CharField( ssh_key_unlock = models.CharField(
max_length=1024, max_length=1024,
blank=True, blank=True,
@@ -281,38 +273,16 @@ class Credential(CommonModelNameNotUnique):
if errors: if errors:
raise ValidationError(errors) raise ValidationError(errors)
def _password_field_allows_ask(self, field):
return bool(self.kind == 'ssh' and field != 'ssh_key_data')
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
new_instance = not bool(self.pk) # If update_fields has been specified, add our field names to it,
# if hit hasn't been specified, then we're just doing a normal save.
update_fields = kwargs.get('update_fields', []) update_fields = kwargs.get('update_fields', [])
# When first saving to the database, don't store any password field
# values, but instead save them until after the instance is created.
if new_instance:
for field in self.PASSWORD_FIELDS:
value = getattr(self, field, '')
setattr(self, '_saved_%s' % field, value)
setattr(self, field, '')
# Otherwise, store encrypted values to the database.
else:
# If update_fields has been specified, add our field names to it,
# if hit hasn't been specified, then we're just doing a normal save.
for field in self.PASSWORD_FIELDS:
ask = bool(self.kind == 'ssh' and field != 'ssh_key_data')
encrypted = encrypt_field(self, field, ask)
setattr(self, field, encrypted)
if field not in update_fields:
update_fields.append(field)
cloud = self.kind in ('aws', 'rax') cloud = self.kind in ('aws', 'rax')
if self.cloud != cloud: if self.cloud != cloud:
self.cloud = cloud self.cloud = cloud
if 'cloud' not in update_fields: if 'cloud' not in update_fields:
update_fields.append('cloud') update_fields.append('cloud')
super(Credential, self).save(*args, **kwargs) super(Credential, self).save(*args, **kwargs)
# After saving a new instance for the first time, set the password
# fields and save again.
if new_instance:
update_fields=[]
for field in self.PASSWORD_FIELDS:
saved_value = getattr(self, '_saved_%s' % field, '')
setattr(self, field, saved_value)
update_fields.append(field)
self.save(update_fields=update_fields)

View File

@@ -651,6 +651,19 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
# Do the actual save. # Do the actual save.
super(InventorySource, self).save(*args, **kwargs) super(InventorySource, self).save(*args, **kwargs)
def _get_current_status(self):
if self.source:
if self.current_job:
return 'running'
elif not self.last_job:
return 'never updated'
elif self.last_job_failed:
return 'failed'
else:
return 'successful'
else:
return 'none'
def get_absolute_url(self): def get_absolute_url(self):
return reverse('api:inventory_source_detail', args=(self.pk,)) return reverse('api:inventory_source_detail', args=(self.pk,))

View File

@@ -261,7 +261,7 @@ class Project(UnifiedJobTemplate, ProjectOptions):
def _get_current_status(self): def _get_current_status(self):
if self.scm_type: if self.scm_type:
if self.current_update: if self.current_update:
return 'updating' return 'running'
elif not self.last_job: elif not self.last_job:
return 'never updated' return 'never updated'
elif self.last_job_failed: elif self.last_job_failed:

View File

@@ -15,13 +15,11 @@ import yaml
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.db import transaction from django.db import transaction
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now from django.utils.timezone import now
from django.core.exceptions import NON_FIELD_ERRORS
# Django-JSONField # Django-JSONField
from jsonfield import JSONField from jsonfield import JSONField
@@ -33,7 +31,9 @@ from djcelery.models import TaskMeta
# AWX # AWX
from awx.main.models.base import * from awx.main.models.base import *
from awx.main.utils import camelcase_to_underscore, encrypt_field, decrypt_field from awx.main.utils import decrypt_field, get_type_for_model
__all__ = ['UnifiedJobTemplate', 'UnifiedJob']
logger = logging.getLogger('awx.main.models.unified_jobs') logger = logging.getLogger('awx.main.models.unified_jobs')
@@ -44,22 +44,20 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
''' '''
STATUS_CHOICES = [ STATUS_CHOICES = [
# from Project # Common to all:
('ok', 'OK'), ('never updated', 'Never Updated'), # A job has never been run using this template.
('missing', 'Missing'), ('running', 'Running'), # A job is currently running (or pending/waiting) using this template.
('never updated', 'Never Updated'), ('failed', 'Failed'), # The last completed job using this template failed (failed, error, canceled).
('running', 'Running'), ('successful', 'Successful'), # The last completed job using this template succeeded.
('failed', 'Failed'), # For Project only:
('successful', 'Successful'), ('ok', 'OK'), # Project is not configured for SCM and path exists.
# from InventorySource ('missing', 'Missing'), # Project path does not exist.
('none', _('No External Source')), # For Inventory Source only:
('never updated', _('Never Updated')), ('none', _('No External Source')), # Inventory source is not configured to update from an external source.
('updating', _('Updating')), # No longer used for Project / Inventory Source:
#('failed', _('Failed')), ('updating', _('Updating')), # Same as running.
#('successful', _('Successful')),
] ]
class Meta: class Meta:
app_label = 'main' app_label = 'main'
unique_together = [('polymorphic_ctype', 'name')] unique_together = [('polymorphic_ctype', 'name')]
@@ -69,7 +67,7 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
default=None, default=None,
editable=False, editable=False,
) )
current_job = models.ForeignKey( # alias for current_update current_job = models.ForeignKey(
'UnifiedJob', 'UnifiedJob',
null=True, null=True,
default=None, default=None,
@@ -77,7 +75,7 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
related_name='%(class)s_as_current_job+', related_name='%(class)s_as_current_job+',
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
) )
last_job = models.ForeignKey( # alias for last_update last_job = models.ForeignKey(
'UnifiedJob', 'UnifiedJob',
null=True, null=True,
default=None, default=None,
@@ -85,11 +83,11 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
related_name='%(class)s_as_last_job+', related_name='%(class)s_as_last_job+',
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
) )
last_job_failed = models.BooleanField( # alias for last_update_failed last_job_failed = models.BooleanField(
default=False, default=False,
editable=False, editable=False,
) )
last_job_run = models.DateTimeField( # alias for last_updated last_job_run = models.DateTimeField(
null=True, null=True,
default=None, default=None,
editable=False, editable=False,
@@ -160,19 +158,19 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
exclude = [x for x in exclude if x != 'polymorphic_ctype'] exclude = [x for x in exclude if x != 'polymorphic_ctype']
return super(UnifiedJobTemplate, self).validate_unique(exclude) return super(UnifiedJobTemplate, self).validate_unique(exclude)
@property @property # Alias for backwards compatibility.
def current_update(self): def current_update(self):
return self.current_job return self.current_job
@property @property # Alias for backwards compatibility.
def last_update(self): def last_update(self):
return self.last_job return self.last_job
@property @property # Alias for backwards compatibility.
def last_update_failed(self): def last_update_failed(self):
return self.last_job_failed return self.last_job_failed
@property @property # Alias for backwards compatibility.
def last_updated(self): def last_updated(self):
return self.last_job_run return self.last_job_run
@@ -198,7 +196,7 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
def _get_current_status(self): def _get_current_status(self):
# Override in subclasses as needed. # Override in subclasses as needed.
if self.current_job: if self.current_job:
return 'updating' return 'running'
elif not self.last_job: elif not self.last_job:
return 'never updated' return 'never updated'
elif self.last_job_failed: elif self.last_job_failed:
@@ -267,16 +265,27 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
return unified_job return unified_job
class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique): class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique):
''' '''
Concrete base class for unified job run by the task engine. Concrete base class for unified job run by the task engine.
''' '''
STATUS_CHOICES = [
('new', _('New')), # Job has been created, but not started.
('pending', _('Pending')), # Job has been queued, but is not yet running.
('waiting', _('Waiting')), # Job is waiting on an update/dependency.
('running', _('Running')), # Job is currently running.
('successful', _('Successful')), # Job completed successfully.
('failed', _('Failed')), # Job completed, but with failures.
('error', _('Error')), # The job was unable to run.
('canceled', _('Canceled')), # The job was canceled before completion.
]
LAUNCH_TYPE_CHOICES = [ LAUNCH_TYPE_CHOICES = [
('manual', _('Manual')), ('manual', _('Manual')), # Job was started manually by a user.
('callback', _('Callback')), ('callback', _('Callback')), # Job was started via host callback.
('scheduled', _('Scheduled')), ('scheduled', _('Scheduled')), # Job was started from a schedule.
('dependency', _('Dependency')), ('dependency', _('Dependency')), # Job was started as a dependency of another job.
] ]
PASSWORD_FIELDS = ('start_args',) PASSWORD_FIELDS = ('start_args',)
@@ -322,7 +331,7 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
) )
status = models.CharField( status = models.CharField(
max_length=20, max_length=20,
choices=TASK_STATUS_CHOICES, choices=STATUS_CHOICES,
default='new', default='new',
editable=False, editable=False,
) )
@@ -361,6 +370,11 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
default={}, default={},
editable=False, editable=False,
) )
job_explanation = models.TextField(
blank=True,
default='',
editable=False,
)
start_args = models.TextField( start_args = models.TextField(
blank=True, blank=True,
default='', default='',
@@ -396,9 +410,6 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
def _get_parent_field_name(cls): def _get_parent_field_name(cls):
return 'unified_job_template' # Override in subclasses. return 'unified_job_template' # Override in subclasses.
def _get_type(self):
return camelcase_to_underscore(self._meta.object_name)
def __unicode__(self): def __unicode__(self):
return u'%s-%s-%s' % (self.created, self.id, self.status) return u'%s-%s-%s' % (self.created, self.id, self.status)
@@ -422,23 +433,9 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
'last_job_failed']) 'last_job_failed'])
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
new_instance = not bool(self.pk)
# If update_fields has been specified, add our field names to it, # If update_fields has been specified, add our field names to it,
# if it hasn't been specified, then we're just doing a normal save. # if it hasn't been specified, then we're just doing a normal save.
update_fields = kwargs.get('update_fields', []) update_fields = kwargs.get('update_fields', [])
# When first saving to the database, don't store any password field
# values, but instead save them until after the instance is created.
# Otherwise, store encrypted values to the database.
for field in self.PASSWORD_FIELDS:
if new_instance:
value = getattr(self, field, '')
setattr(self, '_saved_%s' % field, value)
setattr(self, field, '')
else:
encrypted = encrypt_field(self, field)
setattr(self, field, encrypted)
if field not in update_fields:
update_fields.append(field)
# Get status before save... # Get status before save...
status_before = self.status or 'new' status_before = self.status or 'new'
if self.pk: if self.pk:
@@ -472,15 +469,6 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
if 'unified_job_template' not in update_fields: if 'unified_job_template' not in update_fields:
update_fields.append('unified_job_template') update_fields.append('unified_job_template')
super(UnifiedJob, self).save(*args, **kwargs) super(UnifiedJob, self).save(*args, **kwargs)
# After saving a new instance for the first time, set the password
# fields and save again.
if new_instance:
update_fields = []
for field in self.PASSWORD_FIELDS:
saved_value = getattr(self, '_saved_%s' % field, '')
setattr(self, field, saved_value)
update_fields.append(field)
self.save(update_fields=update_fields)
# If status changed, update parent instance.... # If status changed, update parent instance....
if self.status != status_before: if self.status != status_before:
self._update_parent_instance() self._update_parent_instance()
@@ -538,8 +526,8 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
''' '''
task_class = self._get_task_class() task_class = self._get_task_class()
if not self.can_start: if not self.can_start:
self.result_traceback = "Job is not in a startable status: %s, expecting one of %s" % (self.status, str(('new', 'waiting'))) self.job_explanation = u'%s is not in a startable status: %s, expecting one of %s' % (self._meta.verbose_name, self.status, str(('new', 'waiting')))
self.save() self.save(update_fields=['job_explanation'])
return False return False
needed = self.get_passwords_needed_to_start() needed = self.get_passwords_needed_to_start()
try: try:
@@ -551,8 +539,8 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
opts = dict([(field, start_args.get(field, '')) for field in needed]) opts = dict([(field, start_args.get(field, '')) for field in needed])
if not all(opts.values()): if not all(opts.values()):
missing_fields = ', '.join([k for k,v in opts.items() if not v]) missing_fields = ', '.join([k for k,v in opts.items() if not v])
self.result_traceback = "Missing needed fields: %s" % missing_fields self.job_explanation = u'Missing needed fields: %s' % missing_fields
self.save() self.save(update_fields=['job_explanation'])
return False return False
task_class().apply_async((self.pk,), opts, link_error=error_callback) task_class().apply_async((self.pk,), opts, link_error=error_callback)
return True return True
@@ -571,7 +559,8 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
if not all(opts.values()): if not all(opts.values()):
return False return False
self.update_fields(start_args=json.dumps(kwargs), status='pending') self.update_fields(start_args=json.dumps(kwargs), status='pending')
# notify_task_runner.delay(dict(task_type=self._get_type(), id=self.id, metadata=kwargs)) task_type = get_type_for_model(self)
# notify_task_runner.delay(dict(task_type=task_type, id=self.id, metadata=kwargs))
return True return True
@property @property
@@ -605,9 +594,9 @@ class UnifiedJob(PolymorphicModel, CommonModelNameNotUnique):
if instance.can_cancel: if instance.can_cancel:
instance.status = 'canceled' instance.status = 'canceled'
update_fields = ['status'] update_fields = ['status']
if not instance.result_traceback: if not instance.job_explanation:
instance.result_traceback = 'Forced cancel' instance.job_explanation = 'Forced cancel'
update_fields.append('result_traceback') update_fields.append('job_explanation')
instance.save(update_fields=update_fields) instance.save(update_fields=update_fields)
except: # FIXME: Log this exception! except: # FIXME: Log this exception!
if settings.DEBUG: if settings.DEBUG:

View File

@@ -99,7 +99,7 @@ def handle_work_error(self, task_id, subtasks=None):
if instance.celery_task_id != task_id: if instance.celery_task_id != task_id:
instance.status = 'failed' instance.status = 'failed'
instance.failed = True instance.failed = True
instance.result_traceback = "Previous Task Failed: %s for %s with celery task id: %s" % \ instance.job_explanation = "Previous Task Failed: %s for %s with celery task id: %s" % \
(first_task_type, first_task_name, task_id) (first_task_type, first_task_name, task_id)
instance.save() instance.save()

View File

@@ -823,7 +823,7 @@ class JobStartCancelTest(BaseJobTestMixin, django.test.LiveServerTestCase):
# Sue can start a job (when passwords are already saved) as long as the # Sue can start a job (when passwords are already saved) as long as the
# status is new. Reverse list so "new" will be last. # status is new. Reverse list so "new" will be last.
for status in reversed([x[0] for x in TASK_STATUS_CHOICES]): for status in reversed([x[0] for x in Job.STATUS_CHOICES]):
if status == 'waiting': if status == 'waiting':
continue continue
job.status = status job.status = status
@@ -920,7 +920,7 @@ class JobStartCancelTest(BaseJobTestMixin, django.test.LiveServerTestCase):
self.check_invalid_auth(url, methods=('post',)) self.check_invalid_auth(url, methods=('post',))
# sue can cancel the job, but only when it is pending or running. # sue can cancel the job, but only when it is pending or running.
for status in [x[0] for x in TASK_STATUS_CHOICES]: for status in [x[0] for x in Job.STATUS_CHOICES]:
if status == 'waiting': if status == 'waiting':
continue continue
job.status = status job.status = status