mirror of
https://github.com/ansible/awx.git
synced 2026-01-22 23:18:03 -03:30
Merge pull request #2444 from jakemcdermott/fix-2334
add host_status_counts to adhoc commands; fix status display for adhoc commands
This commit is contained in:
commit
3b3ae9f7f5
@ -9,7 +9,7 @@ import operator
|
||||
import re
|
||||
import six
|
||||
import urllib
|
||||
from collections import defaultdict, OrderedDict
|
||||
from collections import OrderedDict
|
||||
from datetime import timedelta
|
||||
|
||||
# OAuth2
|
||||
@ -1477,23 +1477,11 @@ class ProjectUpdateDetailSerializer(ProjectUpdateSerializer):
|
||||
|
||||
def get_host_status_counts(self, obj):
|
||||
try:
|
||||
event_data = obj.project_update_events.only('event_data').get(event='playbook_on_stats').event_data
|
||||
counts = obj.project_update_events.only('event_data').get(event='playbook_on_stats').get_host_status_counts()
|
||||
except ProjectUpdateEvent.DoesNotExist:
|
||||
event_data = {}
|
||||
counts = {}
|
||||
|
||||
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
|
||||
return counts
|
||||
|
||||
|
||||
class ProjectUpdateListSerializer(ProjectUpdateSerializer, UnifiedJobListSerializer):
|
||||
@ -3274,23 +3262,11 @@ class JobDetailSerializer(JobSerializer):
|
||||
|
||||
def get_host_status_counts(self, obj):
|
||||
try:
|
||||
event_data = obj.job_events.only('event_data').get(event='playbook_on_stats').event_data
|
||||
counts = obj.job_events.only('event_data').get(event='playbook_on_stats').get_host_status_counts()
|
||||
except JobEvent.DoesNotExist:
|
||||
event_data = {}
|
||||
counts = {}
|
||||
|
||||
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
|
||||
return counts
|
||||
|
||||
|
||||
class JobCancelSerializer(BaseSerializer):
|
||||
@ -3470,6 +3446,25 @@ class AdHocCommandSerializer(UnifiedJobSerializer):
|
||||
return vars_validate_or_raise(value)
|
||||
|
||||
|
||||
class AdHocCommandDetailSerializer(AdHocCommandSerializer):
|
||||
|
||||
host_status_counts = serializers.SerializerMethodField(
|
||||
help_text=_('A count of hosts uniquely assigned to each status.'),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = AdHocCommand
|
||||
fields = ('*', 'host_status_counts',)
|
||||
|
||||
def get_host_status_counts(self, obj):
|
||||
try:
|
||||
counts = obj.ad_hoc_command_events.only('event_data').get(event='playbook_on_stats').get_host_status_counts()
|
||||
except AdHocCommandEvent.DoesNotExist:
|
||||
counts = {}
|
||||
|
||||
return counts
|
||||
|
||||
|
||||
class AdHocCommandCancelSerializer(AdHocCommandSerializer):
|
||||
|
||||
can_cancel = serializers.BooleanField(read_only=True)
|
||||
|
||||
@ -4569,7 +4569,7 @@ class HostAdHocCommandsList(AdHocCommandList, SubListCreateAPIView):
|
||||
class AdHocCommandDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
|
||||
|
||||
model = AdHocCommand
|
||||
serializer_class = AdHocCommandSerializer
|
||||
serializer_class = AdHocCommandDetailSerializer
|
||||
|
||||
|
||||
class AdHocCommandCancel(RetrieveAPIView):
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import datetime
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models, DatabaseError
|
||||
@ -39,6 +40,21 @@ def sanitize_event_keys(kwargs, valid_keys):
|
||||
kwargs[key] = Truncator(kwargs[key]).chars(1024)
|
||||
|
||||
|
||||
def create_host_status_counts(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 dict(host_status_counts)
|
||||
|
||||
|
||||
class BasePlaybookEvent(CreatedModifiedModel):
|
||||
'''
|
||||
@ -194,6 +210,9 @@ class BasePlaybookEvent(CreatedModifiedModel):
|
||||
def event_level(self):
|
||||
return self.LEVEL_FOR_EVENT.get(self.event, 0)
|
||||
|
||||
def get_host_status_counts(self):
|
||||
return create_host_status_counts(getattr(self, 'event_data', {}))
|
||||
|
||||
def get_event_display2(self):
|
||||
msg = self.get_event_display()
|
||||
if self.event == 'playbook_on_play_start':
|
||||
@ -588,6 +607,9 @@ class BaseCommandEvent(CreatedModifiedModel):
|
||||
'''
|
||||
return self.event
|
||||
|
||||
def get_host_status_counts(self):
|
||||
return create_host_status_counts(getattr(self, 'event_data', {}))
|
||||
|
||||
|
||||
class AdHocCommandEvent(BaseCommandEvent):
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ const TASK_START = 'playbook_on_task_start';
|
||||
const HOST_STATUS_KEYS = ['dark', 'failures', 'changed', 'ok', 'skipped'];
|
||||
const COMPLETE = ['successful', 'failed'];
|
||||
const INCOMPLETE = ['canceled', 'error'];
|
||||
const UNSUCCESSFUL = ['failed'].concat(INCOMPLETE);
|
||||
const FINISHED = COMPLETE.concat(INCOMPLETE);
|
||||
|
||||
function JobStatusService (moment, message) {
|
||||
@ -41,18 +42,17 @@ function JobStatusService (moment, message) {
|
||||
},
|
||||
};
|
||||
|
||||
if (model.get('type') === 'job' || model.get('type') === 'project_update') {
|
||||
if (model.has('playbook_counts')) {
|
||||
this.setPlaybookCounts(model.get('playbook_counts'));
|
||||
}
|
||||
|
||||
if (model.has('host_status_counts')) {
|
||||
this.setHostStatusCounts(model.get('host_status_counts'));
|
||||
}
|
||||
if (model.has('host_status_counts')) {
|
||||
this.setHostStatusCounts(model.get('host_status_counts'));
|
||||
} else {
|
||||
const hostStatusCounts = this.createHostStatusCounts(this.state.status);
|
||||
|
||||
this.setHostStatusCounts(hostStatusCounts);
|
||||
}
|
||||
|
||||
if (model.has('playbook_counts')) {
|
||||
this.setPlaybookCounts(model.get('playbook_counts'));
|
||||
} else {
|
||||
this.setPlaybookCounts({ task_count: 1, play_count: 1 });
|
||||
}
|
||||
|
||||
@ -61,12 +61,12 @@ function JobStatusService (moment, message) {
|
||||
};
|
||||
|
||||
this.createHostStatusCounts = status => {
|
||||
if (_.includes(COMPLETE, status)) {
|
||||
return { ok: 1 };
|
||||
if (UNSUCCESSFUL.includes(status)) {
|
||||
return { failures: 1 };
|
||||
}
|
||||
|
||||
if (_.includes(INCOMPLETE, status)) {
|
||||
return { failures: 1 };
|
||||
if (COMPLETE.includes(status)) {
|
||||
return { ok: 1 };
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -130,14 +130,25 @@ function JobStatusService (moment, message) {
|
||||
};
|
||||
|
||||
this.isExpectingStatsEvent = () => (this.jobType === 'job') ||
|
||||
(this.jobType === 'project_update');
|
||||
(this.jobType === 'project_update') ||
|
||||
(this.jobType === 'ad_hoc_command');
|
||||
|
||||
this.updateStats = () => {
|
||||
this.updateHostCounts();
|
||||
|
||||
if (this.statsEvent) {
|
||||
this.setFinished(this.statsEvent.created);
|
||||
this.setJobStatus(this.statsEvent.failed ? 'failed' : 'successful');
|
||||
|
||||
const failures = _.get(this.statsEvent, ['event_data', 'failures'], {});
|
||||
const dark = _.get(this.statsEvent, ['event_data', 'dark'], {});
|
||||
|
||||
if (this.statsEvent.failed ||
|
||||
Object.keys(failures).length > 0 ||
|
||||
Object.keys(dark).length > 0) {
|
||||
this.setJobStatus('failed');
|
||||
} else {
|
||||
this.setJobStatus('successful');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -173,9 +184,9 @@ function JobStatusService (moment, message) {
|
||||
|
||||
this.setJobStatus = status => {
|
||||
const isExpectingStats = this.isExpectingStatsEvent();
|
||||
const isIncomplete = _.includes(INCOMPLETE, status);
|
||||
const isFinished = _.includes(FINISHED, status);
|
||||
const isAlreadyFinished = _.includes(FINISHED, this.state.status);
|
||||
const isIncomplete = INCOMPLETE.includes(status);
|
||||
const isFinished = FINISHED.includes(status);
|
||||
const isAlreadyFinished = FINISHED.includes(this.state.status);
|
||||
|
||||
if (isAlreadyFinished) {
|
||||
return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user