mirror of
https://github.com/ZwareBear/awx.git
synced 2026-05-01 20:31:49 -05:00
Merge branch 'devel' into workflow-channels
This commit is contained in:
@@ -28,14 +28,19 @@ from awx.main.models.channels import * # noqa
|
||||
# the dumpdata command; see https://github.com/alex/django-taggit/issues/155).
|
||||
from django.core.serializers.python import Serializer as _PythonSerializer
|
||||
_original_handle_m2m_field = _PythonSerializer.handle_m2m_field
|
||||
|
||||
|
||||
def _new_handle_m2m_field(self, obj, field):
|
||||
try:
|
||||
field.rel.through._meta
|
||||
except AttributeError:
|
||||
return
|
||||
return _original_handle_m2m_field(self, obj, field)
|
||||
|
||||
|
||||
_PythonSerializer.handle_m2m_field = _new_handle_m2m_field
|
||||
|
||||
|
||||
# Add custom methods to User model for permissions checks.
|
||||
from django.contrib.auth.models import User # noqa
|
||||
from awx.main.access import * # noqa
|
||||
@@ -46,26 +51,32 @@ User.add_to_class('can_access', check_user_access)
|
||||
User.add_to_class('accessible_objects', user_accessible_objects)
|
||||
User.add_to_class('admin_role', user_admin_role)
|
||||
|
||||
|
||||
@property
|
||||
def user_get_organizations(user):
|
||||
return Organization.objects.filter(member_role__members=user)
|
||||
|
||||
|
||||
@property
|
||||
def user_get_admin_of_organizations(user):
|
||||
return Organization.objects.filter(admin_role__members=user)
|
||||
|
||||
|
||||
@property
|
||||
def user_get_auditor_of_organizations(user):
|
||||
return Organization.objects.filter(auditor_role__members=user)
|
||||
|
||||
|
||||
User.add_to_class('organizations', user_get_organizations)
|
||||
User.add_to_class('admin_of_organizations', user_get_admin_of_organizations)
|
||||
User.add_to_class('auditor_of_organizations', user_get_auditor_of_organizations)
|
||||
|
||||
|
||||
@property
|
||||
def user_is_system_auditor(user):
|
||||
return Role.singleton('system_auditor').members.filter(id=user.id).exists()
|
||||
|
||||
|
||||
@user_is_system_auditor.setter
|
||||
def user_is_system_auditor(user, tf):
|
||||
if user.id:
|
||||
@@ -74,6 +85,7 @@ def user_is_system_auditor(user, tf):
|
||||
else:
|
||||
Role.singleton('system_auditor').members.remove(user)
|
||||
|
||||
|
||||
User.add_to_class('is_system_auditor', user_is_system_auditor)
|
||||
|
||||
# Import signal handlers only after models have been defined.
|
||||
|
||||
@@ -17,13 +17,11 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
# Django-JSONField
|
||||
from jsonfield import JSONField
|
||||
|
||||
# AWX
|
||||
from awx.main.models.base import * # noqa
|
||||
from awx.main.models.unified_jobs import * # noqa
|
||||
from awx.main.models.notifications import JobNotificationMixin
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
logger = logging.getLogger('awx.main.models.ad_hoc_commands')
|
||||
|
||||
@@ -211,6 +209,7 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
|
||||
def get_notification_friendly_name(self):
|
||||
return "AdHoc Command"
|
||||
|
||||
|
||||
class AdHocCommandEvent(CreatedModifiedModel):
|
||||
'''
|
||||
An event/message logged from the ad hoc event callback for each host.
|
||||
|
||||
@@ -320,6 +320,7 @@ class CommonModelNameNotUnique(PrimordialModel):
|
||||
unique=False,
|
||||
)
|
||||
|
||||
|
||||
class NotificationFieldsModel(BaseModel):
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class ChannelGroup(models.Model):
|
||||
group = models.CharField(max_length=200, unique=True)
|
||||
channels = models.TextField()
|
||||
|
||||
@@ -8,6 +8,7 @@ from jsonbfield.fields import JSONField
|
||||
|
||||
__all__ = ('Fact', )
|
||||
|
||||
|
||||
class Fact(models.Model):
|
||||
"""A model representing a fact returned from Ansible.
|
||||
Facts are stored as JSON dictionaries.
|
||||
@@ -20,8 +21,8 @@ class Fact(models.Model):
|
||||
help_text=_('Host for the facts that the fact scan captured.'),
|
||||
)
|
||||
timestamp = models.DateTimeField(
|
||||
default=None,
|
||||
editable=False,
|
||||
default=None,
|
||||
editable=False,
|
||||
help_text=_('Date and time of the corresponding fact scan gathering time.')
|
||||
)
|
||||
module = models.CharField(max_length=128)
|
||||
|
||||
@@ -39,9 +39,11 @@ class Instance(models.Model):
|
||||
# NOTE: TODO: Likely to repurpose this once standalone ramparts are a thing
|
||||
return "tower"
|
||||
|
||||
|
||||
class TowerScheduleState(SingletonModel):
|
||||
schedule_last_run = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
|
||||
class JobOrigin(models.Model):
|
||||
"""A model representing the relationship between a unified job and
|
||||
the instance that was responsible for starting that job.
|
||||
|
||||
@@ -21,9 +21,6 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
# Django-JSONField
|
||||
from jsonfield import JSONField
|
||||
|
||||
# AWX
|
||||
from awx.main.constants import CLOUD_PROVIDERS
|
||||
from awx.main.models.base import * # noqa
|
||||
@@ -40,6 +37,7 @@ from awx.main.redact import PlainTextCleaner
|
||||
from awx.main.fields import ImplicitRoleField
|
||||
from awx.main.models.mixins import ResourceMixin, SurveyJobTemplateMixin, SurveyJobMixin
|
||||
from awx.main.models.base import PERM_INVENTORY_SCAN
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
from awx.main.consumers import emit_channel_notification
|
||||
|
||||
@@ -190,6 +188,7 @@ class JobOptions(BaseModel):
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, ResourceMixin):
|
||||
'''
|
||||
A job template is a reusable job definition for applying a project (with
|
||||
@@ -394,6 +393,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
||||
any_notification_templates = set(any_notification_templates + list(base_notification_templates.filter(organization_notification_templates_for_any=self.project.organization)))
|
||||
return dict(error=list(error_notification_templates), success=list(success_notification_templates), any=list(any_notification_templates))
|
||||
|
||||
|
||||
class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin):
|
||||
'''
|
||||
A job applies a project (with playbook) to an inventory source with a given
|
||||
@@ -648,6 +648,7 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin):
|
||||
def get_notification_friendly_name(self):
|
||||
return "Job"
|
||||
|
||||
|
||||
class JobHostSummary(CreatedModifiedModel):
|
||||
'''
|
||||
Per-host statistics for each job.
|
||||
|
||||
@@ -12,6 +12,7 @@ from awx.main.models.unified_jobs import UnifiedJobTemplate, UnifiedJob
|
||||
|
||||
__all__ = ('Label', )
|
||||
|
||||
|
||||
class Label(CommonModelNameNotUnique):
|
||||
'''
|
||||
Generic Tag. Designed for tagging Job Templates, but expandable to other models.
|
||||
@@ -37,7 +38,7 @@ class Label(CommonModelNameNotUnique):
|
||||
return \
|
||||
Label.objects.filter(
|
||||
organization=None,
|
||||
jobtemplate_labels__isnull=True
|
||||
unifiedjobtemplate_labels__isnull=True
|
||||
)
|
||||
|
||||
def is_detached(self):
|
||||
@@ -55,4 +56,3 @@ class Label(CommonModelNameNotUnique):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
@@ -5,17 +5,18 @@ import json
|
||||
from django.db import models
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.auth.models import User # noqa
|
||||
from jsonfield import JSONField
|
||||
|
||||
# AWX
|
||||
from awx.main.models.rbac import (
|
||||
Role, RoleAncestorEntry, get_roles_on_resource
|
||||
)
|
||||
from awx.main.utils import parse_yaml_or_json
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
|
||||
__all__ = ['ResourceMixin', 'SurveyJobTemplateMixin', 'SurveyJobMixin']
|
||||
|
||||
|
||||
class ResourceMixin(models.Model):
|
||||
|
||||
class Meta:
|
||||
@@ -216,4 +217,3 @@ class SurveyJobMixin(models.Model):
|
||||
return json.dumps(extra_vars)
|
||||
else:
|
||||
return self.extra_vars
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@ from awx.main.notifications.pagerduty_backend import PagerDutyBackend
|
||||
from awx.main.notifications.hipchat_backend import HipChatBackend
|
||||
from awx.main.notifications.webhook_backend import WebhookBackend
|
||||
from awx.main.notifications.irc_backend import IrcBackend
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
# Django-JSONField
|
||||
from jsonfield import JSONField
|
||||
|
||||
logger = logging.getLogger('awx.main.models.notifications')
|
||||
|
||||
__all__ = ['NotificationTemplate', 'Notification']
|
||||
|
||||
|
||||
class NotificationTemplate(CommonModel):
|
||||
|
||||
NOTIFICATION_TYPES = [('email', _('Email'), CustomEmailBackend),
|
||||
@@ -117,6 +117,7 @@ class NotificationTemplate(CommonModel):
|
||||
notification_obj = EmailMessage(subject, backend_obj.format_body(body), sender, recipients)
|
||||
return backend_obj.send_messages([notification_obj])
|
||||
|
||||
|
||||
class Notification(CreatedModifiedModel):
|
||||
'''
|
||||
A notification event emitted when a NotificationTemplate is run
|
||||
@@ -172,6 +173,7 @@ class Notification(CreatedModifiedModel):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:notification_detail', args=(self.pk,))
|
||||
|
||||
|
||||
class JobNotificationMixin(object):
|
||||
def get_notification_templates(self):
|
||||
raise RuntimeError("Define me")
|
||||
@@ -194,4 +196,3 @@ class JobNotificationMixin(object):
|
||||
|
||||
def build_notification_failed_message(self):
|
||||
return self._build_notification_message('failed')
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin):
|
||||
return self.name
|
||||
|
||||
|
||||
|
||||
class Team(CommonModelNameNotUnique, ResourceMixin):
|
||||
'''
|
||||
A team is a group of users that work on common projects.
|
||||
@@ -191,6 +190,7 @@ class Profile(CreatedModifiedModel):
|
||||
default='',
|
||||
)
|
||||
|
||||
|
||||
"""
|
||||
Since expiration and session expiration is event driven a token could be
|
||||
invalidated for both reasons. Further, we only support a single reason for a
|
||||
@@ -199,6 +199,8 @@ session token being invalid. For this case, mark the token as expired.
|
||||
Note: Again, because the value of reason is event based. The reason may not be
|
||||
set (i.e. may equal '') even though a session is expired or a limit is reached.
|
||||
"""
|
||||
|
||||
|
||||
class AuthToken(BaseModel):
|
||||
'''
|
||||
Custom authentication tokens per user with expiration and request-specific
|
||||
|
||||
@@ -7,9 +7,6 @@ import os
|
||||
import re
|
||||
import urlparse
|
||||
|
||||
# JSONField
|
||||
from jsonfield import JSONField
|
||||
|
||||
# Django
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
@@ -34,6 +31,7 @@ from awx.main.models.rbac import (
|
||||
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
)
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
__all__ = ['Project', 'ProjectUpdate']
|
||||
|
||||
@@ -393,6 +391,7 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:project_detail', args=(self.pk,))
|
||||
|
||||
|
||||
class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin):
|
||||
'''
|
||||
Internal job for tracking project updates from SCM.
|
||||
|
||||
@@ -79,6 +79,7 @@ def check_singleton(func):
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def batch_role_ancestor_rebuilding(allow_nesting=False):
|
||||
'''
|
||||
@@ -426,6 +427,7 @@ class Role(models.Model):
|
||||
def is_ancestor_of(self, role):
|
||||
return role.ancestors.filter(id=self.id).exists()
|
||||
|
||||
|
||||
class RoleAncestorEntry(models.Model):
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -11,14 +11,12 @@ from django.db import models
|
||||
from django.db.models.query import QuerySet
|
||||
from django.utils.timezone import now, make_aware, get_default_timezone
|
||||
|
||||
# Django-JSONField
|
||||
from jsonfield import JSONField
|
||||
|
||||
# AWX
|
||||
from awx.main.models.base import * # noqa
|
||||
from awx.main.utils import ignore_inventory_computed_fields
|
||||
from awx.main.consumers import emit_channel_notification
|
||||
from django.core.urlresolvers import reverse
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
logger = logging.getLogger('awx.main.models.schedule')
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@ from django.utils.timezone import now
|
||||
from django.utils.encoding import smart_text
|
||||
from django.apps import apps
|
||||
|
||||
# Django-JSONField
|
||||
from jsonfield import JSONField
|
||||
|
||||
# Django-Polymorphic
|
||||
from polymorphic import PolymorphicModel
|
||||
|
||||
@@ -35,6 +32,7 @@ from awx.main.models.schedules import Schedule
|
||||
from awx.main.utils import decrypt_field, _inventory_updates
|
||||
from awx.main.redact import UriCleaner, REPLACE_STR
|
||||
from awx.main.consumers import emit_channel_notification
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
__all__ = ['UnifiedJobTemplate', 'UnifiedJob']
|
||||
|
||||
@@ -358,6 +356,7 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
|
||||
dest_field.add(*list(src_field_value.all().values_list('id', flat=True)))
|
||||
return unified_job
|
||||
|
||||
|
||||
class UnifiedJobTypeStringMixin(object):
|
||||
@classmethod
|
||||
def _underscore_to_camel(cls, word):
|
||||
@@ -381,6 +380,7 @@ class UnifiedJobTypeStringMixin(object):
|
||||
return None
|
||||
return model.objects.get(id=job_id)
|
||||
|
||||
|
||||
class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique, UnifiedJobTypeStringMixin):
|
||||
'''
|
||||
Concrete base class for unified job run by the task engine.
|
||||
|
||||
@@ -9,8 +9,6 @@ from django.db import models
|
||||
from django.core.urlresolvers import reverse
|
||||
#from django import settings as tower_settings
|
||||
|
||||
from jsonfield import JSONField
|
||||
|
||||
# AWX
|
||||
from awx.main.models import UnifiedJobTemplate, UnifiedJob
|
||||
from awx.main.models.notifications import (
|
||||
@@ -26,6 +24,7 @@ from awx.main.fields import ImplicitRoleField
|
||||
from awx.main.models.mixins import ResourceMixin, SurveyJobTemplateMixin, SurveyJobMixin
|
||||
from awx.main.redact import REPLACE_STR
|
||||
from awx.main.utils import parse_yaml_or_json
|
||||
from awx.main.fields import JSONField
|
||||
|
||||
from copy import copy
|
||||
|
||||
@@ -33,6 +32,7 @@ __all__ = ['WorkflowJobTemplate', 'WorkflowJob', 'WorkflowJobOptions', 'Workflow
|
||||
|
||||
CHAR_PROMPTS_LIST = ['job_type', 'job_tags', 'skip_tags', 'limit']
|
||||
|
||||
|
||||
class WorkflowNodeBase(CreatedModifiedModel):
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -159,6 +159,7 @@ class WorkflowNodeBase(CreatedModifiedModel):
|
||||
return ['workflow_job', 'unified_job_template',
|
||||
'inventory', 'credential', 'char_prompts']
|
||||
|
||||
|
||||
class WorkflowJobTemplateNode(WorkflowNodeBase):
|
||||
workflow_job_template = models.ForeignKey(
|
||||
'WorkflowJobTemplate',
|
||||
@@ -184,6 +185,7 @@ class WorkflowJobTemplateNode(WorkflowNodeBase):
|
||||
create_kwargs[field_name] = getattr(self, field_name)
|
||||
return WorkflowJobNode.objects.create(**create_kwargs)
|
||||
|
||||
|
||||
class WorkflowJobNode(WorkflowNodeBase):
|
||||
job = models.OneToOneField(
|
||||
'UnifiedJob',
|
||||
@@ -206,7 +208,7 @@ class WorkflowJobNode(WorkflowNodeBase):
|
||||
default={},
|
||||
editable=False,
|
||||
)
|
||||
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:workflow_job_node_detail', args=(self.pk,))
|
||||
|
||||
@@ -260,6 +262,7 @@ class WorkflowJobNode(WorkflowNodeBase):
|
||||
data['launch_type'] = 'workflow'
|
||||
return data
|
||||
|
||||
|
||||
class WorkflowJobOptions(BaseModel):
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -271,8 +274,8 @@ class WorkflowJobOptions(BaseModel):
|
||||
|
||||
extra_vars_dict = VarsDictProperty('extra_vars', True)
|
||||
|
||||
class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTemplateMixin, ResourceMixin):
|
||||
|
||||
class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTemplateMixin, ResourceMixin):
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
|
||||
@@ -374,6 +377,7 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl
|
||||
warning_data[node.pk] = node_prompts_warnings
|
||||
return warning_data
|
||||
|
||||
|
||||
class WorkflowJobInheritNodesMixin(object):
|
||||
def _inherit_relationship(self, old_node, new_node, node_ids_map, node_type):
|
||||
old_related_nodes = self._get_all_by_type(old_node, node_type)
|
||||
@@ -415,10 +419,9 @@ class WorkflowJobInheritNodesMixin(object):
|
||||
new_node = new_nodes[index]
|
||||
for node_type in ['success_nodes', 'failure_nodes', 'always_nodes']:
|
||||
self._inherit_relationship(old_node, new_node, node_ids_map, node_type)
|
||||
|
||||
|
||||
|
||||
class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificationMixin, WorkflowJobInheritNodesMixin):
|
||||
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
ordering = ('id',)
|
||||
|
||||
Reference in New Issue
Block a user