extend JobDetailService to process job_event host results, resolves #1410

This commit is contained in:
Leigh Johnson
2016-04-06 15:00:54 -04:00
parent 6150addc2e
commit a8eaf8cd9c
8 changed files with 359 additions and 316 deletions

View File

@@ -822,7 +822,6 @@ export default
url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : ''; url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : '';
url += (scope.search_task_status === 'failed') ? '&failed=true' : ''; url += (scope.search_task_status === 'failed') ? '&failed=true' : '';
url += '&page_size=' + scope.tasksMaxRows + '&order=id'; url += '&page_size=' + scope.tasksMaxRows + '&order=id';
scope.plays.every(function(p, idx) { scope.plays.every(function(p, idx) {
if (p.id === scope.selectedPlay) { if (p.id === scope.selectedPlay) {
play = scope.plays[idx]; play = scope.plays[idx];
@@ -931,7 +930,7 @@ export default
}]) }])
// Call when the selected task needs to change // Call when the selected task needs to change
.factory('SelectTask', ['LoadHosts', function(LoadHosts) { .factory('SelectTask', ['LoadHosts', 'JobDetailService', function(LoadHosts, JobDetailService) {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
id = params.id, id = params.id,
@@ -946,11 +945,16 @@ export default
scope.tasks[idx].taskActiveClass = ''; scope.tasks[idx].taskActiveClass = '';
} }
}); });
// /api/v1/jobs/16/job_events/?parent=832&event__startswith=runner&page_size=200&order=host_name,counte
LoadHosts({ var params = {
scope: scope, parent: scope.selectedTask,
callback: callback, event__startswith: 'runner',
clear: true page_size: scope.hostResultsMaxRows,
order: 'host_name,counter',
};
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
scope.hostResults = JobDetailService.processHostResults(res.results)
scope.hostResultsLoading = false;
}); });
}; };
}]) }])
@@ -960,8 +964,7 @@ export default
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
callback = params.callback, callback = params.callback,
url; url;
scope.hostResults = []; scope.hostResults = [];
if (scope.selectedTask) { if (scope.selectedTask) {
@@ -970,6 +973,7 @@ export default
url += (scope.search_host_name) ? 'host__name__icontains=' + scope.search_host_name + '&' : ''; url += (scope.search_host_name) ? 'host__name__icontains=' + scope.search_host_name + '&' : '';
url += (scope.search_host_status === 'failed') ? 'failed=true&' : ''; url += (scope.search_host_status === 'failed') ? 'failed=true&' : '';
url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order=host_name,counter'; url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order=host_name,counter';
console.log(url)
scope.hostResultsLoading = true; scope.hostResultsLoading = true;
Rest.setUrl(url); Rest.setUrl(url);
Rest.get() Rest.get()
@@ -1020,7 +1024,6 @@ export default
msg = event.event_data.res; msg = event.event_data.res;
} }
} }
if (event.event !== "runner_on_no_hosts") { if (event.event !== "runner_on_no_hosts") {
scope.hostResults.push({ scope.hostResults.push({
id: event.id, id: event.id,
@@ -1037,7 +1040,6 @@ export default
}); });
scope.hostResultsLoading = false; scope.hostResultsLoading = false;
if (callback) { if (callback) {
scope.$emit(callback); scope.$emit(callback);
} }

View File

@@ -1,49 +1,49 @@
<div class="HostEvent-details--left"> <div class="HostEvent-details--left">
<div class="HostEvent-field"> <div class="HostEvent-field">
<div class="HostEvent-title">EVENT</div> <div class="HostEvent-title">EVENT</div>
<span class="HostEvent-field--content"></span> <span class="HostEvent-field--content"></span>
</div> </div>
<div class="HostEvent-field"> <div class="HostEvent-field">
<span class="HostEvent-field--label">HOST</span> <span class="HostEvent-field--label">HOST</span>
<span class="HostEvent-field--content"> <span class="HostEvent-field--content">
<a ui-sref="jobDetail.host-events({hostName: event.host_name})">{{event.host_name || "No result found"}}</a></span> <a ui-sref="jobDetail.host-events({hostName: event.host_name})">{{event.host_name || "No result found"}}</a></span>
</div> </div>
<div class="HostEvent-field"> <div class="HostEvent-field">
<span class="HostEvent-field--label">STATUS</span> <span class="HostEvent-field--label">STATUS</span>
<span class="HostEvent-field--content"> <span class="HostEvent-field--content">
<a class="HostEvents-status"> <a class="HostEvents-status">
<i class="fa fa-circle" ng-class="processEventStatus"></i> <i class="fa fa-circle" ng-class="processEventStatus(event).class"></i>
</a> </a>
{{event.status || "No result found"}} {{processEventStatus(event).status || "No result found"}}
</span> </span>
</div> </div>
<div class="HostEvent-field"> <div class="HostEvent-field">
<span class="HostEvent-field--label">ID</span> <span class="HostEvent-field--label">ID</span>
<span class="HostEvent-field--content">{{event.id || "No result found"}}</span> <span class="HostEvent-field--content">{{event.id || "No result found"}}</span>
</div> </div>
<div class="HostEvent-field"> <div class="HostEvent-field">
<span class="HostEvent-field--label">CREATED</span> <span class="HostEvent-field--label">CREATED</span>
<span class="HostEvent-field--content">{{event.created || "No result found"}}</span> <span class="HostEvent-field--content">{{event.created || "No result found"}}</span>
</div> </div>
<div class="HostEvent-field"> <div class="HostEvent-field">
<span class="HostEvent-field--label">PLAY</span> <span class="HostEvent-field--label">PLAY</span>
<span class="HostEvent-field--content">{{event.play || "No result found"}}</span> <span class="HostEvent-field--content">{{event.play || "No result found"}}</span>
</div> </div>
<div class="HostEvent-field"> <div class="HostEvent-field">
<span class="HostEvent-field--label">TASK</span> <span class="HostEvent-field--label">TASK</span>
<span class="HostEvent-field--content">{{event.task || "No result found"}}</span> <span class="HostEvent-field--content">{{event.task || "No result found"}}</span>
</div> </div>
<div class="HostEvent-field"> <div class="HostEvent-field">
<span class="HostEvent-field--label">MODULE</span> <span class="HostEvent-field--label">MODULE</span>
<span class="HostEvent-field--content">{{event.event_data.res.invocation.module_name || "No result found"}}</span> <span class="HostEvent-field--content">{{event.event_data.res.invocation.module_name || "No result found"}}</span>
</div> </div>
</div> </div>
<div class="HostEvent-details--right" ng-show="event.event_data.res"> <div class="HostEvent-details--right" ng-show="event.event_data.res">
<div class="HostEvent-title">RESULTS</div> <div class="HostEvent-title">RESULTS</div>
<!-- discard any objects in the ansible response until we decide to flatten them --> <!-- discard any objects in the ansible response until we decide to flatten them -->
<div class="HostEvent-field" ng-repeat="(key, value) in results = event.event_data.res track by $index" ng-if="processResults(value)"> <div class="HostEvent-field" ng-repeat="(key, value) in results = event.event_data.res track by $index" ng-if="processResults(value)">
<span class="HostEvent-field--label">{{key}}</span> <span class="HostEvent-field--label">{{key}}</span>
<span class="HostEvent-field--content">{{value}}</span> <span class="HostEvent-field--content">{{value}}</span>
</div> </div>
</div> </div>

View File

@@ -14,8 +14,7 @@
<!-- view navigation buttons --> <!-- view navigation buttons -->
<button ui-sref="jobDetail.host-event.details" type="button" class="btn btn-sm btn-default" >Details</button> <button ui-sref="jobDetail.host-event.details" type="button" class="btn btn-sm btn-default" >Details</button>
<button ui-sref="jobDetail.host-event.json" type="button" class="btn btn-sm btn-default ">JSON</button> <button ui-sref="jobDetail.host-event.json" type="button" class="btn btn-sm btn-default ">JSON</button>
<button ng-show="event.stdout" ui-sref="jobDetail.host-event.stdout" type="button" class="btn btn-sm btn-default ">Standard Out</button> <button ng-show="stdout" ui-sref="jobDetail.host-event.stdout" type="button" class="btn btn-sm btn-default ">Standard Out</button>
<button ng-show="event.timing" ui-sref="jobDetail.host-event.timing" type="button" class="btn btn-sm btn-default ">Timing</button>
</div> </div>
<div class="HostEvent-body"> <div class="HostEvent-body">

View File

@@ -1,13 +1,2 @@
<div class="EventHost-stdoutPanel Panel"> <textarea id="HostEvent-stdout" class="HostEvent-stdout">
<div class="StandardOut-panelHeader"> </textarea>
<div class="StandardOut-panelHeaderText">STANDARD OUT</div>
<div class="StandardOut-panelHeaderActions">
<a href="/api/v1/jobs/{{ job.id }}/stdout?format=txt_download&token={{ token }}">
<button class="StandardOut-actionButton" aw-tool-tip="Download Output" data-placement="top">
<i class="fa fa-download"></i>
</button>
</a>
</div>
</div>
<standard-out-log stdout-endpoint="event._stdout"></standard-out-log>
</div>

View File

@@ -4,68 +4,78 @@
* All Rights Reserved * All Rights Reserved
*************************************************/ *************************************************/
export default export default
['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'moment', 'event', ['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'moment', 'event',
function($stateParams, $scope, $state, Wait, JobDetailService, moment, event){ function($stateParams, $scope, $state, Wait, JobDetailService, moment, event){
// Avoid rendering objects in the details fieldset
// ng-if="processResults(value)" via host-event-details.partial.html
$scope.processResults = function(value){
if (typeof value == 'object'){return false}
else {return true}
};
var codeMirror = function(){ $scope.processEventStatus = JobDetailService.processEventStatus;
var el = $('#HostEvent-json')[0]; // Avoid rendering objects in the details fieldset
var editor = CodeMirror.fromTextArea(el, { // ng-if="processResults(value)" via host-event-details.partial.html
lineNumbers: true, $scope.processResults = function(value){
mode: {name: "javascript", json: true} if (typeof value == 'object'){return false;}
}); else {return true;}
editor.getDoc().setValue(JSON.stringify($scope.json, null, 4)); };
};
$scope.getActiveHostIndex = function(){ var codeMirror = function(el, json){
var result = $scope.hostResults.filter(function( obj ) { var el = $(el)[0];
return obj.id == $scope.event.id; var editor = CodeMirror.fromTextArea(el, {
}); lineNumbers: true,
return $scope.hostResults.indexOf(result[0]) mode: {name: "javascript", json: true}
}; });
editor.getDoc().setValue(JSON.stringify(json, null, 4));
};
$scope.showPrev = function(){ $scope.getActiveHostIndex = function(){
return $scope.getActiveHostIndex() != 0 var result = $scope.hostResults.filter(function( obj ) {
}; return obj.id == $scope.event.id;
});
return $scope.hostResults.indexOf(result[0]);
};
$scope.showNext = function(){ $scope.showPrev = function(){
return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1]) return $scope.getActiveHostIndex() != 0;
}; };
$scope.goNext = function(){ $scope.showNext = function(){
var index = $scope.getActiveHostIndex() + 1; return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1]);
var id = $scope.hostResults[index].id; };
$state.go('jobDetail.host-event.details', {eventId: id})
};
$scope.goPrev = function(){ $scope.goNext = function(){
var index = $scope.getActiveHostIndex() - 1; var index = $scope.getActiveHostIndex() + 1;
var id = $scope.hostResults[index].id; var id = $scope.hostResults[index].id;
$state.go('jobDetail.host-event.details', {eventId: id}) $state.go('jobDetail.host-event.details', {eventId: id});
}; };
var init = function(){ $scope.goPrev = function(){
$scope.event = event.data.results[0]; var index = $scope.getActiveHostIndex() - 1;
$scope.event.created = moment($scope.event.created).format(); var id = $scope.hostResults[index].id;
$scope.processEventStatus = JobDetailService.processEventStatus($scope.event); $state.go('jobDetail.host-event.details', {eventId: id});
$scope.hostResults = $stateParams.hostResults; };
$scope.json = JobDetailService.processJson($scope.event);
if ($state.current.name == 'jobDetail.host-event.json'){ var init = function(){
codeMirror(); console.log(event)
} $scope.event = event.data.results[0];
try { $scope.event.created = moment($scope.event.created).format();
$scope.stdout = $scope.event.event_data.res.stdout $scope.hostResults = $stateParams.hostResults;
} $scope.json = JobDetailService.processJson($scope.event);
catch(err){ if ($state.current.name == 'jobDetail.host-event.json'){
$scope.sdout = null; codeMirror('#HostEvent-json', $scope.json);
} }
$('#HostEvent').modal('show'); try {
}; $scope.stdout = JobDetailService.processJson($scope.event.event_data.res)
init(); console.log($scope.stdout)
}]; if ($state.current.name == 'jobDetail.host-event.stdout'){
codeMirror('#HostEvent-stdout', $scope.stdout);
}
}
catch(err){
$scope.sdout = null;
}
console.log($scope)
$('#HostEvent').modal('show');
};
init();
}];

View File

@@ -36,9 +36,9 @@
<td class=HostEvents-table--cell> <td class=HostEvents-table--cell>
<!-- status circles --> <!-- status circles -->
<a class="HostEvents-status"> <a class="HostEvents-status">
<i class="fa fa-circle" ng-class="processEventStatus(event)"></i> <i class="fa fa-circle" ng-class="processEventStatus(event).class"></i>
</a> </a>
{{event.status}} {{processEventStatus(event).status}}
</td> </td>
<td class=HostEvents-table--cell>{{event.play}}</td> <td class=HostEvents-table--cell>{{event.play}}</td>
<td class=HostEvents-table--cell>{{event.task}}</td> <td class=HostEvents-table--cell>{{event.task}}</td>

View File

@@ -16,7 +16,7 @@ export default
'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed',
'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList', 'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList',
'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun', 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun',
'LoadPlays', 'LoadTasks', 'LoadHosts', 'HostsEdit', 'LoadPlays', 'LoadTasks', 'HostsEdit',
'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels', 'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels',
'EditSchedule', 'ParseTypeChange', 'JobDetailService', 'EditSchedule', 'ParseTypeChange', 'JobDetailService',
function( function(
@@ -25,7 +25,7 @@ export default
SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph, SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph,
LoadHostSummary, ReloadHostSummaryList, JobIsFinished, LoadHostSummary, ReloadHostSummaryList, JobIsFinished,
SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob, SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob,
PlaybookRun, LoadPlays, LoadTasks, LoadHosts, PlaybookRun, LoadPlays, LoadTasks,
HostsEdit, ParseVariableString, GetChoices, fieldChoices, HostsEdit, ParseVariableString, GetChoices, fieldChoices,
fieldLabels, EditSchedule, ParseTypeChange, JobDetailService fieldLabels, EditSchedule, ParseTypeChange, JobDetailService
) { ) {
@@ -376,64 +376,26 @@ export default
var params = { var params = {
parent: task.id, parent: task.id,
event__startswith: 'runner', event__startswith: 'runner',
page_size: scope.hostResultsMaxRows
}; };
JobDetailService.getRelatedJobEvents(scope.job.id, params) JobDetailService.getRelatedJobEvents(scope.job.id, params)
.success(function(data) { .success(function(data) {
console.log(data)
var idx, event, status, status_text, item, msg; var idx, event, status, status_text, item, msg;
if (data.results.length > 0) { if (data.results.length > 0) {$
lastEventId = data.results[0].id; lastEventId = data.results[0].id;
} }
scope.next_host_results = data.next; scope.next_host_results = data.next;
for (idx=data.results.length - 1; idx >= 0; idx--) { for (idx=data.results.length - 1; idx >= 0; idx--) {
event = data.results[idx]; event = data.results[idx];
if (event.event === "runner_on_skipped") { event.status = JobDetailService.processEventStatus(event).status;
status = 'skipped'; msg = JobDetailService.processEventMsg(event);
} item = JobDetailService.processEventItem(event);
else if (event.event === "runner_on_unreachable") {
status = 'unreachable';
}
else {
status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful';
}
switch(status) {
case "successful":
status_text = 'OK';
break;
case "changed":
status_text = "Changed";
break;
case "failed":
status_text = "Failed";
break;
case "unreachable":
status_text = "Unreachable";
break;
case "skipped":
status_text = "Skipped";
}
if (event.event_data && event.event_data.res) { if (event.event !== "runner_on$_no_hosts") {
item = event.event_data.res.item;
if (typeof item === "object") {
item = JSON.stringify(item);
}
}
msg = '';
if (event.event_data && event.event_data.res) {
if (typeof event.event_data.res === 'object') {
msg = event.event_data.res.msg;
} else {
msg = event.event_data.res;
}
}
if (event.event !== "runner_on_no_hosts") {
task.hostResults[event.id] = { task.hostResults[event.id] = {
id: event.id, id: event.id,
status: status, status: event.status,
status_text: status_text, status_text: event.status.toUpperCase(),
host_id: event.host, host_id: event.host,
task_id: event.parent, task_id: event.parent,
name: event.event_data.host, name: event.event_data.host,
@@ -673,7 +635,7 @@ export default
scope.$emit('LoadTasks', events_url); scope.$emit('LoadTasks', events_url);
}); });
}); });
if (scope.removeLoadJob) { if (scope.removeLoadJob) {
scope.removeLoadJob(); scope.removeLoadJob();
@@ -1037,6 +999,16 @@ export default
scope.searchTasksEnabled = true; scope.searchTasksEnabled = true;
} }
if (!scope.liveEventProcessing || scope.pauseLiveEvents) { if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
// /api/v1/jobs/15/job_tasks/?event_id=762&task__icontains=create&page_size=200&order=id
var params = {
event_id: scope.selectedPlay,
task__icontains: scope.search_task_name,
page_size: scope.tasksMaxRows,
};
if (scope.search_task_status === 'failed'){
params.failed = true;
}
LoadTasks({ LoadTasks({
scope: scope scope: scope
}); });
@@ -1058,8 +1030,20 @@ export default
scope.searchHostsEnabled = true; scope.searchHostsEnabled = true;
} }
if (!scope.liveEventProcessing || scope.pauseLiveEvents) { if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadHosts({ scope.hostResultsLoading = true;
scope: scope var params = {
parent: scope.selectedTask,
event__startswith: 'runner',
page_size: scope.hostResultsMaxRows,
order: 'host_name,counter',
host_name__icontains: scope.search_host_name
}
if (scope.search_host_status === 'failed'){
params.failed = true;
}
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
scope.hostResults = JobDetailService.processHostResults(res.results)
scope.hostResultsLoading = false;
}); });
} }
}; };
@@ -1104,8 +1088,20 @@ export default
scope.filterHostStatus = function() { scope.filterHostStatus = function() {
scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all'; scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all';
if (!scope.liveEventProcessing || scope.pauseLiveEvents) { if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
LoadHosts({ console.log('filterHostStattus', scope)
scope: scope var params = {
parent: scope.selectedTask,
event__startswith: 'runner',
page_size: scope.hostResultsMaxRows,
order: 'host_name,counter'
}
if (scope.search_host_status === 'failed'){
params.failed = true;
}
scope.hostResultsLoading = true;
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
scope.hostResults = JobDetailService.processHostResults(res.results)
scope.hostResultsLoading = false;
}); });
} }
}; };

View File

@@ -1,18 +1,17 @@
export default export default
['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){ ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){
return { return {
/* /*
For ES6 * For ES6
it might be useful to set some default params here, e.g. * it might be useful to set some default params here, e.g.
getJobHostSummaries: function(id, page_size=200, order='host_name'){} * getJobHostSummaries: function(id, page_size=200, order='host_name'){}
without ES6, we'd have to supply defaults like this: * without ES6, we'd have to supply defaults like this:
this.page_size = params.page_size ? params.page_size : 200; * this.page_size = params.page_size ? params.page_size : 200;
*/ */
// the the API passes through Ansible's event_data response // the the API passes through Ansible's event_data response
// we need to massage away the verbose and redundant properties // we need to massage away the verbose and redundant properties
processJson: function(data){ processJson: function(data){
// a deep copy // a deep copy
var result = $.extend(true, {}, data); var result = $.extend(true, {}, data);
@@ -44,147 +43,195 @@ export default
} }
}); });
} }
catch(err){result.event_data = null;} catch(err){result.event_data = undefined;}
return result return result
}, },
// Return Ansible's passed-through response msg on a job_event
processEventMsg: function(event){
return typeof event.event_data.res === 'object' ? event.event_data.res.msg : event.event_data.res;
},
// Return only Ansible's passed-through response item on a job_event
processEventItem: function(event){
try{
var item = event.event_data.res.item;
return typeof item === 'object' ? JSON.stringify(item) : item
}
catch(err){return;}
},
// Generate a helper class for job_event statuses
// the stack for which status to display is
// unreachable > failed > changed > ok
// uses the API's runner events and convenience properties .failed .changed to determine status.
// see: job_event_callback.py
processEventStatus: function(event){ processEventStatus: function(event){
// Generate a helper class for job_event statuses
// the stack for which status to display is
// unreachable > failed > changed > ok
// uses the API's runner events and convenience properties .failed .changed to determine status.
// see: job_event_callback.py
if (event.event == 'runner_on_unreachable'){ if (event.event == 'runner_on_unreachable'){
event.status = 'Unreachable'; return {
return 'HostEvents-status--unreachable' class: 'HostEvents-status--unreachable',
status: 'unreachable'
}
} }
// equiv to 'runner_on_error' && 'runner on failed' // equiv to 'runner_on_error' && 'runner on failed'
if (event.failed){ if (event.failed){
event.status = 'Failed'; return {
return 'HostEvents-status--failed' class: 'HostEvents-status--failed',
status: 'failed'
}
} }
// catch the changed case before ok, because both can be true // catch the changed case before ok, because both can be true
if (event.changed){ if (event.changed){
event.status = 'Changed'; return {
return 'HostEvents-status--changed' class: 'HostEvents-status--changed',
status: 'changed'
}
} }
if (event.event == 'runner_on_ok'){ if (event.event == 'runner_on_ok'){
event.status = 'OK'; return {
return 'HostEvents-status--ok' class: 'HostEvents-status--ok',
status: 'ok'
}
} }
if (event.event == 'runner_on_skipped'){ if (event.event == 'runner_on_skipped'){
event.status = 'Skipped'; return {
return 'HostEvents-status--skipped' class: 'HostEvents-status--skipped',
status: 'skipped'
}
} }
else{ else{
// study a case where none of these apply // study a case where none of these apply
} }
}, },
// GET events related to a job run // Consumes a response from this.getRelatedJobEvents
// e.g. // returns an array for view logic to iterate over to build host result rows
// ?event=playbook_on_stats processHostResults: function(data){
// ?parent=206&event__startswith=runner&page_size=200&order=host_name,counter var self = this;
getRelatedJobEvents: function(id, params){ var results = [];
var url = GetBasePath('jobs'); data.forEach(function(element, index, array){
url = url + id + '/job_events/?'; var event = element;
Object.keys(params).forEach(function(key, index) { if (event.event !== 'runner_on_no_hosts'){
// the API is tolerant of extra ampersands var status = self.processEventStatus(event);
// ?&event=playbook_on_start == ?event=playbook_on_stats var msg = self.processEventMsg(event);
url = url + '&' + key + '=' + params[key]; var item = self.processEventItem(event);
}); results.push({
Rest.setUrl(url); id: event.id,
return Rest.get() status: status.status,
.success(function(data){ status_text: status.status.charAt(0).toUpperCase() + status.status.slice(1),
return data host_id: event.host,
}) task_id: event.parent,
.error(function(data, status) { name: event.event_data.host,
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', created: event.created,
msg: 'Call to ' + url + '. GET returned: ' + status }); msg: typeof msg === 'undefined' ? undefined : msg,
}); item: typeof item === 'undefined' ? undefined : item
}, });
// GET job host summaries related to a job run }
// e.g. ?page_size=200&order=host_name });
getJobHostSummaries: function(id, params){ return results;
var url = GetBasePath('jobs'); },
url = url + id + '/job_host_summaries/?'
Object.keys(params).forEach(function(key, index) { // GET events related to a job run
// the API is tolerant of extra ampersands // e.g.
url = url + '&' + key + '=' + params[key]; // ?event=playbook_on_stats
}); // ?parent=206&event__startswith=runner&page_size=200&order=host_name,counter
Rest.setUrl(url); getRelatedJobEvents: function(id, params){
return Rest.get() var url = GetBasePath('jobs');
.success(function(data){ url = url + id + '/job_events/?';
return data Object.keys(params).forEach(function(key, index) {
}) // the API is tolerant of extra ampersands
.error(function(data, status) { // ?&event=playbook_on_start == ?event=playbook_on_stats
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', url = url + '&' + key + '=' + params[key];
msg: 'Call to ' + url + '. GET returned: ' + status }); });
}); Rest.setUrl(url);
}, return Rest.get()
// GET job plays related to a job run .success(function(data){
// e.g. ?page_size=200 return data
getJobPlays: function(id, params){ })
var url = GetBasePath('jobs'); .error(function(data, status) {
url = url + id + '/job_plays/?'; ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
Object.keys(params).forEach(function(key, index) { msg: 'Call to ' + url + '. GET returned: ' + status });
// the API is tolerant of extra ampersands });
url = url + '&' + key + '=' + params[key]; },
}); // GET job host summaries related to a job run
Rest.setUrl(url); // e.g. ?page_size=200&order=host_name
return Rest.get() getJobHostSummaries: function(id, params){
.success(function(data){ var url = GetBasePath('jobs');
return data url = url + id + '/job_host_summaries/?'
}) Object.keys(params).forEach(function(key, index) {
.error(function(data, status) { // the API is tolerant of extra ampersands
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', url = url + '&' + key + '=' + params[key];
msg: 'Call to ' + url + '. GET returned: ' + status }); });
}); Rest.setUrl(url);
}, return Rest.get()
getJobTasks: function(id, params){ .success(function(data){
var url = GetBasePath('jobs'); return data
url = url + id + '/job_tasks/?'; })
Object.keys(params).forEach(function(key, index) { .error(function(data, status) {
// the API is tolerant of extra ampersands ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
url = url + '&' + key + '=' + params[key]; msg: 'Call to ' + url + '. GET returned: ' + status });
}); });
Rest.setUrl(url); },
return Rest.get() // GET job plays related to a job run
.success(function(data){ // e.g. ?page_size=200
return data getJobPlays: function(id, params){
}) var url = GetBasePath('jobs');
.error(function(data, status) { url = url + id + '/job_plays/?';
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', Object.keys(params).forEach(function(key, index) {
msg: 'Call to ' + url + '. GET returned: ' + status }); // the API is tolerant of extra ampersands
}); url = url + '&' + key + '=' + params[key];
}, });
getJob: function(id){ Rest.setUrl(url);
var url = GetBasePath('jobs'); return Rest.get()
url = url + id; .success(function(data){
Rest.setUrl(url); return data
return Rest.get() })
.success(function(data){ .error(function(data, status) {
return data ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
}) msg: 'Call to ' + url + '. GET returned: ' + status });
.error(function(data, status) { });
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', },
msg: 'Call to ' + url + '. GET returned: ' + status }); getJobTasks: function(id, params){
}); var url = GetBasePath('jobs');
}, url = url + id + '/job_tasks/?';
// GET next set of paginated results Object.keys(params).forEach(function(key, index) {
// expects 'next' param returned by the API e.g. // the API is tolerant of extra ampersands
// "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1" url = url + '&' + key + '=' + params[key];
getNextPage: function(url){ });
return Rest.get() Rest.setUrl(url);
.success(function(data){ return Rest.get()
return data .success(function(data){
}) return data
.error(function(data, status) { })
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', .error(function(data, status) {
msg: 'Call to ' + url + '. GET returned: ' + status }); ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
}); msg: 'Call to ' + url + '. GET returned: ' + status });
} });
} },
} getJob: function(id){
]; var url = GetBasePath('jobs');
url = url + id;
Rest.setUrl(url);
return Rest.get()
.success(function(data){
return data
})
.error(function(data, status) {
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
},
// GET next set of paginated results
// expects 'next' param returned by the API e.g.
// "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1"
getNextPage: function(url){
return Rest.get()
.success(function(data){
return data
})
.error(function(data, status) {
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
}
}
}
];