1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

Merge pull request #3893 from AlanCoding/replace_job_origin

Replace JobOrigin model with ActivityStream.action_node field

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
softwarefactory-project-zuul[bot] 2019-05-31 11:59:09 +00:00 committed by GitHub
commit d7c33a7246
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 71 additions and 50 deletions

View File

@ -4984,7 +4984,7 @@ class ActivityStreamSerializer(BaseSerializer):
class Meta:
model = ActivityStream
fields = ('*', '-name', '-description', '-created', '-modified', 'timestamp', 'operation',
'changes', 'object1', 'object2', 'object_association', 'object_type')
'changes', 'object1', 'object2', 'object_association', 'action_node', 'object_type')
def get_fields(self):
ret = super(ActivityStreamSerializer, self).get_fields()

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-14 14:51
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0079_v360_rm_implicit_oauth2_apps'),
]
operations = [
migrations.RemoveField(
model_name='joborigin',
name='instance',
),
migrations.RemoveField(
model_name='joborigin',
name='unified_job',
),
migrations.AddField(
model_name='activitystream',
name='action_node',
field=models.CharField(blank=True, default='', editable=False, help_text='The cluster node the activity took place on.', max_length=512),
),
migrations.DeleteModel(
name='JobOrigin',
),
]

View File

@ -35,7 +35,7 @@ from awx.main.models.ad_hoc_commands import AdHocCommand # noqa
from awx.main.models.schedules import Schedule # noqa
from awx.main.models.activity_stream import ActivityStream # noqa
from awx.main.models.ha import ( # noqa
Instance, InstanceGroup, JobOrigin, TowerScheduleState,
Instance, InstanceGroup, TowerScheduleState,
)
from awx.main.models.rbac import ( # noqa
Role, batch_role_ancestor_rebuilding, get_roles_on_resource,

View File

@ -7,6 +7,7 @@ from awx.main.fields import JSONField
# Django
from django.db import models
from django.conf import settings
from django.utils.encoding import smart_str
from django.utils.translation import ugettext_lazy as _
@ -35,6 +36,13 @@ class ActivityStream(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
changes = models.TextField(blank=True)
deleted_actor = JSONField(null=True)
action_node = models.CharField(
blank=True,
default='',
editable=False,
max_length=512,
help_text=_("The cluster node the activity took place on."),
)
object_relationship_type = models.TextField(blank=True)
object1 = models.TextField()
@ -78,7 +86,13 @@ class ActivityStream(models.Model):
def __str__(self):
operation = self.operation if 'operation' in self.__dict__ else '_delayed_'
timestamp = self.timestamp.isoformat() if 'timestamp' in self.__dict__ else '_delayed_'
if 'timestamp' in self.__dict__:
if self.timestamp:
timestamp = self.timestamp.isoformat()
else:
timestamp = self.timestamp
else:
timestamp = '_delayed_'
return u'%s-%s-pk=%s' % (operation, timestamp, self.pk)
def get_absolute_url(self, request=None):
@ -97,4 +111,7 @@ class ActivityStream(models.Model):
if 'update_fields' in kwargs and 'deleted_actor' not in kwargs['update_fields']:
kwargs['update_fields'].append('deleted_actor')
hostname_char_limit = self._meta.get_field('action_node').max_length
self.action_node = settings.CLUSTER_HOST_ID[:hostname_char_limit]
super(ActivityStream, self).save(*args, **kwargs)

View File

@ -19,14 +19,11 @@ from awx.api.versioning import reverse
from awx.main.managers import InstanceManager, InstanceGroupManager
from awx.main.fields import JSONField
from awx.main.models.base import BaseModel, HasEditsMixin
from awx.main.models.inventory import InventoryUpdate
from awx.main.models.jobs import Job
from awx.main.models.projects import ProjectUpdate
from awx.main.models.unified_jobs import UnifiedJob
from awx.main.utils import get_cpu_capacity, get_mem_capacity, get_system_task_capacity
from awx.main.models.mixins import RelatedJobsMixin
__all__ = ('Instance', 'InstanceGroup', 'JobOrigin', 'TowerScheduleState', 'TowerAnalyticsState')
__all__ = ('Instance', 'InstanceGroup', 'TowerScheduleState', 'TowerAnalyticsState')
class HasPolicyEditsMixin(HasEditsMixin):
@ -266,24 +263,6 @@ class TowerAnalyticsState(SingletonModel):
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.
It may be possible that a job has no origin (the common reason for this
being that the job was started on Tower < 2.1 before origins were a thing).
This is fine, and code should be able to handle it. A job with no origin
is always assumed to *not* have the current instance as its origin.
"""
unified_job = models.OneToOneField(UnifiedJob, related_name='job_origin', on_delete=models.CASCADE)
instance = models.ForeignKey(Instance, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
app_label = 'main'
def schedule_policy_task():
from awx.main.tasks import apply_cluster_membership_policies
connection.on_commit(lambda: apply_cluster_membership_policies.apply_async())
@ -311,31 +290,6 @@ def on_instance_deleted(sender, instance, using, **kwargs):
schedule_policy_task()
# Unfortunately, the signal can't just be connected against UnifiedJob; it
# turns out that creating a model's subclass doesn't fire the signal for the
# superclass model.
@receiver(post_save, sender=InventoryUpdate)
@receiver(post_save, sender=Job)
@receiver(post_save, sender=ProjectUpdate)
def on_job_create(sender, instance, created=False, raw=False, **kwargs):
"""When a new job is created, save a record of its origin (the machine
that started the job).
"""
# Sanity check: We only want to create a JobOrigin record in cases where
# we are making a new record, and in normal situations.
#
# In other situations, we simply do nothing.
if raw or not created:
return
# Create the JobOrigin record, which attaches to the current instance
# (which started the job).
job_origin, new = JobOrigin.objects.get_or_create(
instance=Instance.objects.me(),
unified_job=instance,
)
class UnifiedJobTemplateInstanceGroupMembership(models.Model):
unifiedjobtemplate = models.ForeignKey(

View File

@ -277,3 +277,22 @@ def test_saved_passwords_hidden_activity(workflow_job_template, job_template_wit
changes = json.loads(entry.changes)
assert 'survey_passwords' not in changes
assert json.loads(changes['extra_data'])['bbbb'] == '$encrypted$'
@pytest.mark.django_db
def test_cluster_node_recorded(inventory, project):
jt = JobTemplate.objects.create(name='testjt', inventory=inventory, project=project)
with mock.patch('awx.main.models.activity_stream.settings.CLUSTER_HOST_ID', 'foo_host'):
job = jt.create_unified_job()
entry = ActivityStream.objects.filter(job=job).first()
assert entry.action_node == 'foo_host'
@pytest.mark.django_db
def test_cluster_node_long_node_name(inventory, project):
jt = JobTemplate.objects.create(name='testjt', inventory=inventory, project=project)
with mock.patch('awx.main.models.activity_stream.settings.CLUSTER_HOST_ID', 'f' * 700):
job = jt.create_unified_job()
# node name is very long, we just want to make sure it does not error
entry = ActivityStream.objects.filter(job=job).first()
assert entry.action_node.startswith('ffffff')