mirror of
https://github.com/ansible/awx.git
synced 2026-03-22 11:25:08 -02:30
AC-505 Initial inventory import models and API support.
This commit is contained in:
@@ -427,6 +427,45 @@ class GroupAccess(BaseAccess):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
class InventorySourceAccess(BaseAccess):
|
||||||
|
'''
|
||||||
|
I can see inventory sources whenever I can see their group.
|
||||||
|
I can change inventory sources whenever I can change their group.
|
||||||
|
'''
|
||||||
|
|
||||||
|
model = InventorySource
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = self.model.objects.filter(active=True).distinct()
|
||||||
|
qs = qs.select_related('created_by', 'group')
|
||||||
|
groups_qs = self.user.get_queryset(Group)
|
||||||
|
return qs.filter(group__in=groups_qs)
|
||||||
|
|
||||||
|
def can_read(self, obj):
|
||||||
|
return obj and self.user.can_access(Group, 'read', obj.group)
|
||||||
|
|
||||||
|
def can_add(self, data):
|
||||||
|
# Automatically created from group.
|
||||||
|
return False
|
||||||
|
|
||||||
|
def can_change(self, obj, data):
|
||||||
|
# Checks for admin or change permission on group.
|
||||||
|
return obj and self.user.can_access(Group, 'change', obj.group, None)
|
||||||
|
|
||||||
|
class InventoryUpdateAccess(BaseAccess):
|
||||||
|
'''
|
||||||
|
I can see inventory updates when I can see the inventory source.
|
||||||
|
I can change inventory updates whenever I can change their source.
|
||||||
|
'''
|
||||||
|
|
||||||
|
model = InventoryUpdate
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = InventoryUpdate.objects.filter(active=True).distinct()
|
||||||
|
qs = qs.select_related('created_by', 'group')
|
||||||
|
inventory_sources_qs = self.user.get_queryset(InventorySource)
|
||||||
|
return qs.filter(inventory_source__in=inventory_sources_qs)
|
||||||
|
|
||||||
class CredentialAccess(BaseAccess):
|
class CredentialAccess(BaseAccess):
|
||||||
'''
|
'''
|
||||||
I can see credentials when:
|
I can see credentials when:
|
||||||
@@ -970,6 +1009,8 @@ register_access(Organization, OrganizationAccess)
|
|||||||
register_access(Inventory, InventoryAccess)
|
register_access(Inventory, InventoryAccess)
|
||||||
register_access(Host, HostAccess)
|
register_access(Host, HostAccess)
|
||||||
register_access(Group, GroupAccess)
|
register_access(Group, GroupAccess)
|
||||||
|
register_access(InventorySource, InventorySourceAccess)
|
||||||
|
register_access(InventoryUpdate, InventoryUpdateAccess)
|
||||||
register_access(Credential, CredentialAccess)
|
register_access(Credential, CredentialAccess)
|
||||||
register_access(Team, TeamAccess)
|
register_access(Team, TeamAccess)
|
||||||
register_access(Project, ProjectAccess)
|
register_access(Project, ProjectAccess)
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class APIView(views.APIView):
|
|||||||
return {
|
return {
|
||||||
'docstring': type(self).__doc__ or '',
|
'docstring': type(self).__doc__ or '',
|
||||||
'new_in_13': getattr(self, 'new_in_13', False),
|
'new_in_13': getattr(self, 'new_in_13', False),
|
||||||
|
'new_in_14': getattr(self, 'new_in_14', False),
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_description(self, html=False):
|
def get_description(self, html=False):
|
||||||
|
|||||||
430
awx/main/migrations/0016_v14_changes.py
Normal file
430
awx/main/migrations/0016_v14_changes.py
Normal file
@@ -0,0 +1,430 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
# Adding model 'InventoryUpdate'
|
||||||
|
db.create_table(u'main_inventoryupdate', (
|
||||||
|
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||||
|
('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||||
|
('modified', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, auto_now=True, blank=True)),
|
||||||
|
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name="{'class': 'inventoryupdate', 'app_label': 'main'}(class)s_created+", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||||
|
('modified_by', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name="{'class': 'inventoryupdate', 'app_label': 'main'}(class)s_modified+", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||||
|
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||||
|
('inventory_source', self.gf('django.db.models.fields.related.ForeignKey')(related_name='inventory_updates', to=orm['main.InventorySource'])),
|
||||||
|
('cancel_flag', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
('status', self.gf('django.db.models.fields.CharField')(default='new', max_length=20)),
|
||||||
|
('failed', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
('job_args', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||||
|
('job_cwd', self.gf('django.db.models.fields.CharField')(default='', max_length=1024, blank=True)),
|
||||||
|
('job_env', self.gf('jsonfield.fields.JSONField')(default={}, blank=True)),
|
||||||
|
('result_stdout', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||||
|
('result_traceback', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||||
|
('celery_task_id', self.gf('django.db.models.fields.CharField')(default='', max_length=100, blank=True)),
|
||||||
|
))
|
||||||
|
db.send_create_signal('main', ['InventoryUpdate'])
|
||||||
|
|
||||||
|
# Adding model 'InventorySource'
|
||||||
|
db.create_table(u'main_inventorysource', (
|
||||||
|
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||||
|
('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||||
|
('modified', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, auto_now=True, blank=True)),
|
||||||
|
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name="{'class': 'inventorysource', 'app_label': u'main'}(class)s_created+", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||||
|
('modified_by', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name="{'class': 'inventorysource', 'app_label': u'main'}(class)s_modified+", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||||
|
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||||
|
('group', self.gf('awx.main.fields.AutoOneToOneField')(related_name='inventory_source', unique=True, to=orm['main.Group'])),
|
||||||
|
('source', self.gf('django.db.models.fields.CharField')(default='', max_length=32, blank=True)),
|
||||||
|
('source_path', self.gf('django.db.models.fields.CharField')(default='', max_length=1024, blank=True)),
|
||||||
|
('source_env', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||||
|
('source_username', self.gf('django.db.models.fields.CharField')(default='', max_length=1024, blank=True)),
|
||||||
|
('source_password', self.gf('django.db.models.fields.CharField')(default='', max_length=1024, blank=True)),
|
||||||
|
('source_regions', self.gf('django.db.models.fields.CharField')(default='', max_length=1024, blank=True)),
|
||||||
|
('source_tags', self.gf('django.db.models.fields.CharField')(default='', max_length=1024, blank=True)),
|
||||||
|
('overwrite_hosts', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
('overwrite_vars', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
('keep_vars', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
('update_on_launch', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
('current_update', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='inventory_source_as_current_update+', null=True, to=orm['main.InventoryUpdate'])),
|
||||||
|
('last_update', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='inventory_source_as_last_update+', null=True, to=orm['main.InventoryUpdate'])),
|
||||||
|
('last_update_failed', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
('last_updated', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
|
||||||
|
('status', self.gf('django.db.models.fields.CharField')(default='none', max_length=32, null=True)),
|
||||||
|
))
|
||||||
|
db.send_create_signal(u'main', ['InventorySource'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
# Deleting model 'InventoryUpdate'
|
||||||
|
db.delete_table(u'main_inventoryupdate')
|
||||||
|
|
||||||
|
# Deleting model 'InventorySource'
|
||||||
|
db.delete_table(u'main_inventorysource')
|
||||||
|
|
||||||
|
|
||||||
|
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'})
|
||||||
|
},
|
||||||
|
u'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': {'object_name': 'Credential'},
|
||||||
|
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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'}),
|
||||||
|
'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'}),
|
||||||
|
'ssh_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||||
|
'ssh_username': ('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', [], {'related_name': "'credentials'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Team']", 'blank': 'True', 'null': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'credentials'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': u"orm['auth.User']", 'blank': 'True', 'null': '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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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'}),
|
||||||
|
'has_active_failures': ('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']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'groups'", 'to': "orm['main.Inventory']"}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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']"}),
|
||||||
|
'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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'}),
|
||||||
|
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts'", 'to': "orm['main.Inventory']"}),
|
||||||
|
'last_job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts_as_last_job+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Job']", 'blank': 'True', 'null': 'True'}),
|
||||||
|
'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': u"orm['main.JobHostSummary']", 'blank': 'True', 'null': 'True'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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'}),
|
||||||
|
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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']"}),
|
||||||
|
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'main.inventorysource': {
|
||||||
|
'Meta': {'object_name': 'InventorySource'},
|
||||||
|
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventorysource\', \'app_label\': u\'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||||
|
'current_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_source_as_current_update+'", 'null': 'True', 'to': "orm['main.InventoryUpdate']"}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'group': ('awx.main.fields.AutoOneToOneField', [], {'related_name': "'inventory_source'", 'unique': 'True', 'to': "orm['main.Group']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'keep_vars': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_source_as_last_update+'", 'null': 'True', 'to': "orm['main.InventoryUpdate']"}),
|
||||||
|
'last_update_failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_updated': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventorysource\', \'app_label\': u\'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||||
|
'overwrite_hosts': ('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_env': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'source_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', '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_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||||
|
'source_username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||||
|
'status': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '32', 'null': 'True'}),
|
||||||
|
'update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||||
|
},
|
||||||
|
'main.inventoryupdate': {
|
||||||
|
'Meta': {'object_name': 'InventoryUpdate'},
|
||||||
|
'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventoryupdate\', \'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'}),
|
||||||
|
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'inventory_source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventory_updates'", 'to': u"orm['main.InventorySource']"}),
|
||||||
|
'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'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventoryupdate\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||||
|
'result_stdout': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'})
|
||||||
|
},
|
||||||
|
'main.job': {
|
||||||
|
'Meta': {'object_name': 'Job'},
|
||||||
|
'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'job\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||||
|
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Credential']"}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
|
||||||
|
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'jobs'", 'blank': 'True', 'through': u"orm['main.JobHostSummary']", 'to': "orm['main.Host']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||||
|
'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_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'}),
|
||||||
|
'launch_type': ('django.db.models.fields.CharField', [], {'default': "'manual'", 'max_length': '20'}),
|
||||||
|
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'job\', \'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'}),
|
||||||
|
'playbook': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
|
||||||
|
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['main.Project']"}),
|
||||||
|
'result_stdout': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'}),
|
||||||
|
'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': 'datetime.datetime.now', 'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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', [], {'related_name': "'job_events_as_primary_host'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Host']", 'blank': 'True', 'null': 'True'}),
|
||||||
|
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'job_events'", 'blank': 'True', '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': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobEvent']", 'blank': 'True', 'null': 'True'}),
|
||||||
|
'play': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||||
|
'task': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'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': 'datetime.datetime.now', 'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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'},
|
||||||
|
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'jobtemplate\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||||
|
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': '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'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", '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'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'jobtemplate\', \'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'}),
|
||||||
|
'playbook': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||||
|
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['main.Project']"}),
|
||||||
|
'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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': u"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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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': u"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']"})
|
||||||
|
},
|
||||||
|
u'main.profile': {
|
||||||
|
'Meta': {'object_name': 'Profile'},
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
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', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'user': ('awx.main.fields.AutoOneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': u"orm['auth.User']"})
|
||||||
|
},
|
||||||
|
u'main.project': {
|
||||||
|
'Meta': {'object_name': 'Project'},
|
||||||
|
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'project\', \'app_label\': u\'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||||
|
'current_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'project_as_current_update+'", 'null': 'True', 'to': "orm['main.ProjectUpdate']"}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'last_update': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'project_as_last_update+'", 'null': 'True', 'to': "orm['main.ProjectUpdate']"}),
|
||||||
|
'last_update_failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_updated': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||||
|
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'project\', \'app_label\': u\'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'}),
|
||||||
|
'scm_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'null': 'True', '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_key_data': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
|
||||||
|
'scm_key_unlock': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'scm_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'scm_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'scm_update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'scm_url': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'scm_username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'status': ('django.db.models.fields.CharField', [], {'default': "'ok'", 'max_length': '32', 'null': 'True'})
|
||||||
|
},
|
||||||
|
'main.projectupdate': {
|
||||||
|
'Meta': {'object_name': 'ProjectUpdate'},
|
||||||
|
'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', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'projectupdate\', \'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'}),
|
||||||
|
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
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'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'projectupdate\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||||
|
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'project_updates'", 'to': u"orm['main.Project']"}),
|
||||||
|
'result_stdout': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||||
|
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'})
|
||||||
|
},
|
||||||
|
'main.team': {
|
||||||
|
'Meta': {'object_name': 'Team'},
|
||||||
|
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'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': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
|
||||||
|
'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', [], {'unique': 'True', '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': u"orm['main.Project']"}),
|
||||||
|
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': u"orm['auth.User']"})
|
||||||
|
},
|
||||||
|
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']
|
||||||
@@ -40,8 +40,8 @@ from awx.main.utils import encrypt_field, decrypt_field
|
|||||||
|
|
||||||
__all__ = ['PrimordialModel', 'Organization', 'Team', 'Project',
|
__all__ = ['PrimordialModel', 'Organization', 'Team', 'Project',
|
||||||
'ProjectUpdate', 'Credential', 'Inventory', 'Host', 'Group',
|
'ProjectUpdate', 'Credential', 'Inventory', 'Host', 'Group',
|
||||||
'Permission', 'JobTemplate', 'Job', 'JobHostSummary', 'JobEvent',
|
'InventorySource', 'InventoryUpdate', 'Permission', 'JobTemplate',
|
||||||
'AuthToken',
|
'Job', 'JobHostSummary', 'JobEvent', 'AuthToken',
|
||||||
'PERM_INVENTORY_ADMIN', 'PERM_INVENTORY_READ',
|
'PERM_INVENTORY_ADMIN', 'PERM_INVENTORY_READ',
|
||||||
'PERM_INVENTORY_WRITE', 'PERM_INVENTORY_DEPLOY',
|
'PERM_INVENTORY_WRITE', 'PERM_INVENTORY_DEPLOY',
|
||||||
'PERM_INVENTORY_CHECK', 'JOB_STATUS_CHOICES']
|
'PERM_INVENTORY_CHECK', 'JOB_STATUS_CHOICES']
|
||||||
@@ -254,6 +254,14 @@ class Host(CommonModelNameNotUnique):
|
|||||||
last_job_host_summary = models.ForeignKey('JobHostSummary', blank=True, null=True, default=None, on_delete=models.SET_NULL, related_name='hosts_as_last_job_summary+')
|
last_job_host_summary = models.ForeignKey('JobHostSummary', blank=True, null=True, default=None, on_delete=models.SET_NULL, related_name='hosts_as_last_job_summary+')
|
||||||
has_active_failures = models.BooleanField(default=False, editable=False)
|
has_active_failures = models.BooleanField(default=False, editable=False)
|
||||||
|
|
||||||
|
# FIXME: Track which inventory source(s) created this host.
|
||||||
|
#inventory_sources = models.ManyToManyField(
|
||||||
|
# 'InventorySource',
|
||||||
|
# related_name='synced_hosts',
|
||||||
|
# blank=True,
|
||||||
|
# editable=False,
|
||||||
|
#)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@@ -317,6 +325,14 @@ class Group(CommonModelNameNotUnique):
|
|||||||
hosts = models.ManyToManyField('Host', related_name='groups', blank=True)
|
hosts = models.ManyToManyField('Host', related_name='groups', blank=True)
|
||||||
has_active_failures = models.BooleanField(default=False, editable=False)
|
has_active_failures = models.BooleanField(default=False, editable=False)
|
||||||
|
|
||||||
|
# FIXME: Track which inventory source(s) created this group.
|
||||||
|
#inventory_sources = models.ManyToManyField(
|
||||||
|
# 'InventorySource',
|
||||||
|
# related_name='synced_groups',
|
||||||
|
# blank=True,
|
||||||
|
# editable=False,
|
||||||
|
#)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@@ -407,6 +423,341 @@ class Group(CommonModelNameNotUnique):
|
|||||||
def job_events(self):
|
def job_events(self):
|
||||||
return JobEvent.objects.filter(host__in=self.all_hosts)
|
return JobEvent.objects.filter(host__in=self.all_hosts)
|
||||||
|
|
||||||
|
class InventorySource(PrimordialModel):
|
||||||
|
|
||||||
|
# FIXME: Track inventory source for import via management command?
|
||||||
|
|
||||||
|
SOURCE_CHOICES = [
|
||||||
|
('file', _('Local File or Script')),
|
||||||
|
('rackspace', _('Rackspace Cloud Servers')),
|
||||||
|
('ec2', _('Amazon EC2')),
|
||||||
|
]
|
||||||
|
|
||||||
|
PASSWORD_FIELDS = ('source_password',)
|
||||||
|
|
||||||
|
INVENTORY_SOURCE_STATUS_CHOICES = [
|
||||||
|
('none', _('No External Source')),
|
||||||
|
('never updated', _('Never Updated')),
|
||||||
|
('updating', _('Updating')),
|
||||||
|
('failed', _('Failed')),
|
||||||
|
('successful', _('Successful')),
|
||||||
|
]
|
||||||
|
|
||||||
|
group = AutoOneToOneField(
|
||||||
|
'Group',
|
||||||
|
related_name='inventory_source',
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
source = models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
choices=SOURCE_CHOICES,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
source_path = models.CharField(
|
||||||
|
max_length=1024,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
source_env = models.TextField(
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
source_username = models.CharField(
|
||||||
|
max_length=1024,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
source_password = models.CharField(
|
||||||
|
max_length=1024,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
source_regions = models.CharField(
|
||||||
|
max_length=1024,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
source_tags = models.CharField(
|
||||||
|
max_length=1024,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
)
|
||||||
|
overwrite_hosts = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
overwrite_vars = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
keep_vars = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
update_on_launch = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
current_update = models.ForeignKey(
|
||||||
|
'InventoryUpdate',
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
editable=False,
|
||||||
|
related_name='inventory_source_as_current_update+',
|
||||||
|
)
|
||||||
|
last_update = models.ForeignKey(
|
||||||
|
'InventoryUpdate',
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
editable=False,
|
||||||
|
related_name='inventory_source_as_last_update+',
|
||||||
|
)
|
||||||
|
last_update_failed = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
last_updated = models.DateTimeField(
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
status = models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
choices=INVENTORY_SOURCE_STATUS_CHOICES,
|
||||||
|
default='none',
|
||||||
|
editable=False,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
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.
|
||||||
|
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:
|
||||||
|
for field in self.PASSWORD_FIELDS:
|
||||||
|
encrypted = encrypt_field(self, field, True)
|
||||||
|
if getattr(self, field) != encrypted:
|
||||||
|
setattr(self, field, encrypted)
|
||||||
|
if field not in update_fields:
|
||||||
|
update_fields.append(field)
|
||||||
|
# Update status and last_updated fields.
|
||||||
|
updated_fields = self.set_status_and_last_updated(save=False)
|
||||||
|
for field in updated_fields:
|
||||||
|
if field not in update_fields:
|
||||||
|
update_fields.append(field)
|
||||||
|
# Do the actual save.
|
||||||
|
super(InventorySource, self).save(*args, **kwargs)
|
||||||
|
# After saving a new instance for the first time (to get a primary
|
||||||
|
# key), 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, '')
|
||||||
|
if getattr(self, field) != saved_value:
|
||||||
|
setattr(self, field, saved_value)
|
||||||
|
update_fields.append(field)
|
||||||
|
if update_fields:
|
||||||
|
self.save(update_fields=update_fields)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def needs_source_password(self):
|
||||||
|
return self.source and self.source_password == 'ASK'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_passwords_needed(self):
|
||||||
|
needed = []
|
||||||
|
for field in ('source_password',):
|
||||||
|
if getattr(self, 'needs_%s' % field):
|
||||||
|
needed.append(field)
|
||||||
|
return needed
|
||||||
|
|
||||||
|
def set_status_and_last_updated(self, save=True):
|
||||||
|
# Determine current status.
|
||||||
|
if self.source:
|
||||||
|
if self.current_update:
|
||||||
|
status = 'updating'
|
||||||
|
elif not self.last_update:
|
||||||
|
status = 'never updated'
|
||||||
|
elif self.last_update_failed:
|
||||||
|
status = 'failed'
|
||||||
|
else:
|
||||||
|
status = 'successful'
|
||||||
|
else:
|
||||||
|
status = 'none'
|
||||||
|
# Determine current last_updated timestamp.
|
||||||
|
last_updated = None
|
||||||
|
if self.source and self.last_update:
|
||||||
|
last_updated = self.last_update.modified
|
||||||
|
# Update values if changed.
|
||||||
|
update_fields = []
|
||||||
|
if self.status != status:
|
||||||
|
self.status = status
|
||||||
|
update_fields.append('status')
|
||||||
|
if self.last_updated != last_updated:
|
||||||
|
self.last_updated = last_updated
|
||||||
|
update_fields.append('last_updated')
|
||||||
|
if save and update_fields:
|
||||||
|
self.save(update_fields=update_fields)
|
||||||
|
return update_fields
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_update(self):
|
||||||
|
# FIXME: Prevent update when another one is active!
|
||||||
|
return bool(self.source)
|
||||||
|
|
||||||
|
def update(self, **kwargs):
|
||||||
|
if self.can_update:
|
||||||
|
needed = self.source_passwords_needed
|
||||||
|
opts = dict([(field, kwargs.get(field, '')) for field in needed])
|
||||||
|
if not all(opts.values()):
|
||||||
|
return
|
||||||
|
inventory_update = self.inventory_updates.create()
|
||||||
|
inventory_update.start(**opts)
|
||||||
|
return inventory_update
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('main:inventory_source_detail', args=(self.pk,))
|
||||||
|
|
||||||
|
class InventoryUpdate(PrimordialModel):
|
||||||
|
'''
|
||||||
|
Internal job for tracking inventory updates from external sources.
|
||||||
|
'''
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'main'
|
||||||
|
|
||||||
|
inventory_source = models.ForeignKey(
|
||||||
|
'InventorySource',
|
||||||
|
related_name='inventory_updates',
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
cancel_flag = models.BooleanField(
|
||||||
|
blank=True,
|
||||||
|
default=False,
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
status = models.CharField(
|
||||||
|
max_length=20,
|
||||||
|
choices=JOB_STATUS_CHOICES,
|
||||||
|
default='new',
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
failed = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
job_args = models.TextField(
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
job_cwd = models.CharField(
|
||||||
|
max_length=1024,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
job_env = JSONField(
|
||||||
|
blank=True,
|
||||||
|
default={},
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
result_stdout = models.TextField(
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
result_traceback = models.TextField(
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
celery_task_id = models.CharField(
|
||||||
|
max_length=100,
|
||||||
|
blank=True,
|
||||||
|
default='',
|
||||||
|
editable=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u'%s-%s-%s' % (self.created, self.id, self.status)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
# Get status before save...
|
||||||
|
status_before = self.status or 'new'
|
||||||
|
if self.pk:
|
||||||
|
inventory_update_before = InventoryUpdate.objects.get(pk=self.pk)
|
||||||
|
if inventory_update_before.status != self.status:
|
||||||
|
status_before = inventory_update_before.status
|
||||||
|
self.failed = bool(self.status in ('failed', 'error', 'canceled'))
|
||||||
|
super(InventoryUpdate, self).save(*args, **kwargs)
|
||||||
|
# If status changed, update inventory.
|
||||||
|
if self.status != status_before:
|
||||||
|
if self.status in ('pending', 'waiting', 'running'):
|
||||||
|
inventory_source = self.inventory_source
|
||||||
|
if inventory_source.current_update != self:
|
||||||
|
inventory_source.current_update = self
|
||||||
|
inventory_source.save(update_fields=['current_update'])
|
||||||
|
elif self.status in ('successful', 'failed', 'error', 'canceled'):
|
||||||
|
inventory_source = self.inventory_source
|
||||||
|
if inventory_source.current_update == self:
|
||||||
|
inventory_source.current_update = None
|
||||||
|
inventory_source.last_update = self
|
||||||
|
inventory_source.last_update_failed = self.failed
|
||||||
|
inventory_source.save(update_fields=['current_update', 'last_update',
|
||||||
|
'last_update_failed'])
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('main:inventory_update_detail', args=(self.pk,))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def celery_task(self):
|
||||||
|
try:
|
||||||
|
if self.celery_task_id:
|
||||||
|
return TaskMeta.objects.get(task_id=self.celery_task_id)
|
||||||
|
except TaskMeta.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_start(self):
|
||||||
|
return bool(self.status == 'new')
|
||||||
|
|
||||||
|
def start(self, **kwargs):
|
||||||
|
from awx.main.tasks import RunInventoryUpdate
|
||||||
|
needed = self.inventory_source.source_passwords_needed
|
||||||
|
opts = dict([(field, kwargs.get(field, '')) for field in needed])
|
||||||
|
if not all(opts.values()):
|
||||||
|
return False
|
||||||
|
self.status = 'pending'
|
||||||
|
self.save(update_fields=['status'])
|
||||||
|
task_result = RunInventoryUpdate().delay(self.pk, **opts)
|
||||||
|
# Reload inventory update from database so we don't clobber results
|
||||||
|
# from RunInventoryUpdate (mainly from tests when using Django 1.4.x).
|
||||||
|
inventory_update = InventoryUpdate.objects.get(pk=self.pk)
|
||||||
|
# The TaskMeta instance in the database isn't created until the worker
|
||||||
|
# starts processing the task, so we can only store the task ID here.
|
||||||
|
inventory_update.celery_task_id = task_result.task_id
|
||||||
|
inventory_update.save(update_fields=['celery_task_id'])
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_cancel(self):
|
||||||
|
return bool(self.status in ('pending', 'waiting', 'running'))
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
if self.can_cancel:
|
||||||
|
if not self.cancel_flag:
|
||||||
|
self.cancel_flag = True
|
||||||
|
self.save(update_fields=['cancel_flag'])
|
||||||
|
return self.cancel_flag
|
||||||
|
|
||||||
class Credential(CommonModelNameNotUnique):
|
class Credential(CommonModelNameNotUnique):
|
||||||
'''
|
'''
|
||||||
A credential contains information about how to talk to a remote set of hosts
|
A credential contains information about how to talk to a remote set of hosts
|
||||||
|
|||||||
@@ -488,6 +488,7 @@ class GroupSerializer(BaseSerializerWithVariables):
|
|||||||
inventory = reverse('main:inventory_detail', args=(obj.inventory.pk,)),
|
inventory = reverse('main:inventory_detail', args=(obj.inventory.pk,)),
|
||||||
job_events = reverse('main:group_job_events_list', args=(obj.pk,)),
|
job_events = reverse('main:group_job_events_list', args=(obj.pk,)),
|
||||||
job_host_summaries = reverse('main:group_job_host_summaries_list', args=(obj.pk,)),
|
job_host_summaries = reverse('main:group_job_host_summaries_list', args=(obj.pk,)),
|
||||||
|
inventory_source = reverse('main:inventory_source_detail', args=(obj.inventory_source.pk,)),
|
||||||
))
|
))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@@ -541,6 +542,67 @@ class GroupVariableDataSerializer(BaseVariableDataSerializer):
|
|||||||
model = Group
|
model = Group
|
||||||
fields = ('variables',)
|
fields = ('variables',)
|
||||||
|
|
||||||
|
class InventorySourceSerializer(BaseSerializer):
|
||||||
|
|
||||||
|
source_password = serializers.WritableField(required=False, default='')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = InventorySource
|
||||||
|
fields = ('id', 'url', 'related', 'summary_fields', 'created',
|
||||||
|
'modified', 'group', 'source', 'source_path', 'source_env',
|
||||||
|
'source_username', 'source_password', 'source_regions',
|
||||||
|
'source_tags', 'overwrite_hosts', 'overwrite_vars',
|
||||||
|
'keep_vars', 'update_on_launch', 'last_update_failed',
|
||||||
|
'status', 'last_updated')
|
||||||
|
|
||||||
|
def to_native(self, obj):
|
||||||
|
ret = super(InventorySourceSerializer, self).to_native(obj)
|
||||||
|
# Replace the actual encrypted value with the string $encrypted$.
|
||||||
|
for field in InventorySource.PASSWORD_FIELDS:
|
||||||
|
if field in ret and unicode(ret[field]).startswith('$encrypted$'):
|
||||||
|
ret[field] = '$encrypted$'
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def restore_object(self, attrs, instance=None):
|
||||||
|
# If the value sent to the API startswith $encrypted$, ignore it.
|
||||||
|
for field in InventorySource.PASSWORD_FIELDS:
|
||||||
|
if unicode(attrs.get(field, '')).startswith('$encrypted$'):
|
||||||
|
attrs.pop(field, None)
|
||||||
|
instance = super(InventorySourceSerializer, self).restore_object(attrs, instance)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def get_related(self, obj):
|
||||||
|
res = super(InventorySourceSerializer, self).get_related(obj)
|
||||||
|
res.update(dict(
|
||||||
|
group = reverse('main:group_detail', args=(obj.group.pk,)),
|
||||||
|
update = reverse('main:inventory_source_update_view', args=(obj.pk,)),
|
||||||
|
inventory_updates = reverse('main:inventory_source_updates_list', args=(obj.pk,)),
|
||||||
|
))
|
||||||
|
if obj.current_update:
|
||||||
|
res['current_update'] = reverse('main:inventory_update_detail',
|
||||||
|
args=(obj.current_update.pk,))
|
||||||
|
if obj.last_update:
|
||||||
|
res['last_update'] = reverse('main:inventory_update_detail',
|
||||||
|
args=(obj.last_update.pk,))
|
||||||
|
return res
|
||||||
|
|
||||||
|
class InventoryUpdateSerializer(BaseSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = InventoryUpdate
|
||||||
|
fields = ('id', 'url', 'related', 'summary_fields', 'created',
|
||||||
|
'modified', 'inventory_source', 'status', 'failed',
|
||||||
|
'result_stdout', 'result_traceback', 'job_args', 'job_cwd',
|
||||||
|
'job_env')
|
||||||
|
|
||||||
|
def get_related(self, obj):
|
||||||
|
res = super(InventoryUpdateSerializer, self).get_related(obj)
|
||||||
|
res.update(dict(
|
||||||
|
inventory_source = reverse('main:inventory_source_detail', args=(obj.inventory_source.pk,)),
|
||||||
|
cancel = reverse('main:inventory_update_cancel', args=(obj.pk,)),
|
||||||
|
))
|
||||||
|
return res
|
||||||
|
|
||||||
class TeamSerializer(BaseSerializer):
|
class TeamSerializer(BaseSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ from django.conf import settings
|
|||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models import Job, ProjectUpdate
|
from awx.main.models import Job, ProjectUpdate, InventoryUpdate
|
||||||
from awx.main.utils import get_ansible_version, decrypt_field, update_scm_url
|
from awx.main.utils import get_ansible_version, decrypt_field, update_scm_url
|
||||||
|
|
||||||
__all__ = ['RunJob', 'RunProjectUpdate']
|
__all__ = ['RunJob', 'RunProjectUpdate', 'RunInventoryImport']
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.tasks')
|
logger = logging.getLogger('awx.main.tasks')
|
||||||
|
|
||||||
@@ -231,12 +231,12 @@ class BaseTask(Task):
|
|||||||
Run the job/task using ansible-playbook and capture its output.
|
Run the job/task using ansible-playbook and capture its output.
|
||||||
'''
|
'''
|
||||||
instance = self.update_model(pk)
|
instance = self.update_model(pk)
|
||||||
if not self.pre_run_check(instance, **kwargs):
|
|
||||||
return
|
|
||||||
instance = self.update_model(pk, status='running')
|
|
||||||
status, stdout, tb = 'error', '', ''
|
status, stdout, tb = 'error', '', ''
|
||||||
output_replacements = []
|
output_replacements = []
|
||||||
try:
|
try:
|
||||||
|
if not self.pre_run_check(instance, **kwargs):
|
||||||
|
return
|
||||||
|
instance = self.update_model(pk, status='running')
|
||||||
kwargs['ssh_key_path'] = self.build_ssh_key_path(instance, **kwargs)
|
kwargs['ssh_key_path'] = self.build_ssh_key_path(instance, **kwargs)
|
||||||
kwargs['passwords'] = self.build_passwords(instance, **kwargs)
|
kwargs['passwords'] = self.build_passwords(instance, **kwargs)
|
||||||
args = self.build_args(instance, **kwargs)
|
args = self.build_args(instance, **kwargs)
|
||||||
@@ -322,7 +322,8 @@ class RunJob(BaseTask):
|
|||||||
# it doesn't make sense to rely on ansible-playbook's default of using
|
# it doesn't make sense to rely on ansible-playbook's default of using
|
||||||
# the current user.
|
# the current user.
|
||||||
ssh_username = ssh_username or 'root'
|
ssh_username = ssh_username or 'root'
|
||||||
inventory_script = self.get_path_to('..', 'scripts', 'inventory.py')
|
inventory_script = self.get_path_to('..', 'plugins', 'inventory',
|
||||||
|
'awx.py')
|
||||||
args = ['ansible-playbook', '-i', inventory_script]
|
args = ['ansible-playbook', '-i', inventory_script]
|
||||||
if job.job_type == 'check':
|
if job.job_type == 'check':
|
||||||
args.append('--check')
|
args.append('--check')
|
||||||
@@ -622,3 +623,26 @@ class RunProjectUpdate(BaseTask):
|
|||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
class RunInventoryUpdate(BaseTask):
|
||||||
|
|
||||||
|
name = 'run_inventory_update'
|
||||||
|
model = InventoryUpdate
|
||||||
|
|
||||||
|
def build_env(self, inventory_update, **kwargs):
|
||||||
|
'''
|
||||||
|
Build environment dictionary for inventory import.
|
||||||
|
'''
|
||||||
|
env = super(RunInventoryUpdate, self).build_env(inventory_update, **kwargs)
|
||||||
|
# FIXME
|
||||||
|
return env
|
||||||
|
|
||||||
|
def build_args(self, inventory_update, **kwargs):
|
||||||
|
'''
|
||||||
|
Build command line argument list for running inventory import.
|
||||||
|
'''
|
||||||
|
# FIXME
|
||||||
|
return ['echo', 'FIXME']
|
||||||
|
|
||||||
|
def build_cwd(self, inventory_update, **kwargs):
|
||||||
|
return self.get_path_to('..', 'plugins', 'inventory')
|
||||||
|
|||||||
@@ -575,8 +575,8 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest):
|
|||||||
#os.environ.setdefault('REST_API_TOKEN',
|
#os.environ.setdefault('REST_API_TOKEN',
|
||||||
# self.super_django_user.auth_token.key)
|
# self.super_django_user.auth_token.key)
|
||||||
os.environ['INVENTORY_ID'] = str(old_inv.pk)
|
os.environ['INVENTORY_ID'] = str(old_inv.pk)
|
||||||
source = os.path.join(os.path.dirname(__file__), '..', '..', 'scripts',
|
source = os.path.join(os.path.dirname(__file__), '..', '..', 'plugins',
|
||||||
'inventory.py')
|
'inventory', 'awx.py')
|
||||||
result, stdout, stderr = self.run_command('inventory_import',
|
result, stdout, stderr = self.run_command('inventory_import',
|
||||||
inventory_id=new_inv.pk,
|
inventory_id=new_inv.pk,
|
||||||
source=source)
|
source=source)
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ class InventoryScriptTest(BaseScriptTest):
|
|||||||
os.environ.setdefault('REST_API_URL', rest_api_url)
|
os.environ.setdefault('REST_API_URL', rest_api_url)
|
||||||
#os.environ.setdefault('REST_API_TOKEN',
|
#os.environ.setdefault('REST_API_TOKEN',
|
||||||
# self.super_django_user.auth_token.key)
|
# self.super_django_user.auth_token.key)
|
||||||
name = os.path.join(os.path.dirname(__file__), '..', '..', 'scripts',
|
name = os.path.join(os.path.dirname(__file__), '..', '..', 'plugins',
|
||||||
'inventory.py')
|
'inventory', 'awx.py')
|
||||||
return self.run_script(name, *args, **options)
|
return self.run_script(name, *args, **options)
|
||||||
|
|
||||||
def test_without_inventory_id(self):
|
def test_without_inventory_id(self):
|
||||||
|
|||||||
@@ -86,6 +86,17 @@ group_urls = patterns('awx.main.views',
|
|||||||
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', 'group_job_host_summaries_list'),
|
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', 'group_job_host_summaries_list'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
inventory_source_urls = patterns('awx.main.views',
|
||||||
|
url(r'^(?P<pk>[0-9]+)/$', 'inventory_source_detail'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/update/$', 'inventory_source_update_view'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/inventory_updates/$', 'inventory_source_updates_list'),
|
||||||
|
)
|
||||||
|
|
||||||
|
inventory_update_urls = patterns('awx.main.views',
|
||||||
|
url(r'^(?P<pk>[0-9]+)/$', 'inventory_update_detail'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/cancel/$', 'inventory_update_cancel'),
|
||||||
|
)
|
||||||
|
|
||||||
credential_urls = patterns('awx.main.views',
|
credential_urls = patterns('awx.main.views',
|
||||||
url(r'^$', 'credential_list'),
|
url(r'^$', 'credential_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', 'credential_detail'),
|
url(r'^(?P<pk>[0-9]+)/$', 'credential_detail'),
|
||||||
@@ -136,6 +147,8 @@ v1_urls = patterns('awx.main.views',
|
|||||||
url(r'^inventories/', include(inventory_urls)),
|
url(r'^inventories/', include(inventory_urls)),
|
||||||
url(r'^hosts/', include(host_urls)),
|
url(r'^hosts/', include(host_urls)),
|
||||||
url(r'^groups/', include(group_urls)),
|
url(r'^groups/', include(group_urls)),
|
||||||
|
url(r'^inventory_sources/', include(inventory_source_urls)),
|
||||||
|
url(r'^inventory_updates/', include(inventory_update_urls)),
|
||||||
url(r'^credentials/', include(credential_urls)),
|
url(r'^credentials/', include(credential_urls)),
|
||||||
url(r'^permissions/', include(permission_urls)),
|
url(r'^permissions/', include(permission_urls)),
|
||||||
url(r'^job_templates/', include(job_template_urls)),
|
url(r'^job_templates/', include(job_template_urls)),
|
||||||
|
|||||||
@@ -680,6 +680,74 @@ class InventoryTreeView(RetrieveAPIView):
|
|||||||
})
|
})
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
class InventorySourceDetail(RetrieveUpdateAPIView):
|
||||||
|
|
||||||
|
model = InventorySource
|
||||||
|
serializer_class = InventorySourceSerializer
|
||||||
|
new_in_14 = True
|
||||||
|
|
||||||
|
class InventorySourceUpdatesList(SubListAPIView):
|
||||||
|
|
||||||
|
model = InventoryUpdate
|
||||||
|
serializer_class = InventoryUpdateSerializer
|
||||||
|
parent_model = InventorySource
|
||||||
|
relationship = 'inventory_updates'
|
||||||
|
new_in_14 = True
|
||||||
|
|
||||||
|
class InventorySourceUpdateView(GenericAPIView):
|
||||||
|
|
||||||
|
model = InventorySource
|
||||||
|
new_in_14 = True
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
data = dict(
|
||||||
|
can_update=obj.can_update,
|
||||||
|
)
|
||||||
|
if obj.source:
|
||||||
|
data['passwords_needed_to_update'] = obj.source_passwords_needed
|
||||||
|
return Response(data)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
if obj.can_update:
|
||||||
|
inventory_update = obj.update(**request.DATA)
|
||||||
|
if not inventory_update:
|
||||||
|
data = dict(passwords_needed_to_update=obj.source_passwords_needed)
|
||||||
|
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
else:
|
||||||
|
headers = {'Location': inventory_update.get_absolute_url()}
|
||||||
|
return Response(status=status.HTTP_202_ACCEPTED, headers=headers)
|
||||||
|
else:
|
||||||
|
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||||
|
|
||||||
|
class InventoryUpdateDetail(RetrieveAPIView):
|
||||||
|
|
||||||
|
model = InventoryUpdate
|
||||||
|
serializer_class = InventoryUpdateSerializer
|
||||||
|
new_in_14 = True
|
||||||
|
|
||||||
|
class InventoryUpdateCancel(GenericAPIView):
|
||||||
|
|
||||||
|
model = InventoryUpdate
|
||||||
|
is_job_cancel = True
|
||||||
|
new_in_14 = True
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
data = dict(
|
||||||
|
can_cancel=obj.can_cancel,
|
||||||
|
)
|
||||||
|
return Response(data)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
if obj.can_cancel:
|
||||||
|
result = obj.cancel()
|
||||||
|
return Response(status=status.HTTP_202_ACCEPTED)
|
||||||
|
else:
|
||||||
|
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||||
|
|
||||||
class JobTemplateList(ListCreateAPIView):
|
class JobTemplateList(ListCreateAPIView):
|
||||||
|
|
||||||
model = JobTemplate
|
model = JobTemplate
|
||||||
|
|||||||
@@ -45,9 +45,10 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
# If running from an AWX installation, use the local version of requests if
|
# If running from an AWX installation, use the local version of requests if
|
||||||
# if cannot be found globally.
|
# if cannot be found globally.
|
||||||
local_site_packages = os.path.join(os.path.dirname(__file__), '..', 'lib',
|
local_site_packages = os.path.join(os.path.dirname(__file__), '..', '..',
|
||||||
'site-packages')
|
'lib', 'site-packages')
|
||||||
sys.path.insert(0, local_site_packages)
|
if os.path.exists(local_site_packages):
|
||||||
|
sys.path.insert(0, local_site_packages)
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
class TokenAuth(requests.auth.AuthBase):
|
class TokenAuth(requests.auth.AuthBase):
|
||||||
@@ -121,9 +122,6 @@ class InventoryScript(object):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
# Always return an empty hash on stdout, even when an error occurs.
|
# Always return an empty hash on stdout, even when an error occurs.
|
||||||
sys.stdout.write(json.dumps({}))
|
sys.stdout.write(json.dumps({}))
|
||||||
#print >> file(os.path.join(os.path.dirname(__file__), 'foo.log'), 'a'), repr(e)
|
|
||||||
#if hasattr(e, 'response'):
|
|
||||||
# print >> file(os.path.join(os.path.dirname(__file__), 'foo.log'), 'a'), e.response.content
|
|
||||||
if self.options.get('traceback', False):
|
if self.options.get('traceback', False):
|
||||||
raise
|
raise
|
||||||
sys.stderr.write(str(e) + '\n')
|
sys.stderr.write(str(e) + '\n')
|
||||||
Reference in New Issue
Block a user