mirror of
https://github.com/ansible/awx.git
synced 2026-03-21 19:07:39 -02:30
add host_status_counts and playbook_counts to project update details
This commit is contained in:
@@ -1419,6 +1419,48 @@ class ProjectUpdateSerializer(UnifiedJobSerializer, ProjectOptionsSerializer):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectUpdateDetailSerializer(ProjectUpdateSerializer):
|
||||||
|
|
||||||
|
host_status_counts = serializers.SerializerMethodField(
|
||||||
|
help_text=_('A count of hosts uniquely assigned to each status.'),
|
||||||
|
)
|
||||||
|
playbook_counts = serializers.SerializerMethodField(
|
||||||
|
help_text=_('A count of all plays and tasks for the job run.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ProjectUpdate
|
||||||
|
fields = ('*', 'host_status_counts', 'playbook_counts',)
|
||||||
|
|
||||||
|
def get_playbook_counts(self, obj):
|
||||||
|
task_count = obj.project_update_events.filter(event='playbook_on_task_start').count()
|
||||||
|
play_count = obj.project_update_events.filter(event='playbook_on_play_start').count()
|
||||||
|
|
||||||
|
data = {'play_count': play_count, 'task_count': task_count}
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_host_status_counts(self, obj):
|
||||||
|
try:
|
||||||
|
event_data = obj.project_update_events.only('event_data').get(event='playbook_on_stats').event_data
|
||||||
|
except ProjectUpdateEvent.DoesNotExist:
|
||||||
|
event_data = {}
|
||||||
|
|
||||||
|
host_status = {}
|
||||||
|
host_status_keys = ['skipped', 'ok', 'changed', 'failures', 'dark']
|
||||||
|
|
||||||
|
for key in host_status_keys:
|
||||||
|
for host in event_data.get(key, {}):
|
||||||
|
host_status[host] = key
|
||||||
|
|
||||||
|
host_status_counts = defaultdict(lambda: 0)
|
||||||
|
|
||||||
|
for value in host_status.values():
|
||||||
|
host_status_counts[value] += 1
|
||||||
|
|
||||||
|
return host_status_counts
|
||||||
|
|
||||||
|
|
||||||
class ProjectUpdateListSerializer(ProjectUpdateSerializer, UnifiedJobListSerializer):
|
class ProjectUpdateListSerializer(ProjectUpdateSerializer, UnifiedJobListSerializer):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1416,7 +1416,7 @@ class ProjectUpdateList(ListAPIView):
|
|||||||
class ProjectUpdateDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
|
class ProjectUpdateDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
|
||||||
|
|
||||||
model = ProjectUpdate
|
model = ProjectUpdate
|
||||||
serializer_class = ProjectUpdateSerializer
|
serializer_class = ProjectUpdateDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
class ProjectUpdateEventsList(SubListAPIView):
|
class ProjectUpdateEventsList(SubListAPIView):
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ from awx.api.serializers import (
|
|||||||
JobDetailSerializer,
|
JobDetailSerializer,
|
||||||
JobSerializer,
|
JobSerializer,
|
||||||
JobOptionsSerializer,
|
JobOptionsSerializer,
|
||||||
|
ProjectUpdateDetailSerializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
Label,
|
Label,
|
||||||
Job,
|
Job,
|
||||||
JobEvent,
|
JobEvent,
|
||||||
|
ProjectUpdateEvent,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -142,10 +144,52 @@ class TestJobDetailSerializerGetHostStatusCountFields(object):
|
|||||||
|
|
||||||
assert host_status_counts == {'ok': 1, 'changed': 1, 'dark': 2}
|
assert host_status_counts == {'ok': 1, 'changed': 1, 'dark': 2}
|
||||||
|
|
||||||
def test_host_status_counts_is_empty_dict_without_stats_event(self, job, mocker):
|
def test_host_status_counts_is_empty_dict_without_stats_event(self, job):
|
||||||
job.job_events = JobEvent.objects.none()
|
job.job_events = JobEvent.objects.none()
|
||||||
|
|
||||||
serializer = JobDetailSerializer()
|
serializer = JobDetailSerializer()
|
||||||
host_status_counts = serializer.get_host_status_counts(job)
|
host_status_counts = serializer.get_host_status_counts(job)
|
||||||
|
|
||||||
assert host_status_counts == {}
|
assert host_status_counts == {}
|
||||||
|
|
||||||
|
|
||||||
|
class TestProjectUpdateDetailSerializerGetHostStatusCountFields(object):
|
||||||
|
|
||||||
|
def test_hosts_are_counted_once(self, project_update, mocker):
|
||||||
|
mock_event = ProjectUpdateEvent(**{
|
||||||
|
'event': 'playbook_on_stats',
|
||||||
|
'event_data': {
|
||||||
|
'skipped': {
|
||||||
|
'localhost': 2,
|
||||||
|
'fiz': 1,
|
||||||
|
},
|
||||||
|
'ok': {
|
||||||
|
'localhost': 1,
|
||||||
|
'foo': 2,
|
||||||
|
},
|
||||||
|
'changed': {
|
||||||
|
'localhost': 1,
|
||||||
|
'bar': 3,
|
||||||
|
},
|
||||||
|
'dark': {
|
||||||
|
'localhost': 2,
|
||||||
|
'fiz': 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mock_qs = namedtuple('mock_qs', ['get'])(mocker.MagicMock(return_value=mock_event))
|
||||||
|
project_update.project_update_events.only = mocker.MagicMock(return_value=mock_qs)
|
||||||
|
|
||||||
|
serializer = ProjectUpdateDetailSerializer()
|
||||||
|
host_status_counts = serializer.get_host_status_counts(project_update)
|
||||||
|
|
||||||
|
assert host_status_counts == {'ok': 1, 'changed': 1, 'dark': 2}
|
||||||
|
|
||||||
|
def test_host_status_counts_is_empty_dict_without_stats_event(self, project_update):
|
||||||
|
project_update.project_update_events = ProjectUpdateEvent.objects.none()
|
||||||
|
|
||||||
|
serializer = ProjectUpdateDetailSerializer()
|
||||||
|
host_status_counts = serializer.get_host_status_counts(project_update)
|
||||||
|
|
||||||
|
assert host_status_counts == {}
|
||||||
|
|||||||
Reference in New Issue
Block a user