mirror of
https://github.com/ansible/awx.git
synced 2026-03-04 18:21:03 -03:30
AC-1040 Model cleanup/refactor, add and use job_explanation field.
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
452
awx/main/migrations/0039_v148_changes.py
Normal file
452
awx/main/migrations/0039_v148_changes.py
Normal 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']
|
||||||
@@ -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
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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,))
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user