mirror of
https://github.com/ansible/awx.git
synced 2026-01-19 13:41:28 -03:30
Renamed LaunchJob to JobTemplate, LaunchJobStatus to Job, LaunchJobHostSummary to JobHostSummary, and LaunchJobStatusEvent to JobEvent. Updated admin, celery task, management commands accordingly.
This commit is contained in:
parent
5e6ad5a244
commit
aff422c976
@ -16,6 +16,7 @@
|
||||
|
||||
|
||||
import json
|
||||
import urllib
|
||||
|
||||
from django.conf.urls import *
|
||||
from django.contrib import admin
|
||||
@ -51,7 +52,16 @@ admin.site.register(User, UserAdmin)
|
||||
|
||||
# FIXME: Hide auth.Group admin
|
||||
|
||||
class OrganizationAdmin(admin.ModelAdmin):
|
||||
class BaseModelAdmin(admin.ModelAdmin):
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
# Automatically set created_by when saved from the admin.
|
||||
# FIXME: Doesn't handle inline model instances yet.
|
||||
if hasattr(obj, 'created_by') and obj.created_by is None:
|
||||
obj.created_by = request.user
|
||||
return super(BaseModelAdmin, self).save_model(request, obj, form, change)
|
||||
|
||||
class OrganizationAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active')
|
||||
list_filter = ('active', 'tags')
|
||||
@ -62,7 +72,7 @@ class OrganizationAdmin(admin.ModelAdmin):
|
||||
(_('Tags'), {'fields': ('tags',)}),
|
||||
(_('Audit Trail'), {'fields': ('creation_date', 'audit_trail',)}),
|
||||
)
|
||||
readonly_fields = ('creation_date', 'audit_trail')
|
||||
readonly_fields = ('creation_date', 'created_by', 'audit_trail')
|
||||
filter_horizontal = ('users', 'admins', 'projects', 'tags')
|
||||
|
||||
class InventoryHostInline(admin.StackedInline):
|
||||
@ -79,7 +89,7 @@ class InventoryGroupInline(admin.StackedInline):
|
||||
fields = ('name', 'description', 'active', 'parents', 'hosts', 'tags')
|
||||
filter_horizontal = ('parents', 'hosts', 'tags')
|
||||
|
||||
class InventoryAdmin(admin.ModelAdmin):
|
||||
class InventoryAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'organization', 'description', 'active')
|
||||
list_filter = ('organization', 'active')
|
||||
@ -89,11 +99,11 @@ class InventoryAdmin(admin.ModelAdmin):
|
||||
(_('Tags'), {'fields': ('tags',)}),
|
||||
(_('Audit Trail'), {'fields': ('creation_date', 'audit_trail',)}),
|
||||
)
|
||||
readonly_fields = ('creation_date', 'audit_trail')
|
||||
readonly_fields = ('creation_date', 'created_by', 'audit_trail')
|
||||
filter_horizontal = ('tags',)
|
||||
inlines = [InventoryHostInline, InventoryGroupInline]
|
||||
|
||||
class TagAdmin(admin.ModelAdmin):
|
||||
class TagAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name',)
|
||||
|
||||
@ -111,18 +121,18 @@ class VariableDataInline(admin.StackedInline):
|
||||
# FIXME: Doesn't yet work as inline due to the way the OneToOne field is
|
||||
# defined.
|
||||
|
||||
class LaunchJobHostSummaryInline(admin.TabularInline):
|
||||
class JobHostSummaryInline(admin.TabularInline):
|
||||
|
||||
model = LaunchJobHostSummary
|
||||
model = JobHostSummary
|
||||
extra = 0
|
||||
can_delete = False
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
class LaunchJobStatusEventInline(admin.StackedInline):
|
||||
class JobEventInline(admin.StackedInline):
|
||||
|
||||
model = LaunchJobStatusEvent
|
||||
model = JobEvent
|
||||
extra = 0
|
||||
can_delete = False
|
||||
|
||||
@ -130,161 +140,197 @@ class LaunchJobStatusEventInline(admin.StackedInline):
|
||||
return False
|
||||
|
||||
def get_event_data_display(self, obj):
|
||||
return format_html('<pre class="json-display">{0}</pre>', json.dumps(obj.event_data, indent=4))
|
||||
return format_html('<pre class="json-display">{0}</pre>',
|
||||
json.dumps(obj.event_data, indent=4))
|
||||
get_event_data_display.short_description = _('Event data')
|
||||
get_event_data_display.allow_tags = True
|
||||
|
||||
class LaunchJobHostSummaryInlineForHost(LaunchJobHostSummaryInline):
|
||||
class JobHostSummaryInlineForHost(JobHostSummaryInline):
|
||||
|
||||
fields = ('launch_job_status', 'changed', 'dark', 'failures', 'ok', 'processed', 'skipped')
|
||||
readonly_fields = ('launch_job_status', 'changed', 'dark', 'failures', 'ok', 'processed', 'skipped')
|
||||
fields = ('job', 'changed', 'dark', 'failures', 'ok', 'processed',
|
||||
'skipped')
|
||||
readonly_fields = ('job', 'changed', 'dark', 'failures', 'ok', 'processed',
|
||||
'skipped')
|
||||
|
||||
class LaunchJobStatusEventInlineForHost(LaunchJobStatusEventInline):
|
||||
class JobEventInlineForHost(JobEventInline):
|
||||
|
||||
fields = ('created', 'event', 'get_event_data_display', 'launch_job_status')
|
||||
readonly_fields = ('created', 'event', 'get_event_data_display', 'launch_job_status')
|
||||
fields = ('job', 'created', 'event', 'get_event_data_display')
|
||||
readonly_fields = ('job', 'created', 'event', 'get_event_data_display')
|
||||
|
||||
class HostAdmin(admin.ModelAdmin):
|
||||
class HostAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'inventory', 'description', 'active')
|
||||
list_filter = ('inventory', 'active')
|
||||
fields = ('name', 'inventory', 'description', 'active', 'tags',
|
||||
'created_by', 'audit_trail')
|
||||
readonly_fields = ('creation_date', 'created_by', 'audit_trail')
|
||||
filter_horizontal = ('tags',)
|
||||
# FIXME: Edit reverse of many to many for groups.
|
||||
#inlines = [VariableDataInline]
|
||||
inlines = [LaunchJobHostSummaryInlineForHost, LaunchJobStatusEventInlineForHost]
|
||||
inlines = [JobHostSummaryInlineForHost, JobEventInlineForHost]
|
||||
|
||||
class GroupAdmin(admin.ModelAdmin):
|
||||
class GroupAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active')
|
||||
filter_horizontal = ('parents', 'hosts', 'tags')
|
||||
#inlines = [VariableDataInline]
|
||||
|
||||
class VariableDataAdmin(admin.ModelAdmin):
|
||||
class VariableDataAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active')
|
||||
filter_horizontal = ('tags',)
|
||||
|
||||
class CredentialAdmin(admin.ModelAdmin):
|
||||
class CredentialAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active')
|
||||
filter_horizontal = ('tags',)
|
||||
|
||||
class TeamAdmin(admin.ModelAdmin):
|
||||
class TeamAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active')
|
||||
filter_horizontal = ('projects', 'users', 'tags')
|
||||
|
||||
class ProjectAdmin(admin.ModelAdmin):
|
||||
class ProjectAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active')
|
||||
filter_horizontal = ('tags',)
|
||||
|
||||
class PermissionAdmin(admin.ModelAdmin):
|
||||
class PermissionAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active')
|
||||
filter_horizontal = ('tags',)
|
||||
|
||||
class LaunchJobAdmin(admin.ModelAdmin):
|
||||
class JobTemplateAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'description', 'active', 'get_start_link_display',
|
||||
'get_statuses_link_display')
|
||||
list_display = ('name', 'description', 'active', 'get_create_link_display',
|
||||
'get_jobs_link_display')
|
||||
fieldsets = (
|
||||
(None, {'fields': ('name', 'active', 'created_by', 'description',
|
||||
'get_start_link_display', 'get_statuses_link_display')}),
|
||||
(None, {'fields': ('name', 'active', 'description',
|
||||
'get_create_link_display', 'get_jobs_link_display')}),
|
||||
(_('Job Parameters'), {'fields': ('inventory', 'project', 'credential',
|
||||
'user', 'job_type')}),
|
||||
(_('Tags'), {'fields': ('tags',)}),
|
||||
(_('Audit Trail'), {'fields': ('creation_date', 'audit_trail',)}),
|
||||
#(_('Tags'), {'fields': ('tags',)}),
|
||||
(_('Audit Trail'), {'fields': ('creation_date', 'created_by',
|
||||
'audit_trail',)}),
|
||||
)
|
||||
readonly_fields = ('creation_date', 'audit_trail', 'get_start_link_display',
|
||||
'get_statuses_link_display')
|
||||
filter_horizontal = ('tags',)
|
||||
readonly_fields = ('creation_date', 'created_by', 'audit_trail',
|
||||
'get_create_link_display', 'get_jobs_link_display')
|
||||
#filter_horizontal = ('tags',)
|
||||
|
||||
def get_start_link_display(self, obj):
|
||||
info = self.model._meta.app_label, self.model._meta.module_name
|
||||
start_url = reverse('admin:%s_%s_start' % info, args=(obj.pk,),
|
||||
current_app=self.admin_site.name)
|
||||
return '<a href="%s">Run Job</a>' % start_url
|
||||
get_start_link_display.short_description = _('Run')
|
||||
get_start_link_display.allow_tags = True
|
||||
|
||||
def get_statuses_link_display(self, obj):
|
||||
info = LaunchJobStatus._meta.app_label, LaunchJobStatus._meta.module_name
|
||||
statuses_url = reverse('admin:%s_%s_changelist' % info,
|
||||
current_app=self.admin_site.name)
|
||||
statuses_url += '?launch_job__id__exact=%d' % obj.pk
|
||||
return '<a href="%s">View Logs</a>' % statuses_url
|
||||
get_statuses_link_display.short_description = _('Logs')
|
||||
get_statuses_link_display.allow_tags = True
|
||||
|
||||
def get_urls(self):
|
||||
info = self.model._meta.app_label, self.model._meta.module_name
|
||||
urls = super(LaunchJobAdmin, self).get_urls()
|
||||
return patterns('',
|
||||
url(r'^(.+)/start/$',
|
||||
self.admin_site.admin_view(self.start_job_view),
|
||||
name='%s_%s_start' % info),
|
||||
) + urls
|
||||
|
||||
def start_job_view(self, request, object_id):
|
||||
obj = self.get_object(request, unquote(object_id))
|
||||
ljs = obj.start()
|
||||
info = ljs._meta.app_label, ljs._meta.module_name
|
||||
status_url = reverse('admin:%s_%s_change' % info, args=(ljs.pk,),
|
||||
def get_create_link_display(self, obj):
|
||||
info = Job._meta.app_label, Job._meta.module_name
|
||||
create_url = reverse('admin:%s_%s_add' % info,
|
||||
current_app=self.admin_site.name)
|
||||
messages.success(request, '%s has been started.' % ljs)
|
||||
return HttpResponseRedirect(status_url)
|
||||
create_opts = {
|
||||
'job_template': obj.pk,
|
||||
'job_type': obj.job_type,
|
||||
}
|
||||
if obj.inventory:
|
||||
create_opts['inventory'] = obj.inventory.pk
|
||||
if obj.project:
|
||||
create_opts['project'] = obj.project.pk
|
||||
if obj.credential:
|
||||
create_opts['credential'] = obj.credential.pk
|
||||
if obj.user:
|
||||
create_opts['user'] = obj.user.pk
|
||||
create_url += '?%s' % urllib.urlencode(create_opts)
|
||||
return format_html('<a href="{0}">{1}</a>', create_url, 'Create Job')
|
||||
get_create_link_display.short_description = _('Create Job')
|
||||
get_create_link_display.allow_tags = True
|
||||
|
||||
class LaunchJobHostSummaryInlineForLaunchJobStatus(LaunchJobHostSummaryInline):
|
||||
def get_jobs_link_display(self, obj):
|
||||
info = Job._meta.app_label, Job._meta.module_name
|
||||
jobs_url = reverse('admin:%s_%s_changelist' % info,
|
||||
current_app=self.admin_site.name)
|
||||
jobs_url += '?job_template__id__exact=%d' % obj.pk
|
||||
return format_html('<a href="{0}">{1}</a>', jobs_url, 'View Jobs')
|
||||
get_jobs_link_display.short_description = _('View Jobs')
|
||||
get_jobs_link_display.allow_tags = True
|
||||
|
||||
fields = ('host', 'changed', 'dark', 'failures', 'ok', 'processed', 'skipped')
|
||||
readonly_fields = ('host', 'changed', 'dark', 'failures', 'ok', 'processed', 'skipped')
|
||||
class JobHostSummaryInlineForJob(JobHostSummaryInline):
|
||||
|
||||
class LaunchJobStatusEventInlineForLaunchJobStatus(LaunchJobStatusEventInline):
|
||||
fields = ('host', 'changed', 'dark', 'failures', 'ok', 'processed',
|
||||
'skipped')
|
||||
readonly_fields = ('host', 'changed', 'dark', 'failures', 'ok',
|
||||
'processed', 'skipped')
|
||||
|
||||
class JobEventInlineForJob(JobEventInline):
|
||||
|
||||
fields = ('created', 'event', 'get_event_data_display', 'host')
|
||||
readonly_fields = ('created', 'event', 'get_event_data_display', 'host')
|
||||
|
||||
class LaunchJobStatusAdmin(admin.ModelAdmin):
|
||||
class JobAdmin(BaseModelAdmin):
|
||||
|
||||
list_display = ('name', 'launch_job', 'status')
|
||||
fields = ('name', 'get_launch_job_display', 'status',
|
||||
'get_result_stdout_display', 'get_result_stderr_display',
|
||||
'get_result_traceback_display', 'celery_task_id', 'tags',
|
||||
'created_by')
|
||||
readonly_fields = ('name', 'description', 'status', 'get_launch_job_display',
|
||||
list_display = ('name', 'job_template', 'status')
|
||||
fieldsets = (
|
||||
(None, {'fields': ('name', 'job_template', 'description')}),
|
||||
(_('Job Parameters'), {'fields': ('inventory', 'project', 'credential',
|
||||
'user', 'job_type')}),
|
||||
#(_('Tags'), {'fields': ('tags',)}),
|
||||
(_('Audit Trail'), {'fields': ('creation_date', 'created_by',
|
||||
'audit_trail',)}),
|
||||
(_('Job Status'), {'fields': ('status', 'get_result_stdout_display',
|
||||
'get_result_stderr_display',
|
||||
'get_result_traceback_display',
|
||||
'celery_task_id')}),
|
||||
)
|
||||
readonly_fields = ('status', 'get_job_template_display',
|
||||
'get_result_stdout_display', 'get_result_stderr_display',
|
||||
'get_result_traceback_display', 'celery_task_id',
|
||||
'created_by', 'tags', 'audit_trail', 'active')
|
||||
'creation_date', 'created_by', 'audit_trail',)
|
||||
filter_horizontal = ('tags',)
|
||||
inlines = [LaunchJobHostSummaryInlineForLaunchJobStatus,
|
||||
LaunchJobStatusEventInlineForLaunchJobStatus]
|
||||
inlines = [JobHostSummaryInlineForJob, JobEventInlineForJob]
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
ro_fields = list(super(JobAdmin, self).get_readonly_fields(request, obj))
|
||||
if obj and obj.pk:
|
||||
ro_fields.extend(['name', 'description', 'job_template',
|
||||
'inventory', 'project', 'credential', 'user',
|
||||
'job_type'])
|
||||
return ro_fields
|
||||
|
||||
def get_launch_job_display(self, obj):
|
||||
info = obj.launch_job._meta.app_label, obj.launch_job._meta.module_name
|
||||
lj_url = reverse('admin:%s_%s_change' % info, args=(obj.launch_job.pk,),
|
||||
current_app=self.admin_site.name)
|
||||
return format_html('<a href="{0}">{1}</a>', lj_url, obj.launch_job)
|
||||
get_launch_job_display.short_description = _('Launch job')
|
||||
get_launch_job_display.allow_tags = True
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fsets = list(super(JobAdmin, self).get_fieldsets(request, obj))
|
||||
if not obj or not obj.pk:
|
||||
fsets = [fs for fs in fsets if
|
||||
'creation_date' not in fs[1]['fields'] and
|
||||
'status' not in fs[1]['fields']]
|
||||
return fsets
|
||||
|
||||
def get_inline_instances(self, request, obj=None):
|
||||
if obj and obj.pk:
|
||||
return super(JobAdmin, self).get_inline_instances(request, obj)
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_job_template_display(self, obj):
|
||||
if obj.job_template:
|
||||
info = JobTemplate._meta.app_label, JobTemplate._meta.module_name
|
||||
job_template_url = reverse('admin:%s_%s_change' % info,
|
||||
args=(obj.job_template.pk,),
|
||||
current_app=self.admin_site.name)
|
||||
return format_html('<a href="{0}">{1}</a>', job_template_url,
|
||||
obj.job_template)
|
||||
else:
|
||||
return _('(None)')
|
||||
get_job_template_display.short_description = _('Job template')
|
||||
get_job_template_display.allow_tags = True
|
||||
|
||||
def get_result_stdout_display(self, obj):
|
||||
return format_html('<pre class="result-display">{0}</pre>', obj.result_stdout or ' ')
|
||||
return format_html('<pre class="result-display">{0}</pre>',
|
||||
obj.result_stdout or ' ')
|
||||
get_result_stdout_display.short_description = _('Stdout')
|
||||
get_result_stdout_display.allow_tags = True
|
||||
|
||||
def get_result_stderr_display(self, obj):
|
||||
return format_html('<pre class="result-display">{0}</pre>', obj.result_stderr or ' ')
|
||||
return format_html('<pre class="result-display">{0}</pre>',
|
||||
obj.result_stderr or ' ')
|
||||
get_result_stderr_display.short_description = _('Stderr')
|
||||
get_result_stderr_display.allow_tags = True
|
||||
|
||||
def get_result_traceback_display(self, obj):
|
||||
return format_html('<pre class="result-display">{0}</pre>', obj.result_traceback or ' ')
|
||||
return format_html('<pre class="result-display">{0}</pre>',
|
||||
obj.result_traceback or ' ')
|
||||
get_result_traceback_display.short_description = _('Traceback')
|
||||
get_result_traceback_display.allow_tags = True
|
||||
|
||||
@ -300,5 +346,5 @@ admin.site.register(VariableData, VariableDataAdmin)
|
||||
admin.site.register(Team, TeamAdmin)
|
||||
admin.site.register(Project, ProjectAdmin)
|
||||
admin.site.register(Credential, CredentialAdmin)
|
||||
admin.site.register(LaunchJob, LaunchJobAdmin)
|
||||
admin.site.register(LaunchJobStatus, LaunchJobStatusAdmin)
|
||||
admin.site.register(JobTemplate, JobTemplateAdmin)
|
||||
admin.site.register(Job, JobAdmin)
|
||||
|
||||
@ -30,10 +30,10 @@ class Command(NoArgsCommand):
|
||||
help = 'Ansible Commander Callback Event Capture'
|
||||
|
||||
option_list = NoArgsCommand.option_list + (
|
||||
make_option('-i', '--launch-job-status', dest='launch_job_status_id',
|
||||
make_option('-j', '--job', dest='job_id',
|
||||
type='int', default=0,
|
||||
help='Launch job status ID (can also be specified using '
|
||||
'ACOM_LAUNCH_JOB_STATUS_ID environment variable)'),
|
||||
help='Job ID (can also be specified using ACOM_JOB_ID '
|
||||
'environment variable)'),
|
||||
make_option('-e', '--event', dest='event_type', default=None,
|
||||
help='Event type'),
|
||||
make_option('-f', '--file', dest='event_data_file', default=None,
|
||||
@ -44,29 +44,28 @@ class Command(NoArgsCommand):
|
||||
)
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
from lib.main.models import LaunchJobStatus, LaunchJobStatusEvent
|
||||
from lib.main.models import Job, JobEvent
|
||||
event_type = options.get('event_type', None)
|
||||
if not event_type:
|
||||
raise CommandError('No event specified')
|
||||
if event_type not in [x[0] for x in LaunchJobStatusEvent.EVENT_TYPES]:
|
||||
if event_type not in [x[0] for x in JobEvent.EVENT_TYPES]:
|
||||
raise CommandError('Unsupported event')
|
||||
event_data_file = options.get('event_data_file', None)
|
||||
event_data_json = options.get('event_data_json', None)
|
||||
if event_data_file is None and event_data_json is None:
|
||||
raise CommandError('Either --file or --data must be specified')
|
||||
try:
|
||||
launch_job_status_id = int(os.getenv('ACOM_LAUNCH_JOB_STATUS_ID',
|
||||
options.get('launch_job_status_id', 0)))
|
||||
job_id = int(os.getenv('ACOM_JOB_ID', options.get('job_id', 0)))
|
||||
except ValueError:
|
||||
raise CommandError('Launch job status ID must be an integer')
|
||||
if not launch_job_status_id:
|
||||
raise CommandError('No launch job status ID specified')
|
||||
raise CommandError('Job ID must be an integer')
|
||||
if not job_id:
|
||||
raise CommandError('No Job ID specified')
|
||||
try:
|
||||
launch_job_status = LaunchJobStatus.objects.get(id=launch_job_status_id)
|
||||
except LaunchJobStatus.DoesNotExist:
|
||||
raise CommandError('Launch job status with ID %d not found' % launch_job_status_id)
|
||||
if launch_job_status.status != 'running':
|
||||
raise CommandError('Unable to add event except when launch job is running')
|
||||
job = Job.objects.get(id=job_id)
|
||||
except Job.DoesNotExist:
|
||||
raise CommandError('Job with ID %d not found' % job_id)
|
||||
if job.status != 'running':
|
||||
raise CommandError('Unable to add event except when job is running')
|
||||
try:
|
||||
if event_data_json is None:
|
||||
try:
|
||||
@ -81,8 +80,7 @@ class Command(NoArgsCommand):
|
||||
event_data = json.loads(event_data_json)
|
||||
except ValueError:
|
||||
raise CommandError('Error parsing JSON data')
|
||||
launch_job_status.launch_job_status_events.create(event=event_type,
|
||||
event_data=event_data)
|
||||
job.job_events.create(event=event_type, event_data=event_data)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from __init__ import run_command_as_script
|
||||
|
||||
@ -27,9 +27,9 @@ class Command(NoArgsCommand):
|
||||
help = 'Ansible Commander Inventory script'
|
||||
|
||||
option_list = NoArgsCommand.option_list + (
|
||||
make_option('-i', '--inventory', dest='inventory', type='int', default=0,
|
||||
help='Inventory ID (can also be specified using '
|
||||
'ACOM_INVENTORY_ID environment variable)'),
|
||||
make_option('-i', '--inventory', dest='inventory_id', type='int',
|
||||
default=0, help='Inventory ID (can also be specified using'
|
||||
' ACOM_INVENTORY_ID environment variable)'),
|
||||
make_option('--list', action='store_true', dest='list', default=False,
|
||||
help='Return JSON hash of host groups.'),
|
||||
make_option('--host', dest='host', default='',
|
||||
@ -75,7 +75,7 @@ class Command(NoArgsCommand):
|
||||
try:
|
||||
# Command line argument takes precedence over environment
|
||||
# variable.
|
||||
inventory_id = int(options.get('inventory', 0) or \
|
||||
inventory_id = int(options.get('inventory_id', 0) or \
|
||||
os.getenv('ACOM_INVENTORY_ID', 0))
|
||||
except ValueError:
|
||||
raise CommandError('Inventory ID must be an integer')
|
||||
|
||||
501
lib/main/migrations/0013_changes.py
Normal file
501
lib/main/migrations/0013_changes.py
Normal file
@ -0,0 +1,501 @@
|
||||
# -*- 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):
|
||||
# Removing unique constraint on 'LaunchJobHostSummary', fields ['launch_job_status', 'host']
|
||||
db.delete_unique(u'main_launchjobhostsummary', ['launch_job_status_id', 'host_id'])
|
||||
|
||||
# Deleting model 'LaunchJobHostSummary'
|
||||
db.delete_table(u'main_launchjobhostsummary')
|
||||
|
||||
# Deleting model 'LaunchJobStatusEvent'
|
||||
db.delete_table(u'main_launchjobstatusevent')
|
||||
|
||||
# Deleting model 'LaunchJob'
|
||||
db.delete_table(u'main_launchjob')
|
||||
|
||||
# Removing M2M table for field tags on 'LaunchJob'
|
||||
db.delete_table('main_launchjob_tags')
|
||||
|
||||
# Removing M2M table for field audit_trail on 'LaunchJob'
|
||||
db.delete_table('main_launchjob_audit_trail')
|
||||
|
||||
# Deleting model 'LaunchJobStatus'
|
||||
db.delete_table(u'main_launchjobstatus')
|
||||
|
||||
# Removing M2M table for field tags on 'LaunchJobStatus'
|
||||
db.delete_table('main_launchjobstatus_tags')
|
||||
|
||||
# Removing M2M table for field audit_trail on 'LaunchJobStatus'
|
||||
db.delete_table('main_launchjobstatus_audit_trail')
|
||||
|
||||
# Adding model 'Job'
|
||||
db.create_table(u'main_job', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name="{'class': 'job', 'app_label': 'main'}(class)s_created", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||
('creation_date', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)),
|
||||
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=512)),
|
||||
('job_template', self.gf('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', self.gf('django.db.models.fields.CharField')(max_length=64)),
|
||||
('inventory', self.gf('django.db.models.fields.related.ForeignKey')(related_name='jobs', null=True, on_delete=models.SET_NULL, to=orm['main.Inventory'])),
|
||||
('credential', self.gf('django.db.models.fields.related.ForeignKey')(related_name='jobs', null=True, on_delete=models.SET_NULL, to=orm['main.Credential'])),
|
||||
('project', self.gf('django.db.models.fields.related.ForeignKey')(related_name='jobs', null=True, on_delete=models.SET_NULL, to=orm['main.Project'])),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='jobs', null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||
('status', self.gf('django.db.models.fields.CharField')(default='pending', max_length=20)),
|
||||
('result_stdout', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||
('result_stderr', 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', ['Job'])
|
||||
|
||||
# Adding M2M table for field tags on 'Job'
|
||||
db.create_table(u'main_job_tags', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('job', models.ForeignKey(orm['main.job'], null=False)),
|
||||
('tag', models.ForeignKey(orm['main.tag'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_job_tags', ['job_id', 'tag_id'])
|
||||
|
||||
# Adding M2M table for field audit_trail on 'Job'
|
||||
db.create_table(u'main_job_audit_trail', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('job', models.ForeignKey(orm['main.job'], null=False)),
|
||||
('audittrail', models.ForeignKey(orm['main.audittrail'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_job_audit_trail', ['job_id', 'audittrail_id'])
|
||||
|
||||
# Adding model 'JobHostSummary'
|
||||
db.create_table(u'main_jobhostsummary', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('job', self.gf('django.db.models.fields.related.ForeignKey')(related_name='job_host_summaries', to=orm['main.Job'])),
|
||||
('host', self.gf('django.db.models.fields.related.ForeignKey')(related_name='job_host_summaries', to=orm['main.Host'])),
|
||||
('changed', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('dark', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('failures', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('ok', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('processed', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('skipped', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
))
|
||||
db.send_create_signal(u'main', ['JobHostSummary'])
|
||||
|
||||
# Adding unique constraint on 'JobHostSummary', fields ['job', 'host']
|
||||
db.create_unique(u'main_jobhostsummary', ['job_id', 'host_id'])
|
||||
|
||||
# Adding model 'JobTemplate'
|
||||
db.create_table(u'main_jobtemplate', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name="{'class': 'jobtemplate', 'app_label': 'main'}(class)s_created", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||
('creation_date', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)),
|
||||
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=512)),
|
||||
('job_type', self.gf('django.db.models.fields.CharField')(max_length=64)),
|
||||
('inventory', self.gf('django.db.models.fields.related.ForeignKey')(related_name='job_templates', on_delete=models.SET_NULL, default=None, to=orm['main.Inventory'], blank=True, null=True)),
|
||||
('credential', self.gf('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)),
|
||||
('project', self.gf('django.db.models.fields.related.ForeignKey')(related_name='job_templates', on_delete=models.SET_NULL, default=None, to=orm['main.Project'], blank=True, null=True)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='job_templates', on_delete=models.SET_NULL, default=None, to=orm['auth.User'], blank=True, null=True)),
|
||||
))
|
||||
db.send_create_signal('main', ['JobTemplate'])
|
||||
|
||||
# Adding M2M table for field tags on 'JobTemplate'
|
||||
db.create_table(u'main_jobtemplate_tags', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('jobtemplate', models.ForeignKey(orm['main.jobtemplate'], null=False)),
|
||||
('tag', models.ForeignKey(orm['main.tag'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_jobtemplate_tags', ['jobtemplate_id', 'tag_id'])
|
||||
|
||||
# Adding M2M table for field audit_trail on 'JobTemplate'
|
||||
db.create_table(u'main_jobtemplate_audit_trail', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('jobtemplate', models.ForeignKey(orm['main.jobtemplate'], null=False)),
|
||||
('audittrail', models.ForeignKey(orm['main.audittrail'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_jobtemplate_audit_trail', ['jobtemplate_id', 'audittrail_id'])
|
||||
|
||||
# Adding model 'JobEvent'
|
||||
db.create_table(u'main_jobevent', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('job', self.gf('django.db.models.fields.related.ForeignKey')(related_name='job_events', to=orm['main.Job'])),
|
||||
('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('event', self.gf('django.db.models.fields.CharField')(max_length=100)),
|
||||
('event_data', self.gf('jsonfield.fields.JSONField')(default='', blank=True)),
|
||||
('host', self.gf('django.db.models.fields.related.ForeignKey')(related_name='job_events', on_delete=models.SET_NULL, default=None, to=orm['main.Host'], blank=True, null=True)),
|
||||
))
|
||||
db.send_create_signal('main', ['JobEvent'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing unique constraint on 'JobHostSummary', fields ['job', 'host']
|
||||
db.delete_unique(u'main_jobhostsummary', ['job_id', 'host_id'])
|
||||
|
||||
# Adding model 'LaunchJobHostSummary'
|
||||
db.create_table(u'main_launchjobhostsummary', (
|
||||
('dark', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('skipped', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('host', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_job_host_summaries', to=orm['main.Host'])),
|
||||
('ok', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('processed', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('failures', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
('changed', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('launch_job_status', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_job_host_summaries', to=orm['main.LaunchJobStatus'])),
|
||||
))
|
||||
db.send_create_signal(u'main', ['LaunchJobHostSummary'])
|
||||
|
||||
# Adding unique constraint on 'LaunchJobHostSummary', fields ['launch_job_status', 'host']
|
||||
db.create_unique(u'main_launchjobhostsummary', ['launch_job_status_id', 'host_id'])
|
||||
|
||||
# Adding model 'LaunchJobStatusEvent'
|
||||
db.create_table(u'main_launchjobstatusevent', (
|
||||
('event', self.gf('django.db.models.fields.CharField')(max_length=100)),
|
||||
('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('event_data', self.gf('jsonfield.fields.JSONField')(default='', blank=True)),
|
||||
('host', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_job_status_events', on_delete=models.SET_NULL, default=None, to=orm['main.Host'], blank=True, null=True)),
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('launch_job_status', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_job_status_events', to=orm['main.LaunchJobStatus'])),
|
||||
))
|
||||
db.send_create_signal('main', ['LaunchJobStatusEvent'])
|
||||
|
||||
# Adding model 'LaunchJob'
|
||||
db.create_table(u'main_launchjob', (
|
||||
('credential', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_jobs', on_delete=models.SET_NULL, default=None, to=orm['main.Credential'], blank=True, null=True)),
|
||||
('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||
('job_type', self.gf('django.db.models.fields.CharField')(max_length=64)),
|
||||
('creation_date', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_jobs', on_delete=models.SET_NULL, default=None, to=orm['auth.User'], blank=True, null=True)),
|
||||
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=512, unique=True)),
|
||||
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name="{'class': 'launchjob', 'app_label': 'main'}(class)s_created", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||
('project', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_jobs', on_delete=models.SET_NULL, default=None, to=orm['main.Project'], blank=True, null=True)),
|
||||
('inventory', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_jobs', on_delete=models.SET_NULL, default=None, to=orm['main.Inventory'], blank=True, null=True)),
|
||||
))
|
||||
db.send_create_signal('main', ['LaunchJob'])
|
||||
|
||||
# Adding M2M table for field tags on 'LaunchJob'
|
||||
db.create_table(u'main_launchjob_tags', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('launchjob', models.ForeignKey(orm['main.launchjob'], null=False)),
|
||||
('tag', models.ForeignKey(orm['main.tag'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_launchjob_tags', ['launchjob_id', 'tag_id'])
|
||||
|
||||
# Adding M2M table for field audit_trail on 'LaunchJob'
|
||||
db.create_table(u'main_launchjob_audit_trail', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('launchjob', models.ForeignKey(orm['main.launchjob'], null=False)),
|
||||
('audittrail', models.ForeignKey(orm['main.audittrail'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_launchjob_audit_trail', ['launchjob_id', 'audittrail_id'])
|
||||
|
||||
# Adding model 'LaunchJobStatus'
|
||||
db.create_table(u'main_launchjobstatus', (
|
||||
('status', self.gf('django.db.models.fields.CharField')(default='pending', max_length=20)),
|
||||
('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||
('result_traceback', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||
('result_stdout', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
|
||||
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name="{'class': 'launchjobstatus', 'app_label': 'main'}(class)s_created", null=True, on_delete=models.SET_NULL, to=orm['auth.User'])),
|
||||
('result_stderr', 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)),
|
||||
('launch_job', self.gf('django.db.models.fields.related.ForeignKey')(related_name='launch_job_statuses', null=True, on_delete=models.SET_NULL, to=orm['main.LaunchJob'])),
|
||||
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
('creation_date', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)),
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=512, unique=True)),
|
||||
))
|
||||
db.send_create_signal('main', ['LaunchJobStatus'])
|
||||
|
||||
# Adding M2M table for field tags on 'LaunchJobStatus'
|
||||
db.create_table(u'main_launchjobstatus_tags', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('launchjobstatus', models.ForeignKey(orm['main.launchjobstatus'], null=False)),
|
||||
('tag', models.ForeignKey(orm['main.tag'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_launchjobstatus_tags', ['launchjobstatus_id', 'tag_id'])
|
||||
|
||||
# Adding M2M table for field audit_trail on 'LaunchJobStatus'
|
||||
db.create_table(u'main_launchjobstatus_audit_trail', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('launchjobstatus', models.ForeignKey(orm['main.launchjobstatus'], null=False)),
|
||||
('audittrail', models.ForeignKey(orm['main.audittrail'], null=False))
|
||||
))
|
||||
db.create_unique(u'main_launchjobstatus_audit_trail', ['launchjobstatus_id', 'audittrail_id'])
|
||||
|
||||
# Deleting model 'Job'
|
||||
db.delete_table(u'main_job')
|
||||
|
||||
# Removing M2M table for field tags on 'Job'
|
||||
db.delete_table('main_job_tags')
|
||||
|
||||
# Removing M2M table for field audit_trail on 'Job'
|
||||
db.delete_table('main_job_audit_trail')
|
||||
|
||||
# Deleting model 'JobHostSummary'
|
||||
db.delete_table(u'main_jobhostsummary')
|
||||
|
||||
# Deleting model 'JobTemplate'
|
||||
db.delete_table(u'main_jobtemplate')
|
||||
|
||||
# Removing M2M table for field tags on 'JobTemplate'
|
||||
db.delete_table('main_jobtemplate_tags')
|
||||
|
||||
# Removing M2M table for field audit_trail on 'JobTemplate'
|
||||
db.delete_table('main_jobtemplate_audit_trail')
|
||||
|
||||
# Deleting model 'JobEvent'
|
||||
db.delete_table(u'main_jobevent')
|
||||
|
||||
|
||||
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.audittrail': {
|
||||
'Meta': {'object_name': 'AuditTrail'},
|
||||
'comment': ('django.db.models.fields.TextField', [], {}),
|
||||
'delta': ('django.db.models.fields.TextField', [], {}),
|
||||
'detail': ('django.db.models.fields.TextField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
|
||||
'resource_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Tag']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'})
|
||||
},
|
||||
'main.credential': {
|
||||
'Meta': {'object_name': 'Credential'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'credential_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'credential\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'default_username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'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'}),
|
||||
'sudo_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'credential_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'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'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'group_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'group\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'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']"}),
|
||||
'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']"}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'group_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'variable_data': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group'", 'unique': 'True', 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.VariableData']", 'blank': 'True', 'null': 'True'})
|
||||
},
|
||||
'main.host': {
|
||||
'Meta': {'unique_together': "(('name', 'inventory'),)", 'object_name': 'Host'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'host_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'host\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'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': "'hosts'", 'to': "orm['main.Inventory']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'host_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'variable_data': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'host'", 'unique': 'True', 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.VariableData']", 'blank': 'True', 'null': 'True'})
|
||||
},
|
||||
'main.inventory': {
|
||||
'Meta': {'unique_together': "(('name', 'organization'),)", 'object_name': 'Inventory'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'inventory_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'inventory\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'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']"}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'inventory_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"})
|
||||
},
|
||||
'main.job': {
|
||||
'Meta': {'object_name': 'Job'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'job_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'celery_task_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'job\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'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'}),
|
||||
'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_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'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['main.Project']"}),
|
||||
'result_stderr': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'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': "'pending'", 'max_length': '20'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'job_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.jobevent': {
|
||||
'Meta': {'object_name': 'JobEvent'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'event': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'event_data': ('jsonfield.fields.JSONField', [], {'default': "''", 'blank': 'True'}),
|
||||
'host': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_events'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Host']", 'blank': 'True', 'null': 'True'}),
|
||||
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']"})
|
||||
},
|
||||
u'main.jobhostsummary': {
|
||||
'Meta': {'ordering': "('-pk',)", 'unique_together': "[('job', 'host')]", 'object_name': 'JobHostSummary'},
|
||||
'changed': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'dark': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'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']"}),
|
||||
'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'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'jobtemplate_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'jobtemplate\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'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'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Inventory']", 'blank': 'True', 'null': 'True'}),
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': u"orm['main.Project']", 'blank': 'True', 'null': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'jobtemplate_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_templates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': u"orm['auth.User']", 'blank': 'True', 'null': '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']"}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organization_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'organization\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'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']"}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organization_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'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'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'permission_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'permission\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'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']"}),
|
||||
'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']"}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'permission_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'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.project': {
|
||||
'Meta': {'object_name': 'Project'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'project_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'project\', \'app_label\': u\'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'default_playbook': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'local_repository': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'scm_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'project_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"})
|
||||
},
|
||||
'main.tag': {
|
||||
'Meta': {'object_name': 'Tag'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'})
|
||||
},
|
||||
'main.team': {
|
||||
'Meta': {'object_name': 'Team'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'team_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'team\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'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']"}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'team_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.variabledata': {
|
||||
'Meta': {'object_name': 'VariableData'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'audit_trail': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'variabledata_by_audit_trail'", 'blank': 'True', 'to': "orm['main.AuditTrail']"}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': '"{\'class\': \'variabledata\', \'app_label\': \'main\'}(class)s_created"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'creation_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'data': ('django.db.models.fields.TextField', [], {}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'variabledata_by_tag'", 'blank': 'True', 'to': "orm['main.Tag']"})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
@ -150,7 +150,7 @@ class PrimordialModel(models.Model):
|
||||
abstract = True
|
||||
|
||||
description = models.TextField(blank=True, default='')
|
||||
created_by = models.ForeignKey('auth.User', on_delete=SET_NULL, null=True, related_name='%s(class)s_created') # not blank=False on purpose for admin!
|
||||
created_by = models.ForeignKey('auth.User', on_delete=SET_NULL, null=True, related_name='%s(class)s_created', editable=False) # not blank=False on purpose for admin!
|
||||
creation_date = models.DateField(auto_now_add=True)
|
||||
tags = models.ManyToManyField('Tag', related_name='%(class)s_by_tag', blank=True)
|
||||
audit_trail = models.ManyToManyField('AuditTrail', related_name='%(class)s_by_audit_trail', blank=True)
|
||||
@ -707,35 +707,51 @@ class Permission(CommonModelNameNotUnique):
|
||||
|
||||
# TODO: other job types (later)
|
||||
|
||||
class LaunchJob(CommonModel):
|
||||
class JobTemplate(CommonModel):
|
||||
'''
|
||||
A launch job is a definition for applying a project (with playbook) to an
|
||||
inventory source with a given credential.
|
||||
A job template is a reusable job definition for applying a project (with
|
||||
playbook) to an inventory source with a given credential.
|
||||
'''
|
||||
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
|
||||
inventory = models.ForeignKey('Inventory', on_delete=SET_NULL, null=True, default=None, blank=True, related_name='launch_jobs')
|
||||
credential = models.ForeignKey('Credential', on_delete=SET_NULL, null=True, default=None, blank=True, related_name='launch_jobs')
|
||||
project = models.ForeignKey('Project', on_delete=SET_NULL, null=True, default=None, blank=True, related_name='launch_jobs')
|
||||
user = models.ForeignKey('auth.User', on_delete=SET_NULL, null=True, default=None, blank=True, related_name='launch_jobs')
|
||||
|
||||
# JOB_TYPE_CHOICES are a subset of PERMISSION_TYPE_CHOICES
|
||||
job_type = models.CharField(max_length=64, choices=JOB_TYPE_CHOICES)
|
||||
|
||||
def start(self):
|
||||
'''
|
||||
Create a new launch job status and start the task via celery.
|
||||
'''
|
||||
from lib.main.tasks import run_launch_job
|
||||
launch_job_status = self.launch_job_statuses.create(name='Launch Job Status %s' % now().isoformat())
|
||||
task_result = run_launch_job.delay(launch_job_status.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.
|
||||
launch_job_status.celery_task_id = task_result.task_id
|
||||
launch_job_status.save(update_fields=['celery_task_id'])
|
||||
return launch_job_status
|
||||
job_type = models.CharField(
|
||||
max_length=64,
|
||||
choices=JOB_TYPE_CHOICES,
|
||||
)
|
||||
inventory = models.ForeignKey(
|
||||
'Inventory',
|
||||
related_name='job_templates',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
credential = models.ForeignKey(
|
||||
'Credential',
|
||||
related_name='job_templates',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
project = models.ForeignKey(
|
||||
'Project',
|
||||
related_name='job_templates',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
'auth.User',
|
||||
related_name='job_templates',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
|
||||
# project has one default playbook but really should have a list of playbooks and flags ...
|
||||
|
||||
@ -756,9 +772,11 @@ class LaunchJob(CommonModel):
|
||||
# --list
|
||||
# -- host <hostname>
|
||||
|
||||
class LaunchJobStatus(CommonModel):
|
||||
class Job(CommonModel):
|
||||
'''
|
||||
Status for a single run of a launch job.
|
||||
A job applies a project (with playbook) to an inventory source with a given
|
||||
credential. It represents a single invocation of ansible-playbook with the
|
||||
given parameters.
|
||||
'''
|
||||
|
||||
STATUS_CHOICES = [
|
||||
@ -771,15 +789,77 @@ class LaunchJobStatus(CommonModel):
|
||||
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
verbose_name_plural = _('launch job statuses')
|
||||
|
||||
launch_job = models.ForeignKey('LaunchJob', null=True, on_delete=SET_NULL, related_name='launch_job_statuses')
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
|
||||
result_stdout = models.TextField(blank=True, default='')
|
||||
result_stderr = models.TextField(blank=True, default='')
|
||||
result_traceback = models.TextField(blank=True, default='')
|
||||
celery_task_id = models.CharField(max_length=100, blank=True, default='', editable=False)
|
||||
hosts = models.ManyToManyField('Host', related_name='launch_job_statuses', blank=True, through='LaunchJobHostSummary')
|
||||
job_template = models.ForeignKey(
|
||||
'JobTemplate',
|
||||
related_name='jobs',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
job_type = models.CharField(
|
||||
max_length=64,
|
||||
choices=JOB_TYPE_CHOICES,
|
||||
)
|
||||
inventory = models.ForeignKey(
|
||||
'Inventory',
|
||||
related_name='jobs',
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
credential = models.ForeignKey(
|
||||
'Credential',
|
||||
related_name='jobs',
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
project = models.ForeignKey(
|
||||
'Project',
|
||||
related_name='jobs',
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
'auth.User',
|
||||
related_name='jobs',
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
default='pending',
|
||||
editable=False,
|
||||
)
|
||||
result_stdout = models.TextField(
|
||||
blank=True,
|
||||
default='',
|
||||
editable=False,
|
||||
)
|
||||
result_stderr = 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,
|
||||
)
|
||||
hosts = models.ManyToManyField(
|
||||
'Host',
|
||||
related_name='jobs',
|
||||
blank=True,
|
||||
editable=False,
|
||||
through='JobHostSummary',
|
||||
)
|
||||
|
||||
@property
|
||||
def celery_task(self):
|
||||
@ -789,24 +869,46 @@ class LaunchJobStatus(CommonModel):
|
||||
except TaskMeta.DoesNotExist:
|
||||
pass
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super(LaunchJobStatus, self).save(*args, **kwargs)
|
||||
# Create a new host summary for each host in the inventory.
|
||||
for host in self.launch_job.inventory.hosts.all():
|
||||
# Due to the way the inventory script is called, hosts without a group won't be affected.
|
||||
if host.groups.count():
|
||||
self.launch_job_host_summaries.get_or_create(host=host)
|
||||
def _run(self):
|
||||
from lib.main.tasks import run_job
|
||||
task_result = run_job.delay(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.
|
||||
self.celery_task_id = task_result.task_id
|
||||
self.save(update_fields=['celery_task_id'])
|
||||
|
||||
class LaunchJobHostSummary(models.Model):
|
||||
def save(self, *args, **kwargs):
|
||||
created = not bool(self.pk)
|
||||
super(Job, self).save(*args, **kwargs)
|
||||
# Create a new host summary for each host in the inventory.
|
||||
for host in self.inventory.hosts.all():
|
||||
# Due to the way the inventory script is called, hosts without a
|
||||
# group won't be included.
|
||||
if host.groups.count():
|
||||
self.job_host_summaries.get_or_create(host=host)
|
||||
# Start job running (but only if just created).
|
||||
if created and self.status == 'pending':
|
||||
self._run()
|
||||
|
||||
class JobHostSummary(models.Model):
|
||||
'''
|
||||
Per-host statistics for each job.
|
||||
'''
|
||||
|
||||
class Meta:
|
||||
unique_together = [('launch_job_status', 'host')]
|
||||
verbose_name_plural = _('Launch Job Host Summaries')
|
||||
unique_together = [('job', 'host')]
|
||||
verbose_name_plural = _('Job Host Summaries')
|
||||
ordering = ('-pk',)
|
||||
|
||||
launch_job_status = models.ForeignKey('LaunchJobStatus', on_delete=models.CASCADE, related_name='launch_job_host_summaries')
|
||||
host = models.ForeignKey('Host', on_delete=models.CASCADE, related_name='launch_job_host_summaries')
|
||||
# FIXME: Can't use SET_NULL for host relationship because of unique constraint.
|
||||
job = models.ForeignKey(
|
||||
'Job',
|
||||
related_name='job_host_summaries',
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
host = models.ForeignKey('Host',
|
||||
related_name='job_host_summaries',
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
|
||||
changed = models.PositiveIntegerField(default=0)
|
||||
dark = models.PositiveIntegerField(default=0)
|
||||
@ -820,7 +922,7 @@ class LaunchJobHostSummary(models.Model):
|
||||
(self.host.name, self.changed, self.dark, self.failures, self.ok,
|
||||
self.processed, self.skipped)
|
||||
|
||||
class LaunchJobStatusEvent(models.Model):
|
||||
class JobEvent(models.Model):
|
||||
'''
|
||||
An event/message logged from the callback when running a job.
|
||||
'''
|
||||
@ -849,11 +951,30 @@ class LaunchJobStatusEvent(models.Model):
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
|
||||
launch_job_status = models.ForeignKey('LaunchJobStatus', related_name='launch_job_status_events', on_delete=CASCADE)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
event = models.CharField(max_length=100, choices=EVENT_TYPES)
|
||||
event_data = JSONField(blank=True, default='')
|
||||
host = models.ForeignKey('Host', blank=True, null=True, default=None, on_delete=SET_NULL, related_name='launch_job_status_events')
|
||||
job = models.ForeignKey(
|
||||
'Job',
|
||||
related_name='job_events',
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
created = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
)
|
||||
event = models.CharField(
|
||||
max_length=100,
|
||||
choices=EVENT_TYPES,
|
||||
)
|
||||
event_data = JSONField(
|
||||
blank=True,
|
||||
default='',
|
||||
)
|
||||
host = models.ForeignKey(
|
||||
'Host',
|
||||
related_name='job_events',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s @ %s' % (self.get_event_display(), self.created.isoformat())
|
||||
@ -861,31 +982,36 @@ class LaunchJobStatusEvent(models.Model):
|
||||
def save(self, *args, **kwargs):
|
||||
try:
|
||||
if not self.host and self.event_data.get('host', ''):
|
||||
# Make sure we're looking at only the hosts from this launch job's associated inventory.
|
||||
self.host = self.launch_job_status.launch_job.inventory.hosts.get(name=self.event_data['host'])
|
||||
self.host = self.job.inventory.hosts.get(name=self.event_data['host'])
|
||||
except (Host.DoesNotExist, AttributeError):
|
||||
pass
|
||||
super(LaunchJobStatusEvent, self).save(*args, **kwargs)
|
||||
super(JobEvent, self).save(*args, **kwargs)
|
||||
self.update_host_summary_from_stats()
|
||||
|
||||
def update_host_summary_from_stats(self):
|
||||
if self.event != 'playbook_on_stats':
|
||||
return
|
||||
hostnames = set()
|
||||
for v in self.event_data.values():
|
||||
hostnames.update(v.keys())
|
||||
try:
|
||||
for v in self.event_data.values():
|
||||
hostnames.update(v.keys())
|
||||
except AttributeError: # In case event_data or v isn't a dict.
|
||||
pass
|
||||
for hostname in hostnames:
|
||||
try:
|
||||
host = self.launch_job_status.launch_job.inventory.hosts.get(name=hostname)
|
||||
host = self.job.inventory.hosts.get(name=hostname)
|
||||
except Host.DoesNotExist:
|
||||
continue
|
||||
host_summary = self.launch_job_status.launch_job_host_summaries.get_or_create(host=host)[0]
|
||||
host_summary = self.job.job_host_summaries.get_or_create(host=host)[0]
|
||||
host_summary_changed = False
|
||||
for stat in ('changed', 'dark', 'failures', 'ok', 'processed', 'skipped'):
|
||||
value = self.event_data.get(stat, {}).get(hostname, 0)
|
||||
if getattr(host_summary, stat) != value:
|
||||
setattr(host_summary, stat, value)
|
||||
host_summary_changed = True
|
||||
try:
|
||||
value = self.event_data.get(stat, {}).get(hostname, 0)
|
||||
if getattr(host_summary, stat) != value:
|
||||
setattr(host_summary, stat, value)
|
||||
host_summary_changed = True
|
||||
except AttributeError: # in case event_data[stat] isn't a dict.
|
||||
pass
|
||||
if host_summary_changed:
|
||||
host_summary.save()
|
||||
|
||||
|
||||
@ -21,12 +21,13 @@ from celery import task
|
||||
from django.conf import settings
|
||||
from lib.main.models import *
|
||||
|
||||
@task(name='run_launch_job')
|
||||
def run_launch_job(launch_job_status_pk):
|
||||
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status_pk)
|
||||
launch_job_status.status = 'running'
|
||||
launch_job_status.save()
|
||||
launch_job = launch_job_status.launch_job
|
||||
__all__ = ['run_job']
|
||||
|
||||
@task(name='run_job')
|
||||
def run_job(job_pk):
|
||||
job = Job.objects.get(pk=job_pk)
|
||||
job.status = 'running'
|
||||
job.save(update_fields=['status'])
|
||||
|
||||
try:
|
||||
status, stdout, stderr, tb = 'error', '', '', ''
|
||||
@ -40,17 +41,18 @@ def run_launch_job(launch_job_status_pk):
|
||||
'acom_callback_event.py'))
|
||||
env = dict(os.environ.items())
|
||||
# question: when running over CLI, generate a random ID or grab next, etc?
|
||||
env['ACOM_LAUNCH_JOB_STATUS_ID'] = str(launch_job_status.pk)
|
||||
env['ACOM_INVENTORY_ID'] = str(launch_job.inventory.pk)
|
||||
# answer: TBD
|
||||
env['ACOM_JOB_ID'] = str(job.pk)
|
||||
env['ACOM_INVENTORY_ID'] = str(job.inventory.pk)
|
||||
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_dir
|
||||
env['ACOM_CALLBACK_EVENT_SCRIPT'] = callback_script
|
||||
|
||||
if hasattr(settings, 'ANSIBLE_TRANSPORT'):
|
||||
env['ANSIBLE_TRANSPORT'] = getattr(settings, 'ANSIBLE_TRANSPORT')
|
||||
|
||||
playbook = launch_job.project.default_playbook
|
||||
playbook = job.project.default_playbook
|
||||
cmdline = ['ansible-playbook', '-i', inventory_script]
|
||||
if launch_job.job_type == 'check':
|
||||
if job.job_type == 'check':
|
||||
cmdline.append('--check')
|
||||
cmdline.append(playbook)
|
||||
|
||||
@ -63,9 +65,10 @@ def run_launch_job(launch_job_status_pk):
|
||||
tb = traceback.format_exc()
|
||||
|
||||
# Reload from database before updating/saving.
|
||||
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status_pk)
|
||||
launch_job_status.status = status
|
||||
launch_job_status.result_stdout = stdout
|
||||
launch_job_status.result_stderr = stderr
|
||||
launch_job_status.result_traceback = tb
|
||||
launch_job_status.save()
|
||||
job = Job.objects.get(pk=job_pk)
|
||||
job.status = status
|
||||
job.result_stdout = stdout
|
||||
job.result_stderr = stderr
|
||||
job.result_traceback = tb
|
||||
job.save(update_fields=['status', 'result_stdout', 'result_stderr',
|
||||
'result_traceback'])
|
||||
|
||||
@ -19,4 +19,4 @@ from lib.main.tests.users import UsersTest
|
||||
from lib.main.tests.inventory import InventoryTest
|
||||
from lib.main.tests.projects import ProjectsTest
|
||||
from lib.main.tests.commands import *
|
||||
from lib.main.tests.tasks import RunLaunchJobTest
|
||||
from lib.main.tests.tasks import RunJobTest
|
||||
|
||||
@ -138,7 +138,7 @@ class AcomInventoryTest(BaseCommandTest):
|
||||
def test_list_with_inventory_id_as_argument(self):
|
||||
inventory = self.inventories[0]
|
||||
result, stdout, stderr = self.run_command('acom_inventory', list=True,
|
||||
inventory=inventory.pk)
|
||||
inventory_id=inventory.pk)
|
||||
self.assertEqual(result, None)
|
||||
data = json.loads(stdout)
|
||||
self.assertEqual(set(data.keys()),
|
||||
@ -156,7 +156,7 @@ class AcomInventoryTest(BaseCommandTest):
|
||||
invalid_id = [x for x in xrange(9999) if x not in inventory_pks][0]
|
||||
os.environ['ACOM_INVENTORY_ID'] = str(invalid_id)
|
||||
result, stdout, stderr = self.run_command('acom_inventory', list=True,
|
||||
inventory=inventory.pk)
|
||||
inventory_id=inventory.pk)
|
||||
self.assertEqual(result, None)
|
||||
data = json.loads(stdout)
|
||||
|
||||
@ -274,40 +274,38 @@ class AcomCallbackEventTest(BaseCommandTest):
|
||||
self.group = self.inventory.groups.create(name='test-group',
|
||||
inventory=self.inventory)
|
||||
self.group.hosts.add(self.host)
|
||||
self.launch_job = LaunchJob.objects.create(name='test-launch-job',
|
||||
inventory=self.inventory,
|
||||
project=self.project)
|
||||
self.launch_job_status = self.launch_job.launch_job_statuses.create(
|
||||
name='launch-job-status-%s' % now().isoformat())
|
||||
self.job = Job.objects.create(name='job-%s' % now().isoformat(),
|
||||
inventory=self.inventory,
|
||||
project=self.project)
|
||||
self.valid_kwargs = {
|
||||
'launch_job_status_id': self.launch_job_status.id,
|
||||
'job_id': self.job.id,
|
||||
'event_type': 'playbook_on_start',
|
||||
'event_data_json': json.dumps({'test_event_data': [2,4,6]}),
|
||||
}
|
||||
|
||||
def test_with_launch_job_status_not_running(self):
|
||||
# Events can only be added when the launch job is running.
|
||||
self.assertEqual(self.launch_job_status.status, 'pending')
|
||||
def test_with_job_status_not_running(self):
|
||||
# Events can only be added when the job is running.
|
||||
self.assertEqual(self.job.status, 'pending')
|
||||
result, stdout, stderr = self.run_command('acom_callback_event',
|
||||
**self.valid_kwargs)
|
||||
self.assertTrue(isinstance(result, CommandError))
|
||||
self.assertTrue('unable to add event ' in str(result).lower())
|
||||
self.launch_job_status.status = 'successful'
|
||||
self.launch_job_status.save()
|
||||
self.job.status = 'successful'
|
||||
self.job.save()
|
||||
result, stdout, stderr = self.run_command('acom_callback_event',
|
||||
**self.valid_kwargs)
|
||||
self.assertTrue(isinstance(result, CommandError))
|
||||
self.assertTrue('unable to add event ' in str(result).lower())
|
||||
self.launch_job_status.status = 'failed'
|
||||
self.launch_job_status.save()
|
||||
self.job.status = 'failed'
|
||||
self.job.save()
|
||||
result, stdout, stderr = self.run_command('acom_callback_event',
|
||||
**self.valid_kwargs)
|
||||
self.assertTrue(isinstance(result, CommandError))
|
||||
self.assertTrue('unable to add event ' in str(result).lower())
|
||||
|
||||
def test_with_invalid_args(self):
|
||||
self.launch_job_status.status = 'running'
|
||||
self.launch_job_status.save()
|
||||
self.job.status = 'running'
|
||||
self.job.save()
|
||||
# Event type not given.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
kwargs.pop('event_type')
|
||||
@ -326,21 +324,21 @@ class AcomCallbackEventTest(BaseCommandTest):
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertTrue(isinstance(result, CommandError))
|
||||
self.assertTrue('either --file or --data' in str(result).lower())
|
||||
# Non-integer launch job status ID.
|
||||
# Non-integer job ID.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
kwargs['launch_job_status_id'] = 'foo'
|
||||
kwargs['job_id'] = 'foo'
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertTrue(isinstance(result, CommandError))
|
||||
self.assertTrue('id must be an integer' in str(result).lower())
|
||||
# No launch job status ID.
|
||||
# No job ID.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
kwargs.pop('launch_job_status_id')
|
||||
kwargs.pop('job_id')
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertTrue(isinstance(result, CommandError))
|
||||
self.assertTrue('no launch job status id' in str(result).lower())
|
||||
# Invalid launch job status ID.
|
||||
self.assertTrue('no job id' in str(result).lower())
|
||||
# Invalid job ID.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
kwargs['launch_job_status_id'] = 9999
|
||||
kwargs['job_id'] = 9999
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertTrue(isinstance(result, CommandError))
|
||||
self.assertTrue('not found' in str(result).lower())
|
||||
@ -362,21 +360,21 @@ class AcomCallbackEventTest(BaseCommandTest):
|
||||
self.assertTrue('reading from' in str(result).lower())
|
||||
|
||||
def test_with_valid_args(self):
|
||||
self.launch_job_status.status = 'running'
|
||||
self.launch_job_status.save()
|
||||
self.job.status = 'running'
|
||||
self.job.save()
|
||||
# Default valid args.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertEqual(result, None)
|
||||
self.assertEqual(self.launch_job_status.launch_job_status_events.count(), 1)
|
||||
# Pass launch job status in environment instead.
|
||||
self.assertEqual(self.job.job_events.count(), 1)
|
||||
# Pass job ID in environment instead.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
kwargs.pop('launch_job_status_id')
|
||||
os.environ['ACOM_LAUNCH_JOB_STATUS_ID'] = str(self.launch_job_status.id)
|
||||
kwargs.pop('job_id')
|
||||
os.environ['ACOM_JOB_ID'] = str(self.job.id)
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertEqual(result, None)
|
||||
self.assertEqual(self.launch_job_status.launch_job_status_events.count(), 2)
|
||||
os.environ.pop('ACOM_LAUNCH_JOB_STATUS_ID', None)
|
||||
self.assertEqual(self.job.job_events.count(), 2)
|
||||
os.environ.pop('ACOM_JOB_ID', None)
|
||||
# Test with JSON data in a file instead.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
kwargs.pop('event_data_json')
|
||||
@ -388,7 +386,7 @@ class AcomCallbackEventTest(BaseCommandTest):
|
||||
kwargs['event_data_file'] = tf
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertEqual(result, None)
|
||||
self.assertEqual(self.launch_job_status.launch_job_status_events.count(), 3)
|
||||
self.assertEqual(self.job.job_events.count(), 3)
|
||||
# Test with JSON data from stdin.
|
||||
kwargs = dict(self.valid_kwargs.items())
|
||||
kwargs.pop('event_data_json')
|
||||
@ -396,4 +394,4 @@ class AcomCallbackEventTest(BaseCommandTest):
|
||||
kwargs['stdin_fileobj'] = StringIO.StringIO(json.dumps({'blah': 'bleep'}))
|
||||
result, stdout, stderr = self.run_command('acom_callback_event', **kwargs)
|
||||
self.assertEqual(result, None)
|
||||
self.assertEqual(self.launch_job_status.launch_job_status_events.count(), 4)
|
||||
self.assertEqual(self.job.job_events.count(), 4)
|
||||
|
||||
@ -46,13 +46,13 @@ class BaseCeleryTest(BaseTransactionTest):
|
||||
'''
|
||||
|
||||
@override_settings(ANSIBLE_TRANSPORT='local')
|
||||
class RunLaunchJobTest(BaseCeleryTest):
|
||||
class RunJobTest(BaseCeleryTest):
|
||||
'''
|
||||
Test cases for run_launch_job celery task.
|
||||
Test cases for run_job celery task.
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
super(RunLaunchJobTest, self).setUp()
|
||||
super(RunJobTest, self).setUp()
|
||||
self.setup_users()
|
||||
self.organization = self.make_organizations(self.super_django_user, 1)[0]
|
||||
self.project = self.make_projects(self.normal_django_user, 1)[0]
|
||||
@ -65,14 +65,11 @@ class RunLaunchJobTest(BaseCeleryTest):
|
||||
self.group = self.inventory.groups.create(name='test-group',
|
||||
inventory=self.inventory)
|
||||
self.group.hosts.add(self.host)
|
||||
self.launch_job = LaunchJob.objects.create(name='test-launch-job',
|
||||
inventory=self.inventory,
|
||||
project=self.project)
|
||||
# Pass test database name in environment for use by the inventory script.
|
||||
os.environ['ACOM_TEST_DATABASE_NAME'] = settings.DATABASES['default']['NAME']
|
||||
|
||||
def tearDown(self):
|
||||
super(RunLaunchJobTest, self).tearDown()
|
||||
super(RunJobTest, self).tearDown()
|
||||
os.environ.pop('ACOM_TEST_DATABASE_NAME', None)
|
||||
os.remove(self.test_playbook)
|
||||
|
||||
@ -84,84 +81,84 @@ class RunLaunchJobTest(BaseCeleryTest):
|
||||
self.project.default_playbook = self.test_playbook
|
||||
self.project.save()
|
||||
|
||||
def test_run_launch_job(self):
|
||||
def test_run_job(self):
|
||||
self.create_test_playbook(TEST_PLAYBOOK)
|
||||
launch_job_status = self.launch_job.start()
|
||||
self.assertEqual(launch_job_status.status, 'pending')
|
||||
self.assertEqual(set(launch_job_status.hosts.values_list('pk', flat=True)),
|
||||
job = Job.objects.create(name='test-job', inventory=self.inventory,
|
||||
project=self.project)
|
||||
self.assertEqual(job.status, 'pending')
|
||||
self.assertEqual(set(job.hosts.values_list('pk', flat=True)),
|
||||
set([self.host.pk]))
|
||||
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status.pk)
|
||||
job = Job.objects.get(pk=job.pk)
|
||||
#print 'stdout:', launch_job_status.result_stdout
|
||||
#print 'stderr:', launch_job_status.result_stderr
|
||||
#print launch_job_status.status
|
||||
#print settings.DATABASES
|
||||
self.assertEqual(launch_job_status.status, 'successful')
|
||||
self.assertTrue(launch_job_status.result_stdout)
|
||||
launch_job_status_events = launch_job_status.launch_job_status_events.all()
|
||||
self.assertEqual(job.status, 'successful')
|
||||
self.assertTrue(job.result_stdout)
|
||||
job_events = job.job_events.all()
|
||||
#for ev in launch_job_status_events:
|
||||
# print ev.event, ev.event_data
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_task_start').count(), 2)
|
||||
self.assertEqual(launch_job_status_events.filter(event='runner_on_ok').count(), 2)
|
||||
for evt in launch_job_status_events.filter(event='runner_on_ok'):
|
||||
self.assertEqual(job_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_task_start').count(), 2)
|
||||
self.assertEqual(job_events.filter(event='runner_on_ok').count(), 2)
|
||||
for evt in job_events.filter(event='runner_on_ok'):
|
||||
self.assertEqual(evt.host, self.host)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_stats').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_stats').count(), 1)
|
||||
|
||||
def test_check_launch_job(self):
|
||||
def test_check_job(self):
|
||||
self.create_test_playbook(TEST_PLAYBOOK)
|
||||
self.launch_job.job_type = 'check'
|
||||
self.launch_job.save()
|
||||
launch_job_status = self.launch_job.start()
|
||||
self.assertEqual(launch_job_status.status, 'pending')
|
||||
self.assertEqual(set(launch_job_status.hosts.values_list('pk', flat=True)),
|
||||
job = Job.objects.create(name='test-job', inventory=self.inventory,
|
||||
project=self.project, job_type='check')
|
||||
self.assertEqual(job.status, 'pending')
|
||||
self.assertEqual(set(job.hosts.values_list('pk', flat=True)),
|
||||
set([self.host.pk]))
|
||||
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status.pk)
|
||||
self.assertEqual(launch_job_status.status, 'successful')
|
||||
self.assertTrue(launch_job_status.result_stdout)
|
||||
launch_job_status_events = launch_job_status.launch_job_status_events.all()
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_task_start').count(), 2)
|
||||
self.assertEqual(launch_job_status_events.filter(event='runner_on_skipped').count(), 2)
|
||||
for evt in launch_job_status_events.filter(event='runner_on_skipped'):
|
||||
job = Job.objects.get(pk=job.pk)
|
||||
self.assertEqual(job.status, 'successful')
|
||||
self.assertTrue(job.result_stdout)
|
||||
job_events = job.job_events.all()
|
||||
self.assertEqual(job_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_task_start').count(), 2)
|
||||
self.assertEqual(job_events.filter(event='runner_on_skipped').count(), 2)
|
||||
for evt in job_events.filter(event='runner_on_skipped'):
|
||||
self.assertEqual(evt.host, self.host)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_stats').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_stats').count(), 1)
|
||||
|
||||
def test_run_launch_job_that_fails(self):
|
||||
def test_run_job_that_fails(self):
|
||||
self.create_test_playbook(TEST_PLAYBOOK2)
|
||||
launch_job_status = self.launch_job.start()
|
||||
self.assertEqual(launch_job_status.status, 'pending')
|
||||
self.assertEqual(set(launch_job_status.hosts.values_list('pk', flat=True)),
|
||||
job = Job.objects.create(name='test-job', inventory=self.inventory,
|
||||
project=self.project)
|
||||
self.assertEqual(job.status, 'pending')
|
||||
self.assertEqual(set(job.hosts.values_list('pk', flat=True)),
|
||||
set([self.host.pk]))
|
||||
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status.pk)
|
||||
self.assertEqual(launch_job_status.status, 'failed')
|
||||
self.assertTrue(launch_job_status.result_stdout)
|
||||
launch_job_status_events = launch_job_status.launch_job_status_events.all()
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_task_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='runner_on_failed').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.get(event='runner_on_failed').host, self.host)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_stats').count(), 1)
|
||||
job = Job.objects.get(pk=job.pk)
|
||||
self.assertEqual(job.status, 'failed')
|
||||
self.assertTrue(job.result_stdout)
|
||||
job_events = job.job_events.all()
|
||||
self.assertEqual(job_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_task_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='runner_on_failed').count(), 1)
|
||||
self.assertEqual(job_events.get(event='runner_on_failed').host, self.host)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_stats').count(), 1)
|
||||
|
||||
def test_check_launch_job_where_task_would_fail(self):
|
||||
def test_check_job_where_task_would_fail(self):
|
||||
self.create_test_playbook(TEST_PLAYBOOK2)
|
||||
self.launch_job.job_type = 'check'
|
||||
self.launch_job.save()
|
||||
launch_job_status = self.launch_job.start()
|
||||
self.assertEqual(launch_job_status.status, 'pending')
|
||||
self.assertEqual(set(launch_job_status.hosts.values_list('pk', flat=True)),
|
||||
job = Job.objects.create(name='test-job', inventory=self.inventory,
|
||||
project=self.project, job_type='check')
|
||||
self.assertEqual(job.status, 'pending')
|
||||
self.assertEqual(set(job.hosts.values_list('pk', flat=True)),
|
||||
set([self.host.pk]))
|
||||
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status.pk)
|
||||
job = Job.objects.get(pk=job.pk)
|
||||
# Since we don't actually run the task, the --check should indicate
|
||||
# everything is successful.
|
||||
self.assertEqual(launch_job_status.status, 'successful')
|
||||
self.assertTrue(launch_job_status.result_stdout)
|
||||
launch_job_status_events = launch_job_status.launch_job_status_events.all()
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_task_start').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.filter(event='runner_on_skipped').count(), 1)
|
||||
self.assertEqual(launch_job_status_events.get(event='runner_on_skipped').host, self.host)
|
||||
self.assertEqual(launch_job_status_events.filter(event='playbook_on_stats').count(), 1)
|
||||
self.assertEqual(job.status, 'successful')
|
||||
self.assertTrue(job.result_stdout)
|
||||
job_events = job.job_events.all()
|
||||
self.assertEqual(job_events.filter(event='playbook_on_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_play_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_task_start').count(), 1)
|
||||
self.assertEqual(job_events.filter(event='runner_on_skipped').count(), 1)
|
||||
self.assertEqual(job_events.get(event='runner_on_skipped').host, self.host)
|
||||
self.assertEqual(job_events.filter(event='playbook_on_stats').count(), 1)
|
||||
|
||||
@ -1,34 +1,36 @@
|
||||
# Copyright (c) 2013 AnsibleWorks, Inc.
|
||||
# This file is a utility Ansible plugin that is not part of Ansible Commander or Ansible.
|
||||
# (it does not import any ansible-commander code, nor does it's license apply to Ansible
|
||||
# or Ansible Commander)
|
||||
# This file is a utility Ansible plugin that is not part of Ansible Commander
|
||||
# or Ansible. It does not import any ansible-commander code, nor does its
|
||||
# license apply to Ansible or Ansible Commander.
|
||||
#
|
||||
# Copyright (c) 2013, AnsibleWorks Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# Redistributions of source code must retain the above copyright notice, this list
|
||||
# of conditions and the following disclaimer.
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
# Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of the <ORGANIZATION> nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software without specific
|
||||
# prior written permission.
|
||||
# Neither the name of the <ORGANIZATION> nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
# OF SUCH DAMAGE.
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import json
|
||||
import os
|
||||
@ -41,11 +43,11 @@ class CallbackModule(object):
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
self.acom_callback_event_script = os.getenv('ACOM_CALLBACK_EVENT_SCRIPT')
|
||||
self.callback_script = os.getenv('ACOM_CALLBACK_EVENT_SCRIPT')
|
||||
|
||||
def _log_event(self, event, **event_data):
|
||||
event_data_json = json.dumps(event_data)
|
||||
cmdline = [self.acom_callback_event_script, '-e', event, '-d', event_data_json]
|
||||
cmdline = [self.callback_script, '-e', event, '-d', event_data_json]
|
||||
subprocess.check_call(cmdline)
|
||||
|
||||
def on_any(self, *args, **kwargs):
|
||||
@ -117,5 +119,3 @@ class CallbackModule(object):
|
||||
for attr in ('changed', 'dark', 'failures', 'ok', 'processed', 'skipped'):
|
||||
d[attr] = getattr(stats, attr)
|
||||
self._log_event('playbook_on_stats', **d)
|
||||
|
||||
|
||||
|
||||
@ -116,10 +116,10 @@ pre.result-display {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
#launch_job_host_summaries-group table td.original p {
|
||||
#job_host_summaries-group table td.original p {
|
||||
display: none
|
||||
}
|
||||
#launch_job_host_summaries-group table tr.has_original td {
|
||||
#job_host_summaries-group table tr.has_original td {
|
||||
padding-top: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user