mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 01:47:35 -02:30
AC-1040 Unified jobs updates to get unit tests to pass (hopefully).
This commit is contained in:
@@ -339,7 +339,8 @@ class ProjectSerializer(BaseSerializer):
|
|||||||
'scm_branch', 'scm_clean',
|
'scm_branch', 'scm_clean',
|
||||||
'scm_delete_on_update', 'scm_delete_on_next_update',
|
'scm_delete_on_update', 'scm_delete_on_next_update',
|
||||||
'scm_update_on_launch', 'credential',
|
'scm_update_on_launch', 'credential',
|
||||||
'last_update_failed', 'status', 'last_updated')
|
#'last_update_failed', 'status', 'last_updated')
|
||||||
|
'last_job_failed', 'status', 'last_job_run')
|
||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
@@ -356,12 +357,17 @@ class ProjectSerializer(BaseSerializer):
|
|||||||
if obj.credential and obj.credential.active:
|
if obj.credential and obj.credential.active:
|
||||||
res['credential'] = reverse('api:credential_detail',
|
res['credential'] = reverse('api:credential_detail',
|
||||||
args=(obj.credential.pk,))
|
args=(obj.credential.pk,))
|
||||||
if obj.current_update:
|
#if obj.current_update:
|
||||||
res['current_update'] = reverse('api:project_update_detail',
|
# res['current_update'] = reverse('api:project_update_detail',
|
||||||
args=(obj.current_update.pk,))
|
#if obj.last_update:
|
||||||
if obj.last_update:
|
# res['last_update'] = reverse('api:project_update_detail',
|
||||||
res['last_update'] = reverse('api:project_update_detail',
|
# args=(obj.last_update.pk,))
|
||||||
args=(obj.last_update.pk,))
|
if obj.current_job:
|
||||||
|
res['current_job'] = reverse('api:project_update_detail',
|
||||||
|
args=(obj.current_job.pk,))
|
||||||
|
if obj.last_job:
|
||||||
|
res['last_job'] = reverse('api:project_update_detail',
|
||||||
|
args=(obj.last_job.pk,))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate_local_path(self, attrs, source):
|
def validate_local_path(self, attrs, source):
|
||||||
@@ -694,8 +700,9 @@ class InventorySourceSerializer(BaseSerializer):
|
|||||||
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||||
'modified', 'inventory', 'group', 'source', 'source_path',
|
'modified', 'inventory', 'group', 'source', 'source_path',
|
||||||
'source_vars', 'credential', 'source_regions', 'overwrite',
|
'source_vars', 'credential', 'source_regions', 'overwrite',
|
||||||
'overwrite_vars', 'update_on_launch', 'update_interval',
|
'overwrite_vars', 'update_on_launch', #'update_interval',
|
||||||
'last_update_failed', 'status', 'last_updated')
|
#'last_update_failed', 'status', 'last_updated')
|
||||||
|
'last_job_failed', 'status', 'last_job_run')
|
||||||
read_only_fields = ('inventory', 'group')
|
read_only_fields = ('inventory', 'group')
|
||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
@@ -716,12 +723,18 @@ class InventorySourceSerializer(BaseSerializer):
|
|||||||
if obj.credential and obj.credential.active:
|
if obj.credential and obj.credential.active:
|
||||||
res['credential'] = reverse('api:credential_detail',
|
res['credential'] = reverse('api:credential_detail',
|
||||||
args=(obj.credential.pk,))
|
args=(obj.credential.pk,))
|
||||||
if obj.current_update:
|
#if obj.current_update:
|
||||||
res['current_update'] = reverse('api:inventory_update_detail',
|
# res['current_update'] = reverse('api:inventory_update_detail',
|
||||||
args=(obj.current_update.pk,))
|
# args=(obj.current_update.pk,))
|
||||||
if obj.last_update:
|
#if obj.last_update:
|
||||||
res['last_update'] = reverse('api:inventory_update_detail',
|
# res['last_update'] = reverse('api:inventory_update_detail',
|
||||||
args=(obj.last_update.pk,))
|
# args=(obj.last_update.pk,))
|
||||||
|
if obj.current_job:
|
||||||
|
res['current_job'] = reverse('api:inventory_update_detail',
|
||||||
|
args=(obj.current_job.pk,))
|
||||||
|
if obj.last_job:
|
||||||
|
res['last_job'] = reverse('api:inventory_update_detail',
|
||||||
|
args=(obj.last_job.pk,))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_summary_fields(self, obj):
|
def get_summary_fields(self, obj):
|
||||||
|
|||||||
@@ -644,7 +644,7 @@ class ProjectList(ListCreateAPIView):
|
|||||||
projects_qs = Project.objects.filter(active=True)
|
projects_qs = Project.objects.filter(active=True)
|
||||||
projects_qs = projects_qs.select_related('current_update', 'last_updated')
|
projects_qs = projects_qs.select_related('current_update', 'last_updated')
|
||||||
for project in projects_qs:
|
for project in projects_qs:
|
||||||
project.set_status_and_last_updated()
|
project._set_status_and_last_job_run()
|
||||||
return super(ProjectList, self).get(request, *args, **kwargs)
|
return super(ProjectList, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
class ProjectDetail(RetrieveUpdateDestroyAPIView):
|
class ProjectDetail(RetrieveUpdateDestroyAPIView):
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ class GroupAccess(BaseAccess):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = self.model.objects.filter(active=True).distinct()
|
qs = self.model.objects.filter(active=True).distinct()
|
||||||
qs = qs.select_related('created_by', 'inventory', 'inventory_source')
|
qs = qs.select_related('created_by', 'inventory')#, 'inventory_source')
|
||||||
qs = qs.prefetch_related('parents', 'children')
|
qs = qs.prefetch_related('parents', 'children')
|
||||||
inventories_qs = self.user.get_queryset(Inventory)
|
inventories_qs = self.user.get_queryset(Inventory)
|
||||||
return qs.filter(inventory__in=inventories_qs)
|
return qs.filter(inventory__in=inventories_qs)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class AutoSingleRelatedObjectDescriptor(SingleRelatedObjectDescriptor):
|
|||||||
except self.related.model.DoesNotExist:
|
except self.related.model.DoesNotExist:
|
||||||
obj = self.related.model(**{self.related.field.name: instance})
|
obj = self.related.model(**{self.related.field.name: instance})
|
||||||
if self.related.field.rel.parent_link:
|
if self.related.field.rel.parent_link:
|
||||||
|
raise NotImplementedError('not supported with polymorphic!')
|
||||||
for f in instance._meta.local_fields:
|
for f in instance._meta.local_fields:
|
||||||
setattr(obj, f.name, getattr(instance, f.name))
|
setattr(obj, f.name, getattr(instance, f.name))
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|||||||
@@ -53,15 +53,36 @@ class Migration(DataMigration):
|
|||||||
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.Project._meta.app_label, model=orm.Project._meta.module_name)
|
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.Project._meta.app_label, model=orm.Project._meta.module_name)
|
||||||
for project in orm.Project.objects.order_by('pk'):
|
for project in orm.Project.objects.order_by('pk'):
|
||||||
d = self._get_dict_from_common_model(project)
|
d = self._get_dict_from_common_model(project)
|
||||||
d['polymorphic_ctype_id'] = new_ctype.pk
|
d.update({
|
||||||
|
'polymorphic_ctype_id': new_ctype.pk,
|
||||||
|
'local_path': project.local_path,
|
||||||
|
'scm_type': project.scm_type,
|
||||||
|
'scm_url': project.scm_url,
|
||||||
|
'scm_branch': project.scm_branch,
|
||||||
|
'scm_clean': project.scm_clean,
|
||||||
|
'scm_delete_on_update': project.scm_delete_on_update,
|
||||||
|
'credential_id': project.credential_id,
|
||||||
|
'scm_delete_on_next_update': project.scm_delete_on_next_update,
|
||||||
|
'scm_update_on_launch': project.scm_update_on_launch,
|
||||||
|
})
|
||||||
new_project, created = orm.ProjectNew.objects.get_or_create(old_pk=project.pk, defaults=d)
|
new_project, created = orm.ProjectNew.objects.get_or_create(old_pk=project.pk, defaults=d)
|
||||||
|
|
||||||
# Copy ProjectUpdate old to new.
|
# Copy ProjectUpdate old to new.
|
||||||
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.ProjectUpdate._meta.app_label, model=orm.ProjectUpdate._meta.module_name)
|
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.ProjectUpdate._meta.app_label, model=orm.ProjectUpdate._meta.module_name)
|
||||||
for project_update in orm.ProjectUpdate.objects.order_by('pk'):
|
for project_update in orm.ProjectUpdate.objects.order_by('pk'):
|
||||||
|
project = project_update.project
|
||||||
d = self._get_dict_from_common_task_model(project_update)
|
d = self._get_dict_from_common_task_model(project_update)
|
||||||
d['project_id'] = orm.ProjectNew.objects.get(old_pk=project_update.project_id).pk
|
d.update({
|
||||||
d['polymorphic_ctype_id'] = new_ctype.pk
|
'polymorphic_ctype_id': new_ctype.pk,
|
||||||
|
'project_id': orm.ProjectNew.objects.get(old_pk=project_update.project_id).pk,
|
||||||
|
'local_path': project.local_path,
|
||||||
|
'scm_type': project.scm_type,
|
||||||
|
'scm_url': project.scm_url,
|
||||||
|
'scm_branch': project.scm_branch,
|
||||||
|
'scm_clean': project.scm_clean,
|
||||||
|
'scm_delete_on_update': project.scm_delete_on_update,
|
||||||
|
'credential_id': project.credential_id,
|
||||||
|
})
|
||||||
new_project_update, created = orm.ProjectUpdateNew.objects.get_or_create(old_pk=project_update.pk, defaults=d)
|
new_project_update, created = orm.ProjectUpdateNew.objects.get_or_create(old_pk=project_update.pk, defaults=d)
|
||||||
|
|
||||||
# Update Project last run.
|
# Update Project last run.
|
||||||
@@ -71,6 +92,9 @@ class Migration(DataMigration):
|
|||||||
new_project.current_job = orm.ProjectUpdateNew.objects.get(old_pk=project.current_update_id)
|
new_project.current_job = orm.ProjectUpdateNew.objects.get(old_pk=project.current_update_id)
|
||||||
if project.last_update:
|
if project.last_update:
|
||||||
new_project.last_job = orm.ProjectUpdateNew.objects.get(old_pk=project.last_update_id)
|
new_project.last_job = orm.ProjectUpdateNew.objects.get(old_pk=project.last_update_id)
|
||||||
|
new_project.last_job_failed = project.last_update_failed
|
||||||
|
new_project.last_job_run = project.last_updated
|
||||||
|
new_project.status = project.status
|
||||||
new_project.save()
|
new_project.save()
|
||||||
|
|
||||||
# Update Organization projects.
|
# Update Organization projects.
|
||||||
@@ -97,15 +121,38 @@ class Migration(DataMigration):
|
|||||||
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.InventorySource._meta.app_label, model=orm.InventorySource._meta.module_name)
|
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.InventorySource._meta.app_label, model=orm.InventorySource._meta.module_name)
|
||||||
for inventory_source in orm.InventorySource.objects.order_by('pk'):
|
for inventory_source in orm.InventorySource.objects.order_by('pk'):
|
||||||
d = self._get_dict_from_common_model(inventory_source)
|
d = self._get_dict_from_common_model(inventory_source)
|
||||||
d['polymorphic_ctype_id'] = new_ctype.pk
|
d.update({
|
||||||
|
'polymorphic_ctype_id': new_ctype.pk,
|
||||||
|
'source': inventory_source.source,
|
||||||
|
'source_path': inventory_source.source_path,
|
||||||
|
'source_vars': inventory_source.source_vars,
|
||||||
|
'credential_id': inventory_source.credential_id,
|
||||||
|
'source_regions': inventory_source.source_regions,
|
||||||
|
'overwrite': inventory_source.overwrite,
|
||||||
|
'overwrite_vars': inventory_source.overwrite_vars,
|
||||||
|
'update_on_launch': inventory_source.update_on_launch,
|
||||||
|
'inventory_id': inventory_source.inventory_id,
|
||||||
|
'group_id': inventory_source.group_id,
|
||||||
|
})
|
||||||
new_inventory_source, created = orm.InventorySourceNew.objects.get_or_create(old_pk=inventory_source.pk, defaults=d)
|
new_inventory_source, created = orm.InventorySourceNew.objects.get_or_create(old_pk=inventory_source.pk, defaults=d)
|
||||||
|
|
||||||
# Copy InventoryUpdate old to new.
|
# Copy InventoryUpdate old to new.
|
||||||
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.InventoryUpdate._meta.app_label, model=orm.InventoryUpdate._meta.module_name)
|
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.InventoryUpdate._meta.app_label, model=orm.InventoryUpdate._meta.module_name)
|
||||||
for inventory_update in orm.InventoryUpdate.objects.order_by('pk'):
|
for inventory_update in orm.InventoryUpdate.objects.order_by('pk'):
|
||||||
|
inventory_source = inventory_update.inventory_source
|
||||||
d = self._get_dict_from_common_task_model(inventory_update)
|
d = self._get_dict_from_common_task_model(inventory_update)
|
||||||
d['inventory_source_id'] = orm.InventorySourceNew.objects.get(old_pk=inventory_update.inventory_source_id).pk
|
d.update({
|
||||||
d['polymorphic_ctype_id'] = new_ctype.pk
|
'polymorphic_ctype_id': new_ctype.pk,
|
||||||
|
'source': inventory_source.source,
|
||||||
|
'source_path': inventory_source.source_path,
|
||||||
|
'source_vars': inventory_source.source_vars,
|
||||||
|
'credential_id': inventory_source.credential_id,
|
||||||
|
'source_regions': inventory_source.source_regions,
|
||||||
|
'overwrite': inventory_source.overwrite,
|
||||||
|
'overwrite_vars': inventory_source.overwrite_vars,
|
||||||
|
'inventory_source_id': orm.InventorySourceNew.objects.get(old_pk=inventory_update.inventory_source_id).pk,
|
||||||
|
'license_error': inventory_update.license_error,
|
||||||
|
})
|
||||||
new_inventory_update, created = orm.InventoryUpdateNew.objects.get_or_create(old_pk=inventory_update.pk, defaults=d)
|
new_inventory_update, created = orm.InventoryUpdateNew.objects.get_or_create(old_pk=inventory_update.pk, defaults=d)
|
||||||
|
|
||||||
# Update InventorySource last run.
|
# Update InventorySource last run.
|
||||||
@@ -115,6 +162,9 @@ class Migration(DataMigration):
|
|||||||
new_inventory_source.current_job = orm.InventoryUpdateNew.objects.get(old_pk=inventory_source.current_update_id)
|
new_inventory_source.current_job = orm.InventoryUpdateNew.objects.get(old_pk=inventory_source.current_update_id)
|
||||||
if inventory_source.last_update:
|
if inventory_source.last_update:
|
||||||
new_inventory_source.last_job = orm.InventoryUpdateNew.objects.get(old_pk=inventory_source.last_update_id)
|
new_inventory_source.last_job = orm.InventoryUpdateNew.objects.get(old_pk=inventory_source.last_update_id)
|
||||||
|
new_inventory_source.last_job_failed = inventory_source.last_update_failed
|
||||||
|
new_inventory_source.last_job_run = inventory_source.last_updated
|
||||||
|
new_inventory_source.status = inventory_source.status
|
||||||
new_inventory_source.save()
|
new_inventory_source.save()
|
||||||
|
|
||||||
# Update Group inventory_sources.
|
# Update Group inventory_sources.
|
||||||
@@ -133,20 +183,57 @@ class Migration(DataMigration):
|
|||||||
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.JobTemplate._meta.app_label, model=orm.JobTemplate._meta.module_name)
|
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.JobTemplate._meta.app_label, model=orm.JobTemplate._meta.module_name)
|
||||||
for job_template in orm.JobTemplate.objects.order_by('pk'):
|
for job_template in orm.JobTemplate.objects.order_by('pk'):
|
||||||
d = self._get_dict_from_common_model(job_template)
|
d = self._get_dict_from_common_model(job_template)
|
||||||
|
d.update({
|
||||||
|
'polymorphic_ctype_id': new_ctype.pk,
|
||||||
|
'job_type': job_template.job_type,
|
||||||
|
'inventory_id': job_template.inventory_id,
|
||||||
|
'playbook': job_template.playbook,
|
||||||
|
'credential_id': job_template.credential_id,
|
||||||
|
'cloud_credential_id': job_template.cloud_credential_id,
|
||||||
|
'forks': job_template.forks,
|
||||||
|
'limit': job_template.limit,
|
||||||
|
'extra_vars': job_template.extra_vars,
|
||||||
|
'job_tags': job_template.job_tags,
|
||||||
|
'host_config_key': job_template.host_config_key,
|
||||||
|
})
|
||||||
if job_template.project:
|
if job_template.project:
|
||||||
d['project_id'] = orm.ProjectNew.objects.get(old_pk=job_template.project_id).pk
|
d['project_id'] = orm.ProjectNew.objects.get(old_pk=job_template.project_id).pk
|
||||||
d['polymorphic_ctype_id'] = new_ctype.pk
|
|
||||||
new_job_template, created = orm.JobTemplateNew.objects.get_or_create(old_pk=job_template.pk, defaults=d)
|
new_job_template, created = orm.JobTemplateNew.objects.get_or_create(old_pk=job_template.pk, defaults=d)
|
||||||
|
|
||||||
# Copy Job old to new.
|
# Copy Job old to new.
|
||||||
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.Job._meta.app_label, model=orm.Job._meta.module_name)
|
new_ctype = orm['contenttypes.ContentType'].objects.get(app_label=orm.Job._meta.app_label, model=orm.Job._meta.module_name)
|
||||||
for job in orm.Job.objects.order_by('pk'):
|
for job in orm.Job.objects.order_by('pk'):
|
||||||
d = self._get_dict_from_common_task_model(job)
|
d = self._get_dict_from_common_task_model(job)
|
||||||
|
d.update({
|
||||||
|
'polymorphic_ctype_id': new_ctype.pk,
|
||||||
|
'job_type': job_template.job_type,
|
||||||
|
'inventory_id': job_template.inventory_id,
|
||||||
|
'playbook': job_template.playbook,
|
||||||
|
'credential_id': job_template.credential_id,
|
||||||
|
'cloud_credential_id': job_template.cloud_credential_id,
|
||||||
|
'forks': job_template.forks,
|
||||||
|
'limit': job_template.limit,
|
||||||
|
'extra_vars': job_template.extra_vars,
|
||||||
|
'job_tags': job_template.job_tags,
|
||||||
|
})
|
||||||
if job.project:
|
if job.project:
|
||||||
d['project_id'] = orm.ProjectNew.objects.get(old_pk=job.project_id).pk
|
d['project_id'] = orm.ProjectNew.objects.get(old_pk=job.project_id).pk
|
||||||
d['polymorphic_ctype_id'] = new_ctype.pk
|
if job.job_template:
|
||||||
|
d['job_template_id'] = orm.JobTemplateNew.objects.get(old_pk=job.job_template_id).pk
|
||||||
new_job, created = orm.JobNew.objects.get_or_create(old_pk=job.pk, defaults=d)
|
new_job, created = orm.JobNew.objects.get_or_create(old_pk=job.pk, defaults=d)
|
||||||
|
|
||||||
|
# Update JobTemplate last run.
|
||||||
|
for new_job_template in orm.JobTemplateNew.objects.order_by('pk'):
|
||||||
|
try:
|
||||||
|
new_last_job = new_job_template.jobs.order_by('-pk')[0]
|
||||||
|
new_job_template.last_job = new_last_job
|
||||||
|
new_job_template.last_job_failed = new_last_job.failed
|
||||||
|
new_job_template.last_job_run = new_last_job.finished
|
||||||
|
new_job_template.status = 'failed' if new_last_job.failed else 'successful'
|
||||||
|
except IndexError:
|
||||||
|
new_job_template.status = 'never updated'
|
||||||
|
new_inventory_source.save()
|
||||||
|
|
||||||
# Update JobHostSummary job.
|
# Update JobHostSummary job.
|
||||||
for job_host_summary in orm.JobHostSummary.objects.order_by('pk'):
|
for job_host_summary in orm.JobHostSummary.objects.order_by('pk'):
|
||||||
new_job = orm.JobNew.objects.get(old_pk=job_host_summary.job_id)
|
new_job = orm.JobNew.objects.get(old_pk=job_host_summary.job_id)
|
||||||
@@ -192,6 +279,7 @@ class Migration(DataMigration):
|
|||||||
"Write your backwards methods here."
|
"Write your backwards methods here."
|
||||||
|
|
||||||
# FIXME: Would like to have this, but not required.
|
# FIXME: Would like to have this, but not required.
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
models = {
|
models = {
|
||||||
u'auth.group': {
|
u'auth.group': {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django.db import models
|
|||||||
|
|
||||||
class Migration(SchemaMigration):
|
class Migration(SchemaMigration):
|
||||||
'''
|
'''
|
||||||
Rename tables to be consistent with model names.
|
Rename tables/columns to be consistent with model/field names.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def forwards(self, orm):
|
def forwards(self, orm):
|
||||||
@@ -19,41 +19,60 @@ class Migration(SchemaMigration):
|
|||||||
db.rename_table(u'main_jobnew', 'main_job')
|
db.rename_table(u'main_jobnew', 'main_job')
|
||||||
|
|
||||||
db.rename_table(db.shorten_name(u'main_team_new_projects'), db.shorten_name(u'main_team_projects'))
|
db.rename_table(db.shorten_name(u'main_team_new_projects'), db.shorten_name(u'main_team_projects'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_team_projects'), 'projectnew_id', 'project_id')
|
||||||
db.rename_table(db.shorten_name(u'main_organization_new_projects'), db.shorten_name(u'main_organization_projects'))
|
db.rename_table(db.shorten_name(u'main_organization_new_projects'), db.shorten_name(u'main_organization_projects'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_organization_projects'), 'projectnew_id', 'project_id')
|
||||||
db.rename_column(u'main_permission', 'new_project_id', 'project_id')
|
db.rename_column(u'main_permission', 'new_project_id', 'project_id')
|
||||||
|
|
||||||
db.rename_column(u'main_host', 'new_last_job_id', 'last_job_id')
|
db.rename_column(u'main_host', 'new_last_job_id', 'last_job_id')
|
||||||
db.rename_table(db.shorten_name(u'main_host_new_inventory_sources'), db.shorten_name(u'main_host_inventory_sources'))
|
db.rename_table(db.shorten_name(u'main_host_new_inventory_sources'), db.shorten_name(u'main_host_inventory_sources'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_host_inventory_sources'), 'inventorysourcenew_id', 'inventorysource_id')
|
||||||
db.rename_table(db.shorten_name(u'main_group_new_inventory_sources'), db.shorten_name(u'main_group_inventory_sources'))
|
db.rename_table(db.shorten_name(u'main_group_new_inventory_sources'), db.shorten_name(u'main_group_inventory_sources'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_group_inventory_sources'), 'inventorysourcenew_id', 'inventorysource_id')
|
||||||
|
|
||||||
db.rename_column(u'main_jobhostsummary', 'new_job_id', 'job_id')
|
db.rename_column(u'main_jobhostsummary', 'new_job_id', 'job_id')
|
||||||
db.rename_column(u'main_jobevent', 'new_job_id', 'job_id')
|
db.rename_column(u'main_jobevent', 'new_job_id', 'job_id')
|
||||||
|
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_new_project'), db.shorten_name(u'main_activitystream_project'))
|
db.rename_table(db.shorten_name(u'main_activitystream_new_project'), db.shorten_name(u'main_activitystream_project'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_project'), 'projectnew_id', 'project_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_new_project_update'), db.shorten_name(u'main_activitystream_project_update'))
|
db.rename_table(db.shorten_name(u'main_activitystream_new_project_update'), db.shorten_name(u'main_activitystream_project_update'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_project_update'), 'projectupdatenew_id', 'projectupdate_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_new_inventory_source'), db.shorten_name(u'main_activitystream_inventory_source'))
|
db.rename_table(db.shorten_name(u'main_activitystream_new_inventory_source'), db.shorten_name(u'main_activitystream_inventory_source'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_inventory_source'), 'inventorysourcenew_id', 'inventorysource_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_new_inventory_update'), db.shorten_name(u'main_activitystream_inventory_update'))
|
db.rename_table(db.shorten_name(u'main_activitystream_new_inventory_update'), db.shorten_name(u'main_activitystream_inventory_update'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_inventory_update'), 'inventoryupdatenew_id', 'inventoryupdate_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_new_job_template'), db.shorten_name(u'main_activitystream_job_template'))
|
db.rename_table(db.shorten_name(u'main_activitystream_new_job_template'), db.shorten_name(u'main_activitystream_job_template'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_job_template'), 'jobtemplatenew_id', 'jobtemplate_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_new_job'), db.shorten_name(u'main_activitystream_job'))
|
db.rename_table(db.shorten_name(u'main_activitystream_new_job'), db.shorten_name(u'main_activitystream_job'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_job'), 'jobnew_id', 'job_id')
|
||||||
|
|
||||||
def backwards(self, orm):
|
def backwards(self, orm):
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_job'), 'job_id', 'jobnew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_job'), db.shorten_name(u'main_activitystream_new_job'))
|
db.rename_table(db.shorten_name(u'main_activitystream_job'), db.shorten_name(u'main_activitystream_new_job'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_job_template'), 'jobtemplate_id', 'jobtemplatenew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_job_template'), db.shorten_name(u'main_activitystream_new_job_template'))
|
db.rename_table(db.shorten_name(u'main_activitystream_job_template'), db.shorten_name(u'main_activitystream_new_job_template'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_inventory_update'), 'inventoryupdate_id', 'inventoryupdatenew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_inventory_update'), db.shorten_name(u'main_activitystream_new_inventory_update'))
|
db.rename_table(db.shorten_name(u'main_activitystream_inventory_update'), db.shorten_name(u'main_activitystream_new_inventory_update'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_inventory_source'), 'inventorysource_id', 'inventorysourcenew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_inventory_source'), db.shorten_name(u'main_activitystream_new_inventory_source'))
|
db.rename_table(db.shorten_name(u'main_activitystream_inventory_source'), db.shorten_name(u'main_activitystream_new_inventory_source'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_project_update'), 'projectupdate_id', 'projectupdatenew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_project_update'), db.shorten_name(u'main_activitystream_new_project_update'))
|
db.rename_table(db.shorten_name(u'main_activitystream_project_update'), db.shorten_name(u'main_activitystream_new_project_update'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_activitystream_project'), 'project_id', 'projectnew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_activitystream_project'), db.shorten_name(u'main_activitystream_new_project'))
|
db.rename_table(db.shorten_name(u'main_activitystream_project'), db.shorten_name(u'main_activitystream_new_project'))
|
||||||
|
|
||||||
db.rename_column(u'main_jobevent', 'job_id', 'new_job_id')
|
db.rename_column(u'main_jobevent', 'job_id', 'new_job_id')
|
||||||
db.rename_column(u'main_jobhostsummary', 'job_id', 'new_job_id')
|
db.rename_column(u'main_jobhostsummary', 'job_id', 'new_job_id')
|
||||||
|
|
||||||
|
db.rename_column(db.shorten_name(u'main_group_inventory_sources'), 'inventorysource_id', 'inventorysourcenew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_group_inventory_sources'), db.shorten_name(u'main_group_new_inventory_sources'))
|
db.rename_table(db.shorten_name(u'main_group_inventory_sources'), db.shorten_name(u'main_group_new_inventory_sources'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_host_inventory_sources'), 'inventorysource_id', 'inventorysourcenew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_host_inventory_sources'), db.shorten_name(u'main_host_new_inventory_sources'))
|
db.rename_table(db.shorten_name(u'main_host_inventory_sources'), db.shorten_name(u'main_host_new_inventory_sources'))
|
||||||
db.rename_column(u'main_host', 'last_job_id', 'new_last_job_id')
|
db.rename_column(u'main_host', 'last_job_id', 'new_last_job_id')
|
||||||
|
|
||||||
db.rename_column(u'main_permission', 'project_id', 'new_project_id')
|
db.rename_column(u'main_permission', 'project_id', 'new_project_id')
|
||||||
|
db.rename_column(db.shorten_name(u'main_organization_projects'), 'project_id', 'projectnew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_organization_projects'), db.shorten_name(u'main_organization_new_projects'))
|
db.rename_table(db.shorten_name(u'main_organization_projects'), db.shorten_name(u'main_organization_new_projects'))
|
||||||
|
db.rename_column(db.shorten_name(u'main_team_projects'), 'project_id', 'projectnew_id')
|
||||||
db.rename_table(db.shorten_name(u'main_team_projects'), db.shorten_name(u'main_team_new_projects'))
|
db.rename_table(db.shorten_name(u'main_team_projects'), db.shorten_name(u'main_team_new_projects'))
|
||||||
|
|
||||||
db.rename_table(u'main_job', 'main_jobnew')
|
db.rename_table(u'main_job', 'main_jobnew')
|
||||||
|
|||||||
@@ -58,12 +58,12 @@ class ActivityStreamBase(models.Model):
|
|||||||
# For compatibility with Django 1.4.x, attempt to handle any calls to
|
# For compatibility with Django 1.4.x, attempt to handle any calls to
|
||||||
# save that pass update_fields.
|
# save that pass update_fields.
|
||||||
try:
|
try:
|
||||||
super(ActivityStream, self).save(*args, **kwargs)
|
super(ActivityStreamBase, self).save(*args, **kwargs)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
if 'update_fields' not in kwargs:
|
if 'update_fields' not in kwargs:
|
||||||
raise
|
raise
|
||||||
kwargs.pop('update_fields')
|
kwargs.pop('update_fields')
|
||||||
super(ActivityStream, self).save(*args, **kwargs)
|
super(ActivityStreamBase, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
||||||
|
|||||||
@@ -133,7 +133,8 @@ class Inventory(CommonModel):
|
|||||||
active_groups = self.groups.filter(active=True)
|
active_groups = self.groups.filter(active=True)
|
||||||
failed_groups = active_groups.filter(has_active_failures=True)
|
failed_groups = active_groups.filter(has_active_failures=True)
|
||||||
active_inventory_sources = self.inventory_sources.filter(active=True, source__in=CLOUD_INVENTORY_SOURCES)
|
active_inventory_sources = self.inventory_sources.filter(active=True, source__in=CLOUD_INVENTORY_SOURCES)
|
||||||
failed_inventory_sources = active_inventory_sources.filter(last_update_failed=True)
|
#failed_inventory_sources = active_inventory_sources.filter(last_update_failed=True)
|
||||||
|
failed_inventory_sources = active_inventory_sources.filter(last_job_failed=True)
|
||||||
computed_fields = {
|
computed_fields = {
|
||||||
'has_active_failures': bool(failed_hosts.count()),
|
'has_active_failures': bool(failed_hosts.count()),
|
||||||
'total_hosts': active_hosts.count(),
|
'total_hosts': active_hosts.count(),
|
||||||
@@ -233,7 +234,7 @@ class HostBase(CommonModelNameNotUnique):
|
|||||||
When marking hosts inactive, remove all associations to related
|
When marking hosts inactive, remove all associations to related
|
||||||
inventory sources.
|
inventory sources.
|
||||||
'''
|
'''
|
||||||
super(Host, self).mark_inactive(save=save)
|
super(HostBase, self).mark_inactive(save=save)
|
||||||
self.inventory_sources.clear()
|
self.inventory_sources.clear()
|
||||||
|
|
||||||
def update_computed_fields(self, update_inventory=True, update_groups=True):
|
def update_computed_fields(self, update_inventory=True, update_groups=True):
|
||||||
@@ -457,7 +458,7 @@ class GroupBase(CommonModelNameNotUnique):
|
|||||||
groups/hosts/inventory_sources.
|
groups/hosts/inventory_sources.
|
||||||
'''
|
'''
|
||||||
def mark_actual():
|
def mark_actual():
|
||||||
super(Group, self).mark_inactive(save=save)
|
super(GroupBase, self).mark_inactive(save=save)
|
||||||
self.inventory_source.mark_inactive(save=save)
|
self.inventory_source.mark_inactive(save=save)
|
||||||
self.inventory_sources.clear()
|
self.inventory_sources.clear()
|
||||||
self.parents.clear()
|
self.parents.clear()
|
||||||
@@ -674,20 +675,6 @@ class InventorySourceOptions(BaseModel):
|
|||||||
help_text=_('Overwrite local variables from remote inventory source.'),
|
help_text=_('Overwrite local variables from remote inventory source.'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InventorySourceBase(InventorySourceOptions):
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
app_label = 'main'
|
|
||||||
|
|
||||||
update_on_launch = models.BooleanField(
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
update_cache_timeout = models.PositiveIntegerField(
|
|
||||||
default=0,
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ec2_region_choices(cls):
|
def get_ec2_region_choices(cls):
|
||||||
ec2_region_names = getattr(settings, 'EC2_REGION_NAMES', {})
|
ec2_region_names = getattr(settings, 'EC2_REGION_NAMES', {})
|
||||||
@@ -758,57 +745,46 @@ class InventorySourceBase(InventorySourceOptions):
|
|||||||
', '.join(invalid_regions)))
|
', '.join(invalid_regions)))
|
||||||
return ','.join(regions)
|
return ','.join(regions)
|
||||||
|
|
||||||
|
|
||||||
|
class InventorySourceBase(InventorySourceOptions):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
app_label = 'main'
|
||||||
|
|
||||||
|
update_on_launch = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
update_cache_timeout = models.PositiveIntegerField(
|
||||||
|
default=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InventorySourceBaseMethods(object):
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
new_instance = not bool(self.pk)
|
|
||||||
# If update_fields has been specified, add our field names to it,
|
# If update_fields has been specified, add our field names to it,
|
||||||
# if it hasn't been specified, then we're just doing a normal save.
|
# if it hasn't been specified, then we're just doing a normal save.
|
||||||
update_fields = kwargs.get('update_fields', [])
|
update_fields = kwargs.get('update_fields', [])
|
||||||
# Update status and last_updated fields.
|
|
||||||
updated_fields = self.set_status_and_last_updated(save=False)
|
|
||||||
for field in updated_fields:
|
|
||||||
if field not in update_fields:
|
|
||||||
update_fields.append(field)
|
|
||||||
# Update inventory from group (if available).
|
# Update inventory from group (if available).
|
||||||
if self.group and not self.inventory:
|
if self.group and not self.inventory:
|
||||||
self.inventory = self.group.inventory
|
self.inventory = self.group.inventory
|
||||||
if 'inventory' not in update_fields:
|
if 'inventory' not in update_fields:
|
||||||
update_fields.append('inventory')
|
update_fields.append('inventory')
|
||||||
|
# Set name automatically.
|
||||||
|
if not self.name:
|
||||||
|
self.name = 'inventory_source %s' % now()
|
||||||
|
if 'name' not in update_fields:
|
||||||
|
update_fields.append('name')
|
||||||
# Do the actual save.
|
# Do the actual save.
|
||||||
super(InventorySource, self).save(*args, **kwargs)
|
super(InventorySourceBaseMethods, self).save(*args, **kwargs)
|
||||||
|
|
||||||
source_vars_dict = VarsDictProperty('source_vars')
|
source_vars_dict = VarsDictProperty('source_vars')
|
||||||
|
|
||||||
def set_status_and_last_updated(self, save=True):
|
def get_absolute_url(self):
|
||||||
# Determine current status.
|
return reverse('api:inventory_source_detail', args=(self.pk,))
|
||||||
if self.source:
|
|
||||||
if self.current_update:
|
|
||||||
status = 'updating'
|
|
||||||
elif not self.last_update:
|
|
||||||
status = 'never updated'
|
|
||||||
elif self.last_update_failed:
|
|
||||||
status = 'failed'
|
|
||||||
else:
|
|
||||||
status = 'successful'
|
|
||||||
else:
|
|
||||||
status = 'none'
|
|
||||||
# Determine current last_updated timestamp.
|
|
||||||
last_updated = None
|
|
||||||
if self.source and self.last_update:
|
|
||||||
last_updated = self.last_update.modified
|
|
||||||
# Update values if changed.
|
|
||||||
update_fields = []
|
|
||||||
if self.status != status:
|
|
||||||
self.status = status
|
|
||||||
update_fields.append('status')
|
|
||||||
if self.last_updated != last_updated:
|
|
||||||
self.last_updated = last_updated
|
|
||||||
update_fields.append('last_updated')
|
|
||||||
if save and update_fields:
|
|
||||||
self.save(update_fields=update_fields)
|
|
||||||
return update_fields
|
|
||||||
|
|
||||||
@property
|
def _can_update(self):
|
||||||
def can_update(self):
|
|
||||||
# FIXME: Prevent update when another one is active!
|
# FIXME: Prevent update when another one is active!
|
||||||
return bool(self.source)
|
return bool(self.source)
|
||||||
|
|
||||||
@@ -827,13 +803,10 @@ class InventorySourceBase(InventorySourceOptions):
|
|||||||
inventory_update.signal_start(**kwargs)
|
inventory_update.signal_start(**kwargs)
|
||||||
return inventory_update
|
return inventory_update
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('api:inventory_source_detail', args=(self.pk,))
|
|
||||||
|
|
||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
||||||
|
|
||||||
class InventorySource(PrimordialModel, InventorySourceBase):
|
class InventorySource(InventorySourceBaseMethods, PrimordialModel, InventorySourceBase):
|
||||||
|
|
||||||
INVENTORY_SOURCE_STATUS_CHOICES = [
|
INVENTORY_SOURCE_STATUS_CHOICES = [
|
||||||
('none', _('No External Source')),
|
('none', _('No External Source')),
|
||||||
@@ -893,7 +866,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
||||||
|
|
||||||
class InventorySourceNew(UnifiedJobTemplate, InventorySourceBase):
|
class InventorySourceNew(InventorySourceBaseMethods, UnifiedJobTemplate, InventorySourceBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -923,7 +896,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 1:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
||||||
|
|
||||||
class InventorySource(UnifiedJobTemplate, InventorySourceBase):
|
class InventorySource(InventorySourceBaseMethods, UnifiedJobTemplate, InventorySourceBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -959,6 +932,9 @@ class InventoryUpdateBase(InventorySourceOptions):
|
|||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryUpdateBaseMethods(object):
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
update_fields = kwargs.get('update_fields', [])
|
update_fields = kwargs.get('update_fields', [])
|
||||||
if bool('license' in self.result_stdout and
|
if bool('license' in self.result_stdout and
|
||||||
@@ -966,7 +942,7 @@ class InventoryUpdateBase(InventorySourceOptions):
|
|||||||
self.license_error = True
|
self.license_error = True
|
||||||
if 'license_error' not in update_fields:
|
if 'license_error' not in update_fields:
|
||||||
update_fields.append('license_error')
|
update_fields.append('license_error')
|
||||||
super(InventoryUpdate, self).save(*args, **kwargs)
|
super(InventoryUpdateBaseMethods, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def _get_parent_instance(self):
|
def _get_parent_instance(self):
|
||||||
return self.inventory_source
|
return self.inventory_source
|
||||||
@@ -1008,7 +984,7 @@ class InventoryUpdateBase(InventorySourceOptions):
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
||||||
|
|
||||||
class InventoryUpdate(CommonTask, InventoryUpdateBase):
|
class InventoryUpdate(InventoryUpdateBaseMethods, CommonTask, InventoryUpdateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -1022,7 +998,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
||||||
|
|
||||||
class InventoryUpdateNew(UnifiedJob, InventoryUpdateBase):
|
class InventoryUpdateNew(InventoryUpdateBaseMethods, UnifiedJob, InventoryUpdateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -1043,7 +1019,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 1:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
||||||
|
|
||||||
class InventoryUpdate(UnifiedJob, InventoryUpdateBase):
|
class InventoryUpdate(InventoryUpdateBaseMethods, UnifiedJob, InventoryUpdateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ from django.utils.timezone import now, make_aware, get_default_timezone
|
|||||||
# Django-JSONField
|
# Django-JSONField
|
||||||
from jsonfield import JSONField
|
from jsonfield import JSONField
|
||||||
|
|
||||||
|
# Django-Polymorphic
|
||||||
|
from polymorphic import PolymorphicModel
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models.base import *
|
from awx.main.models.base import *
|
||||||
from awx.main.models.unified_jobs import *
|
from awx.main.models.unified_jobs import *
|
||||||
@@ -142,6 +145,7 @@ class JobTemplateBase(JobOptions):
|
|||||||
default='',
|
default='',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class JobTemplateBaseMethods(object):
|
||||||
|
|
||||||
def create_job(self, **kwargs):
|
def create_job(self, **kwargs):
|
||||||
'''
|
'''
|
||||||
@@ -185,7 +189,7 @@ class JobTemplateBase(JobOptions):
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
||||||
|
|
||||||
class JobTemplate(CommonModel, JobTemplateBase):
|
class JobTemplate(JobTemplateBaseMethods, CommonModel, JobTemplateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -199,7 +203,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
||||||
|
|
||||||
class JobTemplateNew(UnifiedJobTemplate, JobTemplateBase):
|
class JobTemplateNew(JobTemplateBaseMethods, UnifiedJobTemplate, JobTemplateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -221,7 +225,8 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 1:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
||||||
|
|
||||||
class JobTemplate(UnifiedJobTemplate, JobTemplateBase):
|
#class JobTemplate(JobTemplateBase, UnifiedJobTemplate):
|
||||||
|
class JobTemplate(JobTemplateBaseMethods, UnifiedJobTemplate, JobTemplateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -253,6 +258,8 @@ class JobBase(JobOptions):
|
|||||||
through='JobHostSummary',
|
through='JobHostSummary',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class JobBaseMethods(object):
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('api:job_detail', args=(self.pk,))
|
return reverse('api:job_detail', args=(self.pk,))
|
||||||
|
|
||||||
@@ -405,7 +412,7 @@ class JobBase(JobOptions):
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
||||||
|
|
||||||
class Job(CommonTask, JobBase):
|
class Job(JobBaseMethods, CommonTask, JobBase):
|
||||||
|
|
||||||
LAUNCH_TYPE_CHOICES = [
|
LAUNCH_TYPE_CHOICES = [
|
||||||
('manual', _('Manual')),
|
('manual', _('Manual')),
|
||||||
@@ -439,7 +446,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
||||||
|
|
||||||
class JobNew(UnifiedJob, JobBase):
|
class JobNew(JobBaseMethods, UnifiedJob, JobBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -468,7 +475,8 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 1:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
||||||
|
|
||||||
class Job(UnifiedJob, JobBase):
|
#class Job(JobBase, UnifiedJob):
|
||||||
|
class Job(JobBaseMethods, UnifiedJob, JobBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -535,7 +543,7 @@ class JobHostSummaryBase(CreatedModifiedModel):
|
|||||||
update_fields = kwargs.get('update_fields', [])
|
update_fields = kwargs.get('update_fields', [])
|
||||||
self.failed = bool(self.dark or self.failures)
|
self.failed = bool(self.dark or self.failures)
|
||||||
update_fields.append('failed')
|
update_fields.append('failed')
|
||||||
super(JobHostSummary, self).save(*args, **kwargs)
|
super(JobHostSummaryBase, self).save(*args, **kwargs)
|
||||||
self.update_host_last_job_summary()
|
self.update_host_last_job_summary()
|
||||||
|
|
||||||
def update_host_last_job_summary(self):
|
def update_host_last_job_summary(self):
|
||||||
@@ -887,7 +895,7 @@ class JobEventBase(CreatedModifiedModel):
|
|||||||
self.parent = self._find_parent()
|
self.parent = self._find_parent()
|
||||||
if 'parent' not in update_fields:
|
if 'parent' not in update_fields:
|
||||||
update_fields.append('parent')
|
update_fields.append('parent')
|
||||||
super(JobEvent, self).save(*args, **kwargs)
|
super(JobEventBase, self).save(*args, **kwargs)
|
||||||
if post_process and not from_parent_update:
|
if post_process and not from_parent_update:
|
||||||
self.update_parent_failed_and_changed()
|
self.update_parent_failed_and_changed()
|
||||||
# FIXME: The update_hosts() call (and its queries) are the current
|
# FIXME: The update_hosts() call (and its queries) are the current
|
||||||
|
|||||||
@@ -175,6 +175,9 @@ class ProjectBase(ProjectOptions):
|
|||||||
default=0,
|
default=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectBaseMethods(object):
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
new_instance = not bool(self.pk)
|
new_instance = not bool(self.pk)
|
||||||
# If update_fields has been specified, add our field names to it,
|
# If update_fields has been specified, add our field names to it,
|
||||||
@@ -182,7 +185,7 @@ class ProjectBase(ProjectOptions):
|
|||||||
update_fields = kwargs.get('update_fields', [])
|
update_fields = kwargs.get('update_fields', [])
|
||||||
# Check if scm_type or scm_url changes.
|
# Check if scm_type or scm_url changes.
|
||||||
if self.pk:
|
if self.pk:
|
||||||
project_before = Project.objects.get(pk=self.pk)
|
project_before = self.__class__.objects.get(pk=self.pk)
|
||||||
if project_before.scm_type != self.scm_type or project_before.scm_url != self.scm_url:
|
if project_before.scm_type != self.scm_type or project_before.scm_url != self.scm_url:
|
||||||
self.scm_delete_on_next_update = True
|
self.scm_delete_on_next_update = True
|
||||||
if 'scm_delete_on_next_update' not in update_fields:
|
if 'scm_delete_on_next_update' not in update_fields:
|
||||||
@@ -193,13 +196,8 @@ class ProjectBase(ProjectOptions):
|
|||||||
self.local_path = u'_%d__%s' % (self.pk, slug_name)
|
self.local_path = u'_%d__%s' % (self.pk, slug_name)
|
||||||
if 'local_path' not in update_fields:
|
if 'local_path' not in update_fields:
|
||||||
update_fields.append('local_path')
|
update_fields.append('local_path')
|
||||||
# Update status and last_updated fields.
|
|
||||||
updated_fields = self.set_status_and_last_updated(save=False)
|
|
||||||
for field in updated_fields:
|
|
||||||
if field not in update_fields:
|
|
||||||
update_fields.append(field)
|
|
||||||
# Do the actual save.
|
# Do the actual save.
|
||||||
super(Project, self).save(*args, **kwargs)
|
super(ProjectBaseMethods, self).save(*args, **kwargs)
|
||||||
if new_instance:
|
if new_instance:
|
||||||
update_fields=[]
|
update_fields=[]
|
||||||
# Generate local_path for SCM after initial save (so we have a PK).
|
# Generate local_path for SCM after initial save (so we have a PK).
|
||||||
@@ -211,50 +209,37 @@ class ProjectBase(ProjectOptions):
|
|||||||
if new_instance and self.scm_type:
|
if new_instance and self.scm_type:
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def set_status_and_last_updated(self, save=True):
|
def _get_current_status(self):
|
||||||
# Determine current status.
|
|
||||||
if self.scm_type:
|
if self.scm_type:
|
||||||
if self.current_update:
|
if self.current_update:
|
||||||
status = 'updating'
|
return 'updating'
|
||||||
elif not self.last_update:
|
elif not self.last_job:
|
||||||
status = 'never updated'
|
return 'never updated'
|
||||||
elif self.last_update_failed:
|
elif self.last_job_failed:
|
||||||
status = 'failed'
|
return 'failed'
|
||||||
elif not self.get_project_path():
|
elif not self.get_project_path():
|
||||||
status = 'missing'
|
return 'missing'
|
||||||
else:
|
else:
|
||||||
status = 'successful'
|
return 'successful'
|
||||||
elif not self.get_project_path():
|
elif not self.get_project_path():
|
||||||
status = 'missing'
|
return 'missing'
|
||||||
else:
|
else:
|
||||||
status = 'ok'
|
return 'ok'
|
||||||
# Determine current last_updated timestamp.
|
|
||||||
last_updated = None
|
def _get_last_job_run(self):
|
||||||
if self.scm_type and self.last_update:
|
if self.scm_type and self.last_job:
|
||||||
last_updated = self.last_update.modified
|
return self.last_job.finished
|
||||||
else:
|
else:
|
||||||
project_path = self.get_project_path()
|
project_path = self.get_project_path()
|
||||||
if project_path:
|
if project_path:
|
||||||
try:
|
try:
|
||||||
mtime = os.path.getmtime(project_path)
|
mtime = os.path.getmtime(project_path)
|
||||||
dt = datetime.datetime.fromtimestamp(mtime)
|
dt = datetime.datetime.fromtimestamp(mtime)
|
||||||
last_updated = make_aware(dt, get_default_timezone())
|
return make_aware(dt, get_default_timezone())
|
||||||
except os.error:
|
except os.error:
|
||||||
pass
|
pass
|
||||||
# Update values if changed.
|
|
||||||
update_fields = []
|
|
||||||
if self.status != status:
|
|
||||||
self.status = status
|
|
||||||
update_fields.append('status')
|
|
||||||
if self.last_updated != last_updated:
|
|
||||||
self.last_updated = last_updated
|
|
||||||
update_fields.append('last_updated')
|
|
||||||
if save and update_fields:
|
|
||||||
self.save(update_fields=update_fields)
|
|
||||||
return update_fields
|
|
||||||
|
|
||||||
@property
|
def _can_update(self):
|
||||||
def can_update(self):
|
|
||||||
# FIXME: Prevent update when another one is active!
|
# FIXME: Prevent update when another one is active!
|
||||||
return bool(self.scm_type)# and not self.current_update)
|
return bool(self.scm_type)# and not self.current_update)
|
||||||
|
|
||||||
@@ -319,7 +304,7 @@ class ProjectBase(ProjectOptions):
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
||||||
|
|
||||||
class Project(CommonModel, ProjectBase):
|
class Project(ProjectBaseMethods, CommonModel, ProjectBase):
|
||||||
|
|
||||||
PROJECT_STATUS_CHOICES = [
|
PROJECT_STATUS_CHOICES = [
|
||||||
('ok', 'OK'),
|
('ok', 'OK'),
|
||||||
@@ -366,7 +351,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
||||||
|
|
||||||
class ProjectNew(UnifiedJobTemplate, ProjectBase):
|
class ProjectNew(ProjectBaseMethods, UnifiedJobTemplate, ProjectBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -380,7 +365,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 1:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
||||||
|
|
||||||
class Project(UnifiedJobTemplate, ProjectBase):
|
class Project(ProjectBaseMethods, UnifiedJobTemplate, ProjectBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -395,12 +380,15 @@ class ProjectUpdateBase(ProjectOptions):
|
|||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('api:project_update_detail', args=(self.pk,))
|
class ProjectUpdateBaseMethods(object):
|
||||||
|
|
||||||
def _get_parent_instance(self):
|
def _get_parent_instance(self):
|
||||||
return self.project
|
return self.project
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('api:project_update_detail', args=(self.pk,))
|
||||||
|
|
||||||
def _get_task_class(self):
|
def _get_task_class(self):
|
||||||
from awx.main.tasks import RunProjectUpdate
|
from awx.main.tasks import RunProjectUpdate
|
||||||
return RunProjectUpdate
|
return RunProjectUpdate
|
||||||
@@ -436,25 +424,25 @@ class ProjectUpdateBase(ProjectOptions):
|
|||||||
parent_instance = self._get_parent_instance()
|
parent_instance = self._get_parent_instance()
|
||||||
if parent_instance:
|
if parent_instance:
|
||||||
if self.status in ('pending', 'waiting', 'running'):
|
if self.status in ('pending', 'waiting', 'running'):
|
||||||
if parent_instance.current_update != self:
|
if parent_instance.current_job != self:
|
||||||
parent_instance.current_update = self
|
parent_instance.current_job = self
|
||||||
parent_instance.save(update_fields=['current_update'])
|
parent_instance.save(update_fields=['current_job'])
|
||||||
elif self.status in ('successful', 'failed', 'error', 'canceled'):
|
elif self.status in ('successful', 'failed', 'error', 'canceled'):
|
||||||
if parent_instance.current_update == self:
|
if parent_instance.current_job == self:
|
||||||
parent_instance.current_update = None
|
parent_instance.current_job = None
|
||||||
parent_instance.last_update = self
|
parent_instance.last_job = self
|
||||||
parent_instance.last_update_failed = self.failed
|
parent_instance.last_job_failed = self.failed
|
||||||
if not self.failed and parent_instance.scm_delete_on_next_update:
|
if not self.failed and parent_instance.scm_delete_on_next_update:
|
||||||
parent_instance.scm_delete_on_next_update = False
|
parent_instance.scm_delete_on_next_update = False
|
||||||
parent_instance.save(update_fields=['current_update',
|
parent_instance.save(update_fields=['current_job',
|
||||||
'last_update',
|
'last_job',
|
||||||
'last_update_failed',
|
'last_job_failed',
|
||||||
'scm_delete_on_next_update'])
|
'scm_delete_on_next_update'])
|
||||||
|
|
||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
||||||
|
|
||||||
class ProjectUpdate(CommonTask, ProjectUpdateBase):
|
class ProjectUpdate(ProjectUpdateBaseMethods, CommonTask, ProjectUpdateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -468,7 +456,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 0:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
if getattr(settings, 'UNIFIED_JOBS_STEP') in (0, 1):
|
||||||
|
|
||||||
class ProjectUpdateNew(UnifiedJob, ProjectUpdateBase):
|
class ProjectUpdateNew(ProjectUpdateBaseMethods, UnifiedJob, ProjectUpdateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
@@ -489,7 +477,7 @@ if getattr(settings, 'UNIFIED_JOBS_STEP') == 1:
|
|||||||
|
|
||||||
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
if getattr(settings, 'UNIFIED_JOBS_STEP') == 2:
|
||||||
|
|
||||||
class ProjectUpdate(UnifiedJob, ProjectUpdateBase):
|
class ProjectUpdate(ProjectUpdateBaseMethods, UnifiedJob, ProjectUpdateBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
|
|||||||
@@ -40,3 +40,6 @@ class Schedule(CommonModel):
|
|||||||
rrule = models.CharField(
|
rrule = models.CharField(
|
||||||
max_length=255,
|
max_length=255,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
super(Schedule, self).save(*args, **kwargs)
|
||||||
|
|||||||
@@ -109,7 +109,84 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
|
|||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# FIXME: Include code common to Project/InventorySource/JobTemplate
|
@property
|
||||||
|
def current_update(self):
|
||||||
|
return self.current_job
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_update(self):
|
||||||
|
return self.last_job
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_update_failed(self):
|
||||||
|
return self.last_job_failed
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_updated(self):
|
||||||
|
return self.last_job_run
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
# If update_fields has been specified, add our field names to it,
|
||||||
|
# if it hasn't been specified, then we're just doing a normal save.
|
||||||
|
update_fields = kwargs.get('update_fields', [])
|
||||||
|
# Update status and last_updated fields.
|
||||||
|
updated_fields = self._set_status_and_last_job_run(save=False)
|
||||||
|
for field in updated_fields:
|
||||||
|
if field not in update_fields:
|
||||||
|
update_fields.append(field)
|
||||||
|
# Do the actual save.
|
||||||
|
super(UnifiedJobTemplate, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
def _get_current_status(self):
|
||||||
|
# Override in subclasses as needed.
|
||||||
|
if self.current_job:
|
||||||
|
return 'updating'
|
||||||
|
elif not self.last_job:
|
||||||
|
return 'never updated'
|
||||||
|
elif self.last_job_failed:
|
||||||
|
return 'failed'
|
||||||
|
else:
|
||||||
|
return 'successful'
|
||||||
|
|
||||||
|
def _get_last_job_run(self):
|
||||||
|
# Override in subclasses as needed.
|
||||||
|
if self.last_job:
|
||||||
|
return self.last_job.finished
|
||||||
|
|
||||||
|
def _set_status_and_last_job_run(self, save=True):
|
||||||
|
status = self._get_current_status()
|
||||||
|
last_job_run = self._get_last_job_run()
|
||||||
|
# Update values if changed.
|
||||||
|
update_fields = []
|
||||||
|
if self.status != status:
|
||||||
|
self.status = status
|
||||||
|
update_fields.append('status')
|
||||||
|
if self.last_job_run != last_job_run:
|
||||||
|
self.last_job_run = last_job_run
|
||||||
|
update_fields.append('last_job_run')
|
||||||
|
if save and update_fields:
|
||||||
|
self.save(update_fields=update_fields)
|
||||||
|
return update_fields
|
||||||
|
|
||||||
|
def _can_update(self):
|
||||||
|
# Override in subclasses as needed.
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_update(self):
|
||||||
|
return self._can_update()
|
||||||
|
|
||||||
|
def update_signature(self, **kwargs):
|
||||||
|
raise NotImplementedError # Implement in subclass.
|
||||||
|
|
||||||
|
def update(self, **kwargs):
|
||||||
|
raise NotImplementedError # Implement in subclass.
|
||||||
|
|
||||||
|
def _get_child_queryset(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _create_child_instance(self, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UnifiedJob(PolymorphicModel, PrimordialModel):
|
class UnifiedJob(PolymorphicModel, PrimordialModel):
|
||||||
@@ -156,7 +233,6 @@ class UnifiedJob(PolymorphicModel, PrimordialModel):
|
|||||||
editable=False,
|
editable=False,
|
||||||
related_name='%(class)s_blocked_by+',
|
related_name='%(class)s_blocked_by+',
|
||||||
)
|
)
|
||||||
|
|
||||||
cancel_flag = models.BooleanField(
|
cancel_flag = models.BooleanField(
|
||||||
blank=True,
|
blank=True,
|
||||||
default=False,
|
default=False,
|
||||||
@@ -229,4 +305,176 @@ class UnifiedJob(PolymorphicModel, PrimordialModel):
|
|||||||
default='',
|
default='',
|
||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
# FIXME: Add methods from CommonTask.
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u'%s-%s-%s' % (self.created, self.id, self.status)
|
||||||
|
|
||||||
|
def _get_parent_instance(self):
|
||||||
|
return self.job_template
|
||||||
|
|
||||||
|
def _update_parent_instance(self):
|
||||||
|
parent_instance = self._get_parent_instance()
|
||||||
|
if parent_instance:
|
||||||
|
if self.status in ('pending', 'waiting', 'running'):
|
||||||
|
if parent_instance.current_job != self:
|
||||||
|
parent_instance.current_job = self
|
||||||
|
parent_instance.save(update_fields=['current_job'])
|
||||||
|
elif self.status in ('successful', 'failed', 'error', 'canceled'):
|
||||||
|
if parent_instance.current_job == self:
|
||||||
|
parent_instance.current_job = None
|
||||||
|
parent_instance.last_job = self
|
||||||
|
parent_instance.last_job_failed = self.failed
|
||||||
|
parent_instance.save(update_fields=['current_job',
|
||||||
|
'last_job',
|
||||||
|
'last_job_failed'])
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
# If update_fields has been specified, add our field names to it,
|
||||||
|
# if it hasn't been specified, then we're just doing a normal save.
|
||||||
|
update_fields = kwargs.get('update_fields', [])
|
||||||
|
# Get status before save...
|
||||||
|
status_before = self.status or 'new'
|
||||||
|
if self.pk:
|
||||||
|
self_before = self.__class__.objects.get(pk=self.pk)
|
||||||
|
if self_before.status != self.status:
|
||||||
|
status_before = self_before.status
|
||||||
|
failed = bool(self.status in ('failed', 'error', 'canceled'))
|
||||||
|
if self.failed != failed:
|
||||||
|
self.failed = failed
|
||||||
|
if 'failed' not in update_fields:
|
||||||
|
update_fields.append('failed')
|
||||||
|
if self.status == 'running' and not self.started:
|
||||||
|
self.started = now()
|
||||||
|
if 'started' not in update_fields:
|
||||||
|
update_fields.append('started')
|
||||||
|
if self.status in ('successful', 'failed', 'error', 'canceled') and not self.finished:
|
||||||
|
self.finished = now()
|
||||||
|
if 'finished' not in update_fields:
|
||||||
|
update_fields.append('finished')
|
||||||
|
if self.started and self.finished and not self.elapsed:
|
||||||
|
td = self.finished - self.started
|
||||||
|
elapsed = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / (10**6 * 1.0)
|
||||||
|
else:
|
||||||
|
elapsed = 0.0
|
||||||
|
if self.elapsed != elapsed:
|
||||||
|
self.elapsed = elapsed
|
||||||
|
if 'elapsed' not in update_fields:
|
||||||
|
update_fields.append('elapsed')
|
||||||
|
super(UnifiedJob, self).save(*args, **kwargs)
|
||||||
|
# If status changed, update parent instance....
|
||||||
|
if self.status != status_before:
|
||||||
|
self._update_parent_instance()
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
if self.result_stdout_file != "":
|
||||||
|
try:
|
||||||
|
os.remove(self.result_stdout_file)
|
||||||
|
except Exception, e:
|
||||||
|
pass
|
||||||
|
super(UnifiedJob, self).delete()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def result_stdout(self):
|
||||||
|
if self.result_stdout_file != "":
|
||||||
|
if not os.path.exists(self.result_stdout_file):
|
||||||
|
return "stdout capture is missing"
|
||||||
|
stdout_fd = open(self.result_stdout_file, "r")
|
||||||
|
output = stdout_fd.read()
|
||||||
|
stdout_fd.close()
|
||||||
|
return output
|
||||||
|
return self.result_stdout_text
|
||||||
|
|
||||||
|
@property
|
||||||
|
def celery_task(self):
|
||||||
|
try:
|
||||||
|
if self.celery_task_id:
|
||||||
|
return TaskMeta.objects.get(task_id=self.celery_task_id)
|
||||||
|
except TaskMeta.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_start(self):
|
||||||
|
return bool(self.status == 'new')
|
||||||
|
|
||||||
|
def _get_task_class(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _get_passwords_needed_to_start(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def start_signature(self, **kwargs):
|
||||||
|
from awx.main.tasks import handle_work_error
|
||||||
|
|
||||||
|
task_class = self._get_task_class()
|
||||||
|
if not self.can_start:
|
||||||
|
return False
|
||||||
|
needed = self._get_passwords_needed_to_start()
|
||||||
|
opts = dict([(field, kwargs.get(field, '')) for field in needed])
|
||||||
|
if not all(opts.values()):
|
||||||
|
return False
|
||||||
|
self.status = 'pending'
|
||||||
|
self.save(update_fields=['status'])
|
||||||
|
transaction.commit()
|
||||||
|
task_actual = task_class().si(self.pk, **opts)
|
||||||
|
return task_actual
|
||||||
|
|
||||||
|
def start(self, **kwargs):
|
||||||
|
task_actual = self.start_signature(**kwargs)
|
||||||
|
# TODO: Callback for status
|
||||||
|
task_result = task_actual.delay()
|
||||||
|
# Reload instance from database so we don't clobber results from task
|
||||||
|
# (mainly from tests when using Django 1.4.x).
|
||||||
|
instance = self.__class__.objects.get(pk=self.pk)
|
||||||
|
# The TaskMeta instance in the database isn't created until the worker
|
||||||
|
# starts processing the task, so we can only store the task ID here.
|
||||||
|
instance.celery_task_id = task_result.task_id
|
||||||
|
instance.save(update_fields=['celery_task_id'])
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_cancel(self):
|
||||||
|
return bool(self.status in ('pending', 'waiting', 'running'))
|
||||||
|
|
||||||
|
def _force_cancel(self):
|
||||||
|
# Update the status to 'canceled' if we can detect that the job
|
||||||
|
# really isn't running (i.e. celery has crashed or forcefully
|
||||||
|
# killed the worker).
|
||||||
|
task_statuses = ('STARTED', 'SUCCESS', 'FAILED', 'RETRY', 'REVOKED')
|
||||||
|
try:
|
||||||
|
taskmeta = self.celery_task
|
||||||
|
if not taskmeta or taskmeta.status not in task_statuses:
|
||||||
|
return
|
||||||
|
from celery import current_app
|
||||||
|
i = current_app.control.inspect()
|
||||||
|
for v in (i.active() or {}).values():
|
||||||
|
if taskmeta.task_id in [x['id'] for x in v]:
|
||||||
|
return
|
||||||
|
for v in (i.reserved() or {}).values():
|
||||||
|
if taskmeta.task_id in [x['id'] for x in v]:
|
||||||
|
return
|
||||||
|
for v in (i.revoked() or {}).values():
|
||||||
|
if taskmeta.task_id in [x['id'] for x in v]:
|
||||||
|
return
|
||||||
|
for v in (i.scheduled() or {}).values():
|
||||||
|
if taskmeta.task_id in [x['id'] for x in v]:
|
||||||
|
return
|
||||||
|
instance = self.__class__.objects.get(pk=self.pk)
|
||||||
|
if instance.can_cancel:
|
||||||
|
instance.status = 'canceled'
|
||||||
|
update_fields = ['status']
|
||||||
|
if not instance.result_traceback:
|
||||||
|
instance.result_traceback = 'Forced cancel'
|
||||||
|
update_fields.append('result_traceback')
|
||||||
|
instance.save(update_fields=update_fields)
|
||||||
|
except: # FIXME: Log this exception!
|
||||||
|
if settings.DEBUG:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
if self.can_cancel:
|
||||||
|
if not self.cancel_flag:
|
||||||
|
self.cancel_flag = True
|
||||||
|
self.save(update_fields=['cancel_flag'])
|
||||||
|
if settings.BROKER_URL.startswith('amqp://'):
|
||||||
|
self._force_cancel()
|
||||||
|
return self.cancel_flag
|
||||||
|
|||||||
@@ -374,7 +374,16 @@ class BaseTestMixin(object):
|
|||||||
self.check_list_ids(response, qs, check_order)
|
self.check_list_ids(response, qs, check_order)
|
||||||
if fields:
|
if fields:
|
||||||
for obj in response['results']:
|
for obj in response['results']:
|
||||||
self.assertTrue(set(obj.keys()) <= set(fields))
|
returned_fields = set(obj.keys())
|
||||||
|
expected_fields = set(fields)
|
||||||
|
msg = ''
|
||||||
|
not_expected = returned_fields - expected_fields
|
||||||
|
if not_expected:
|
||||||
|
msg += 'fields %s not expected ' % ', '.join(not_expected)
|
||||||
|
not_returned = expected_fields - returned_fields
|
||||||
|
if not_returned:
|
||||||
|
msg += 'fields %s not returned ' % ', '.join(not_returned)
|
||||||
|
self.assertTrue(set(obj.keys()) <= set(fields), msg)
|
||||||
|
|
||||||
def start_taskmanager(self, command_port):
|
def start_taskmanager(self, command_port):
|
||||||
self.taskmanager_process = Process(target=run_taskmanager,
|
self.taskmanager_process = Process(target=run_taskmanager,
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ class BaseJobTestMixin(BaseTestMixin):
|
|||||||
|
|
||||||
class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
|
class JobTemplateTest(BaseJobTestMixin, django.test.TestCase):
|
||||||
|
|
||||||
JOB_TEMPLATE_FIELDS = ('id', 'url', 'related', 'summary_fields', 'created',
|
JOB_TEMPLATE_FIELDS = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
|
||||||
'modified', 'name', 'description', 'job_type',
|
'modified', 'name', 'description', 'job_type',
|
||||||
'inventory', 'project', 'playbook', 'credential',
|
'inventory', 'project', 'playbook', 'credential',
|
||||||
'cloud_credential', 'forks', 'limit', 'verbosity',
|
'cloud_credential', 'forks', 'limit', 'verbosity',
|
||||||
|
|||||||
@@ -1610,7 +1610,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
|
|||||||
self.assertEqual(job.status, 'new')
|
self.assertEqual(job.status, 'new')
|
||||||
self.assertFalse(job.passwords_needed_to_start)
|
self.assertFalse(job.passwords_needed_to_start)
|
||||||
self.assertTrue(job.start())
|
self.assertTrue(job.start())
|
||||||
self.assertEqual(job.status, 'pending')
|
self.assertTrue(job.status in ('pending', 'waiting'), job.status)
|
||||||
job = Job.objects.get(pk=job.pk)
|
job = Job.objects.get(pk=job.pk)
|
||||||
self.assertTrue(job.status in ('successful', 'failed'),
|
self.assertTrue(job.status in ('successful', 'failed'),
|
||||||
job.result_stdout + job.result_traceback)
|
job.result_stdout + job.result_traceback)
|
||||||
@@ -1624,7 +1624,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
|
|||||||
self.assertEqual(job.status, 'new')
|
self.assertEqual(job.status, 'new')
|
||||||
self.assertFalse(job.passwords_needed_to_start)
|
self.assertFalse(job.passwords_needed_to_start)
|
||||||
self.assertTrue(job.start())
|
self.assertTrue(job.start())
|
||||||
self.assertEqual(job.status, 'pending')
|
self.assertTrue(job.status in ('pending', 'waiting'), job.status)
|
||||||
job = Job.objects.get(pk=job.pk)
|
job = Job.objects.get(pk=job.pk)
|
||||||
# FIXME: Not quite sure why the project update still returns successful
|
# FIXME: Not quite sure why the project update still returns successful
|
||||||
# in this case?
|
# in this case?
|
||||||
|
|||||||
@@ -269,8 +269,8 @@ TEST_GIT_USERNAME = ''
|
|||||||
TEST_GIT_PASSWORD = ''
|
TEST_GIT_PASSWORD = ''
|
||||||
TEST_GIT_KEY_DATA = TEST_SSH_KEY_DATA
|
TEST_GIT_KEY_DATA = TEST_SSH_KEY_DATA
|
||||||
TEST_GIT_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com.git'
|
TEST_GIT_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com.git'
|
||||||
TEST_GIT_PRIVATE_HTTPS = 'https://github.com/ansible/ansible-doc.git'
|
TEST_GIT_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs.git'
|
||||||
TEST_GIT_PRIVATE_SSH = 'git@github.com:ansible/ansible-doc.git'
|
TEST_GIT_PRIVATE_SSH = 'git@github.com:ansible/product-docs.git'
|
||||||
|
|
||||||
TEST_HG_USERNAME = ''
|
TEST_HG_USERNAME = ''
|
||||||
TEST_HG_PASSWORD = ''
|
TEST_HG_PASSWORD = ''
|
||||||
@@ -282,7 +282,7 @@ TEST_HG_PRIVATE_SSH = ''
|
|||||||
TEST_SVN_USERNAME = ''
|
TEST_SVN_USERNAME = ''
|
||||||
TEST_SVN_PASSWORD = ''
|
TEST_SVN_PASSWORD = ''
|
||||||
TEST_SVN_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com'
|
TEST_SVN_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com'
|
||||||
TEST_SVN_PRIVATE_HTTPS = 'https://github.com/ansible/ansible-doc'
|
TEST_SVN_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs'
|
||||||
|
|
||||||
# To test repo access via SSH login to localhost.
|
# To test repo access via SSH login to localhost.
|
||||||
import getpass
|
import getpass
|
||||||
|
|||||||
Reference in New Issue
Block a user