mirror of
https://github.com/ansible/awx.git
synced 2026-01-20 14:11:24 -03:30
underlying infrastructure for dealing with commits is working now
This commit is contained in:
parent
11592047d6
commit
bb82bfe95a
@ -4,36 +4,55 @@
|
||||
* All Rights Reserved
|
||||
*************************************************/
|
||||
|
||||
export default ['jobResultsService', function(jobResultsService){
|
||||
export default ['jobResultsService', '$q', function(jobResultsService, $q){
|
||||
var val = {};
|
||||
|
||||
// Get the count of the last event
|
||||
var getPreviousCount = function(counter) {
|
||||
// get the ids of all the queue
|
||||
var counters = Object.keys(val.queue).map(counter => parseInt(counter));
|
||||
var previousCount = $q.defer();
|
||||
|
||||
// iterate backwards to find the last count
|
||||
while(counters.indexOf(counter - 1) > -1) {
|
||||
counter = counter - 1;
|
||||
if (val.queue[counter].count) {
|
||||
// need to create a new copy of count when returning
|
||||
// so that it is accurate for the particular event
|
||||
return _.clone(val.queue[counter].count);
|
||||
// iteratively find the last count
|
||||
var findCount = function(counter) {
|
||||
if (counter === 0) {
|
||||
// if counter is 0, no count has been initialized
|
||||
// initialize one!
|
||||
previousCount.resolve({
|
||||
ok: 0,
|
||||
skipped: 0,
|
||||
unreachable: 0,
|
||||
failures: 0,
|
||||
changed: 0
|
||||
});
|
||||
} else if (val.queue[counter] && val.queue[counter].count) {
|
||||
// this event has a count, resolve!
|
||||
previousCount.resolve(_.clone(val.queue[counter].count));
|
||||
} else {
|
||||
// this event doesn't have a count, decrement to the
|
||||
// previous event and check it
|
||||
findCount(counter - 1);
|
||||
}
|
||||
};
|
||||
|
||||
if (val.queue[counter - 1]) {
|
||||
// if the previous event has been resolved, start the iterative
|
||||
// get previous count process
|
||||
findCount(counter - 1);
|
||||
} else if (val.populateDefers[counter - 1]){
|
||||
// if the previous event has not been resolved, wait for it to
|
||||
// be and then start the iterative get previous count process
|
||||
val.populateDefers[counter - 1].promise.then(function() {
|
||||
findCount(counter - 1);
|
||||
});
|
||||
}
|
||||
|
||||
// no count initialized
|
||||
return {
|
||||
ok: 0,
|
||||
skipped: 0,
|
||||
unreachable: 0,
|
||||
failures: 0,
|
||||
changed: 0
|
||||
};
|
||||
return previousCount.promise;
|
||||
};
|
||||
|
||||
// munge the raw event from the backend into the event_queue's format
|
||||
var mungeEvent = function(event) {
|
||||
var mungedEventDefer = $q.defer();
|
||||
|
||||
// basic data needed in the munged event
|
||||
var mungedEvent = {
|
||||
counter: event.counter,
|
||||
id: event.id,
|
||||
@ -41,58 +60,175 @@ export default ['jobResultsService', function(jobResultsService){
|
||||
name: event.event_name
|
||||
};
|
||||
|
||||
// for different types of events, you need different types of data
|
||||
if (event.event_name === 'playbook_on_start') {
|
||||
// sets count initially so this is a change
|
||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
||||
mungedEvent.count = {
|
||||
ok: 0,
|
||||
skipped: 0,
|
||||
unreachable: 0,
|
||||
failures: 0,
|
||||
changed: 0
|
||||
};
|
||||
mungedEvent.changes = ['count'];
|
||||
mungedEventDefer.resolve(mungedEvent);
|
||||
} else if (event.event_name === 'runner_on_ok' ||
|
||||
event.event_name === 'runner_on_async_ok') {
|
||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
||||
mungedEvent.count.ok++;
|
||||
mungedEvent.changes = ['count'];
|
||||
getPreviousCount(mungedEvent.counter)
|
||||
.then(count => {
|
||||
mungedEvent.count = count;
|
||||
mungedEvent.count.ok++;
|
||||
mungedEvent.changes = ['count'];
|
||||
mungedEventDefer.resolve(mungedEvent);
|
||||
});
|
||||
} else if (event.event_name === 'runner_on_skipped') {
|
||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
||||
mungedEvent.count.skipped++;
|
||||
mungedEvent.changes = ['count'];
|
||||
getPreviousCount(mungedEvent.counter)
|
||||
.then(count => {
|
||||
mungedEvent.count = count;
|
||||
mungedEvent.count.skipped++;
|
||||
mungedEvent.changes = ['count'];
|
||||
mungedEventDefer.resolve(mungedEvent);
|
||||
});
|
||||
} else if (event.event_name === 'runner_on_unreachable') {
|
||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
||||
mungedEvent.count.unreachable++;
|
||||
mungedEvent.changes = ['count'];
|
||||
getPreviousCount(mungedEvent.counter)
|
||||
.then(count => {
|
||||
mungedEvent.count = count;
|
||||
mungedEvent.count.unrecahble++;
|
||||
mungedEvent.changes = ['count'];
|
||||
mungedEventDefer.resolve(mungedEvent);
|
||||
});
|
||||
} else if (event.event_name === 'runner_on_error' ||
|
||||
event.event_name === 'runner_on_async_failed') {
|
||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
||||
mungedEvent.count.failed++;
|
||||
mungedEvent.changes = ['count'];
|
||||
getPreviousCount(mungedEvent.counter)
|
||||
.then(count => {
|
||||
mungedEvent.count = count;
|
||||
mungedEvent.count.failed++;
|
||||
mungedEvent.changes = ['count'];
|
||||
mungedEventDefer.resolve(mungedEvent);
|
||||
});
|
||||
} else if (event.event_name === 'playbook_on_stats') {
|
||||
// get the data for populating the host status bar
|
||||
mungedEvent.count = jobResultsService
|
||||
.getCountsFromStatsEvent(event.event_data);
|
||||
mungedEvent.changes = ['count', 'countFinished'];
|
||||
mungedEventDefer.resolve(mungedEvent);
|
||||
} else {
|
||||
mungedEventDefer.resolve(mungedEvent);
|
||||
}
|
||||
return mungedEvent;
|
||||
|
||||
return mungedEventDefer.promise;
|
||||
};
|
||||
|
||||
val = {
|
||||
populateDefers: {},
|
||||
queue: {},
|
||||
// reinitializes the event queue value for the job results page
|
||||
//
|
||||
// TODO: implement some sort of local storage scheme
|
||||
// to make viewing job details that the user has
|
||||
// previous clicked on super quick, this would be where you grab
|
||||
// from local storage
|
||||
initialize: function() {
|
||||
val.queue = {};
|
||||
val.populateDefers = {};
|
||||
},
|
||||
// populates the event queue
|
||||
populate: function(event) {
|
||||
// don't populate the event if it's already been added either
|
||||
// by rest or by websocket event
|
||||
if (!val.queue[event.counter]) {
|
||||
var mungedEvent = mungeEvent(event);
|
||||
val.queue[mungedEvent.counter] = mungedEvent;
|
||||
|
||||
return mungedEvent;
|
||||
// if a defer hasn't been set up for the event,
|
||||
// set one up now
|
||||
if (!val.populateDefers[event.counter]) {
|
||||
val.populateDefers[event.counter] = $q.defer();
|
||||
}
|
||||
|
||||
if (!val.queue[event.counter]) {
|
||||
var resolvePopulation = function(event) {
|
||||
// to resolve, put the event on the queue and
|
||||
// then resolve the deferred value
|
||||
//
|
||||
// TODO: implement some sort of local storage scheme
|
||||
// to make viewing job details that the user has
|
||||
// previous clicked on super quick, this would be
|
||||
// where you put in local storage
|
||||
val.queue[event.counter] = event;
|
||||
val.populateDefers[event.counter].resolve(event);
|
||||
}
|
||||
|
||||
if (event.counter === 1) {
|
||||
// for the first event, go ahead and munge and
|
||||
// resolve
|
||||
mungeEvent(event).then(event => {
|
||||
resolvePopulation(event);
|
||||
});
|
||||
} else {
|
||||
// for all other events, you have to do some things
|
||||
// to keep the event processing in the UI synchronous
|
||||
|
||||
if (!val.populateDefers[event.counter - 1]) {
|
||||
// first, if the previous event doesn't have
|
||||
// a defer set up (this happens when websocket
|
||||
// events are coming in and you need to make
|
||||
// rest calls to catch up), go ahead and set a
|
||||
// defer for the previous event
|
||||
val.populateDefers[event.counter - 1] = $q.defer();
|
||||
}
|
||||
|
||||
// you can start the munging process...
|
||||
mungeEvent(event).then(event => {
|
||||
// ...but wait until the previous event has
|
||||
// been resolved before resolving this one and
|
||||
// doing stuff in the ui (that's why we
|
||||
// needed that previous conditional). this
|
||||
// could be done in a more asynchronous nature
|
||||
// if we need a performance boost. See the
|
||||
// todo note in the markProcessed function
|
||||
// for an idea
|
||||
val.populateDefers[event.counter - 1].promise
|
||||
.then(() => {
|
||||
resolvePopulation(event);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// don't repopulate the event if it's already been added
|
||||
// and munged either by rest or by websocket event
|
||||
val.populateDefers[event.counter]
|
||||
.resolve(val.queue[event.counter]);
|
||||
}
|
||||
|
||||
return val.populateDefers[event.counter].promise;
|
||||
},
|
||||
// the event has been processed in the view and should be marked as
|
||||
// completed in the queue
|
||||
markProcessed: function(event) {
|
||||
val.queue[event.counter].processed = true;
|
||||
var process = function(event) {
|
||||
// the event has now done it's work in the UI, record
|
||||
// that!
|
||||
val.queue[event.counter].processed = true;
|
||||
|
||||
// TODO: we can actually record what has been done in the
|
||||
// UI and at what event too! (something like "resolved
|
||||
// the count on event 63)".
|
||||
//
|
||||
// if we do something like this, we actually wouldn't
|
||||
// have to wait until the previous events had completed
|
||||
// before resolving and returning to the controller
|
||||
// in populate()...
|
||||
// in other words, we could send events out of order to
|
||||
// the controller, but let the controller know that it's
|
||||
// an older event that what is in the view so we don't
|
||||
// need to do anything
|
||||
};
|
||||
|
||||
if (!val.queue[event.counter]) {
|
||||
// sometimes, the process is called in the controller and
|
||||
// the event queue hasn't caught up and actually added
|
||||
// the event to the queue yet. Wait until that happens
|
||||
val.populateDefers[event.counter].promise
|
||||
.finally(function() {
|
||||
process(event);
|
||||
});
|
||||
} else {
|
||||
process(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -76,36 +76,55 @@ export default ['jobData', 'jobDataOptions', 'jobLabels', 'count', '$scope', 'Pa
|
||||
$scope.hostCount = getTotalHostCount(count.val);
|
||||
$scope.countFinished = count.countFinished;
|
||||
|
||||
// Process incoming job status changes
|
||||
$rootScope.$on('JobStatusChange-jobDetails', function(e, data) {
|
||||
if (parseInt(data.unified_job_id, 10) === parseInt($scope.job.id,10)) {
|
||||
$scope.job.status = data.status;
|
||||
}
|
||||
});
|
||||
|
||||
// EVENT STUFF BELOW
|
||||
|
||||
// just putting the event queue on scope so it can be inspected in the
|
||||
// console
|
||||
$scope.event_queue = eventQueue.queue;
|
||||
$scope.defersArr = eventQueue.populateDefers;
|
||||
|
||||
// This is where the async updates to the UI actually happen.
|
||||
// Flow is event queue munging in the service -> $scope setting in here
|
||||
var processEvent = function(event) {
|
||||
// put the event in the queue
|
||||
var mungedEvent = eventQueue.populate(event);
|
||||
eventQueue.populate(event).then(mungedEvent => {
|
||||
// make changes to ui based on the event returned from the queue
|
||||
if (mungedEvent.changes) {
|
||||
mungedEvent.changes.forEach(change => {
|
||||
// we've got a change we need to make to the UI!
|
||||
// update the necessary scope and make the change
|
||||
if (change === 'count' && !$scope.countFinished) {
|
||||
// for all events that affect the host count,
|
||||
// update the status bar as well as the host
|
||||
// count badge
|
||||
$scope.count = mungedEvent.count;
|
||||
$scope.hostCount = getTotalHostCount(mungedEvent
|
||||
.count);
|
||||
}
|
||||
|
||||
// make changes to ui based on the event returned from the queue
|
||||
if (mungedEvent.changes) {
|
||||
mungedEvent.changes.forEach(change => {
|
||||
if (change === 'count' && !$scope.countFinished) {
|
||||
$scope.count = mungedEvent.count;
|
||||
$scope.hostCount = getTotalHostCount(mungedEvent
|
||||
.count);
|
||||
}
|
||||
if (change === 'countFinished') {
|
||||
// the playbook_on_stats event actually lets
|
||||
// us know that we don't need to iteratively
|
||||
// look at event to update the host counts
|
||||
// any more.
|
||||
$scope.countFinished = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (change === 'countFnished') {
|
||||
$scope.countFinished = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// the changes have been processed in the ui, mark it in the queue
|
||||
eventQueue.markProcessed(event);
|
||||
// the changes have been processed in the ui, mark it in the queue
|
||||
eventQueue.markProcessed(event);
|
||||
});
|
||||
};
|
||||
|
||||
// grab completed event data and process each event
|
||||
// PULL! grab completed event data and process each event
|
||||
var getEvents = function(url) {
|
||||
jobResultsService.getEvents(url)
|
||||
.then(events => {
|
||||
@ -122,15 +141,14 @@ export default ['jobData', 'jobDataOptions', 'jobLabels', 'count', '$scope', 'Pa
|
||||
};
|
||||
getEvents($scope.job.related.job_events);
|
||||
|
||||
// process incoming job events
|
||||
// PUSH! process incoming job events
|
||||
$rootScope.event_socket.on("job_events-" + $scope.job.id, function(data) {
|
||||
processEvent(data);
|
||||
});
|
||||
|
||||
// process incoming job status changes
|
||||
$rootScope.$on('JobStatusChange-jobDetails', function(e, data) {
|
||||
if (parseInt(data.unified_job_id, 10) === parseInt($scope.job.id,10)) {
|
||||
$scope.job.status = data.status;
|
||||
}
|
||||
// STOP! stop listening to job events
|
||||
$scope.$on('$destroy', function() {
|
||||
$rootScope.event_socket.removeAllListeners("job_events-" +
|
||||
$scope.job.id);
|
||||
});
|
||||
}];
|
||||
|
||||
@ -16,6 +16,7 @@ export default {
|
||||
label: '{{ job.id }} - {{ job.name }}'
|
||||
},
|
||||
resolve: {
|
||||
// the GET for the particular job
|
||||
jobData: ['Rest', 'GetBasePath', '$stateParams', '$q', '$state', 'Alert', function(Rest, GetBasePath, $stateParams, $q, $state, Alert) {
|
||||
Rest.setUrl(GetBasePath('jobs') + $stateParams.id);
|
||||
var val = $q.defer();
|
||||
@ -35,6 +36,10 @@ export default {
|
||||
});
|
||||
return val.promise;
|
||||
}],
|
||||
// after the GET for the job, this helps us keep the status bar from
|
||||
// flashing as rest data comes in. If the job is finished and
|
||||
// there's a playbook_on_stats event, go ahead and resolve the count
|
||||
// so you don't get that flashing!
|
||||
count: ['jobData', 'jobResultsService', 'Rest', '$q', function(jobData, jobResultsService, Rest, $q) {
|
||||
var defer = $q.defer();
|
||||
if (jobData.finished) {
|
||||
@ -72,6 +77,8 @@ export default {
|
||||
}
|
||||
return defer.promise;
|
||||
}],
|
||||
// GET for the particular jobs labels to be displayed in the
|
||||
// left-hand pane
|
||||
jobLabels: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) {
|
||||
var getNext = function(data, arr, resolve) {
|
||||
Rest.setUrl(data.next);
|
||||
@ -101,6 +108,9 @@ export default {
|
||||
|
||||
return seeMoreResolve.promise;
|
||||
}],
|
||||
// OPTIONS request for the job. Used to make things like the
|
||||
// verbosity data in the left-hand pane prettier than just an
|
||||
// integer
|
||||
jobDataOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) {
|
||||
Rest.setUrl(GetBasePath('jobs') + $stateParams.id);
|
||||
var val = $q.defer();
|
||||
@ -112,6 +122,11 @@ export default {
|
||||
});
|
||||
return val.promise;
|
||||
}],
|
||||
// This gives us access to the job events socket so we can start
|
||||
// listening for updates we need to make for the ui as data comes in
|
||||
//
|
||||
// TODO: we could probably make this better by not initing
|
||||
// job_events for completed jobs
|
||||
jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) {
|
||||
if (!$rootScope.event_socket) {
|
||||
$rootScope.event_socket = Socket({
|
||||
@ -126,6 +141,8 @@ export default {
|
||||
return true;
|
||||
}
|
||||
}],
|
||||
// This clears out the event queue, otherwise it'd be full of events
|
||||
// for previous job results the user had navigated to
|
||||
eventQueueInit: ['eventQueue', function(eventQueue) {
|
||||
eventQueue.initialize();
|
||||
}]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user