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:
Jake McDermott 2018-07-09 12:08:25 -04:00 committed by GitHub
commit 3b3ae9f7f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 49 deletions

View File

@ -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)

View File

@ -4569,7 +4569,7 @@ class HostAdHocCommandsList(AdHocCommandList, SubListCreateAPIView):
class AdHocCommandDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
model = AdHocCommand
serializer_class = AdHocCommandSerializer
serializer_class = AdHocCommandDetailSerializer
class AdHocCommandCancel(RetrieveAPIView):

View File

@ -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):

View File

@ -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;