mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 09:57:35 -02:30
underlying infrastructure for dealing with commits is working now
This commit is contained in:
committed by
jaredevantabor
parent
11592047d6
commit
bb82bfe95a
@@ -4,36 +4,55 @@
|
|||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
export default ['jobResultsService', function(jobResultsService){
|
export default ['jobResultsService', '$q', function(jobResultsService, $q){
|
||||||
var val = {};
|
var val = {};
|
||||||
|
|
||||||
// Get the count of the last event
|
// Get the count of the last event
|
||||||
var getPreviousCount = function(counter) {
|
var getPreviousCount = function(counter) {
|
||||||
// get the ids of all the queue
|
var previousCount = $q.defer();
|
||||||
var counters = Object.keys(val.queue).map(counter => parseInt(counter));
|
|
||||||
|
|
||||||
// iterate backwards to find the last count
|
// iteratively find the last count
|
||||||
while(counters.indexOf(counter - 1) > -1) {
|
var findCount = function(counter) {
|
||||||
counter = counter - 1;
|
if (counter === 0) {
|
||||||
if (val.queue[counter].count) {
|
// if counter is 0, no count has been initialized
|
||||||
// need to create a new copy of count when returning
|
// initialize one!
|
||||||
// so that it is accurate for the particular event
|
previousCount.resolve({
|
||||||
return _.clone(val.queue[counter].count);
|
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 previousCount.promise;
|
||||||
return {
|
|
||||||
ok: 0,
|
|
||||||
skipped: 0,
|
|
||||||
unreachable: 0,
|
|
||||||
failures: 0,
|
|
||||||
changed: 0
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// munge the raw event from the backend into the event_queue's format
|
// munge the raw event from the backend into the event_queue's format
|
||||||
var mungeEvent = function(event) {
|
var mungeEvent = function(event) {
|
||||||
|
var mungedEventDefer = $q.defer();
|
||||||
|
|
||||||
|
// basic data needed in the munged event
|
||||||
var mungedEvent = {
|
var mungedEvent = {
|
||||||
counter: event.counter,
|
counter: event.counter,
|
||||||
id: event.id,
|
id: event.id,
|
||||||
@@ -41,58 +60,175 @@ export default ['jobResultsService', function(jobResultsService){
|
|||||||
name: event.event_name
|
name: event.event_name
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// for different types of events, you need different types of data
|
||||||
if (event.event_name === 'playbook_on_start') {
|
if (event.event_name === 'playbook_on_start') {
|
||||||
// sets count initially so this is a change
|
mungedEvent.count = {
|
||||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
ok: 0,
|
||||||
|
skipped: 0,
|
||||||
|
unreachable: 0,
|
||||||
|
failures: 0,
|
||||||
|
changed: 0
|
||||||
|
};
|
||||||
mungedEvent.changes = ['count'];
|
mungedEvent.changes = ['count'];
|
||||||
|
mungedEventDefer.resolve(mungedEvent);
|
||||||
} else if (event.event_name === 'runner_on_ok' ||
|
} else if (event.event_name === 'runner_on_ok' ||
|
||||||
event.event_name === 'runner_on_async_ok') {
|
event.event_name === 'runner_on_async_ok') {
|
||||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
getPreviousCount(mungedEvent.counter)
|
||||||
mungedEvent.count.ok++;
|
.then(count => {
|
||||||
mungedEvent.changes = ['count'];
|
mungedEvent.count = count;
|
||||||
|
mungedEvent.count.ok++;
|
||||||
|
mungedEvent.changes = ['count'];
|
||||||
|
mungedEventDefer.resolve(mungedEvent);
|
||||||
|
});
|
||||||
} else if (event.event_name === 'runner_on_skipped') {
|
} else if (event.event_name === 'runner_on_skipped') {
|
||||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
getPreviousCount(mungedEvent.counter)
|
||||||
mungedEvent.count.skipped++;
|
.then(count => {
|
||||||
mungedEvent.changes = ['count'];
|
mungedEvent.count = count;
|
||||||
|
mungedEvent.count.skipped++;
|
||||||
|
mungedEvent.changes = ['count'];
|
||||||
|
mungedEventDefer.resolve(mungedEvent);
|
||||||
|
});
|
||||||
} else if (event.event_name === 'runner_on_unreachable') {
|
} else if (event.event_name === 'runner_on_unreachable') {
|
||||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
getPreviousCount(mungedEvent.counter)
|
||||||
mungedEvent.count.unreachable++;
|
.then(count => {
|
||||||
mungedEvent.changes = ['count'];
|
mungedEvent.count = count;
|
||||||
|
mungedEvent.count.unrecahble++;
|
||||||
|
mungedEvent.changes = ['count'];
|
||||||
|
mungedEventDefer.resolve(mungedEvent);
|
||||||
|
});
|
||||||
} else if (event.event_name === 'runner_on_error' ||
|
} else if (event.event_name === 'runner_on_error' ||
|
||||||
event.event_name === 'runner_on_async_failed') {
|
event.event_name === 'runner_on_async_failed') {
|
||||||
mungedEvent.count = getPreviousCount(mungedEvent.counter);
|
getPreviousCount(mungedEvent.counter)
|
||||||
mungedEvent.count.failed++;
|
.then(count => {
|
||||||
mungedEvent.changes = ['count'];
|
mungedEvent.count = count;
|
||||||
|
mungedEvent.count.failed++;
|
||||||
|
mungedEvent.changes = ['count'];
|
||||||
|
mungedEventDefer.resolve(mungedEvent);
|
||||||
|
});
|
||||||
} else if (event.event_name === 'playbook_on_stats') {
|
} else if (event.event_name === 'playbook_on_stats') {
|
||||||
// get the data for populating the host status bar
|
// get the data for populating the host status bar
|
||||||
mungedEvent.count = jobResultsService
|
mungedEvent.count = jobResultsService
|
||||||
.getCountsFromStatsEvent(event.event_data);
|
.getCountsFromStatsEvent(event.event_data);
|
||||||
mungedEvent.changes = ['count', 'countFinished'];
|
mungedEvent.changes = ['count', 'countFinished'];
|
||||||
|
mungedEventDefer.resolve(mungedEvent);
|
||||||
|
} else {
|
||||||
|
mungedEventDefer.resolve(mungedEvent);
|
||||||
}
|
}
|
||||||
return mungedEvent;
|
|
||||||
|
return mungedEventDefer.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
val = {
|
val = {
|
||||||
|
populateDefers: {},
|
||||||
queue: {},
|
queue: {},
|
||||||
// reinitializes the event queue value for the job results page
|
// 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() {
|
initialize: function() {
|
||||||
val.queue = {};
|
val.queue = {};
|
||||||
|
val.populateDefers = {};
|
||||||
},
|
},
|
||||||
// populates the event queue
|
// populates the event queue
|
||||||
populate: function(event) {
|
populate: function(event) {
|
||||||
// don't populate the event if it's already been added either
|
// if a defer hasn't been set up for the event,
|
||||||
// by rest or by websocket event
|
// set one up now
|
||||||
if (!val.queue[event.counter]) {
|
if (!val.populateDefers[event.counter]) {
|
||||||
var mungedEvent = mungeEvent(event);
|
val.populateDefers[event.counter] = $q.defer();
|
||||||
val.queue[mungedEvent.counter] = mungedEvent;
|
|
||||||
|
|
||||||
return mungedEvent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// the event has been processed in the view and should be marked as
|
||||||
// completed in the queue
|
// completed in the queue
|
||||||
markProcessed: function(event) {
|
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.hostCount = getTotalHostCount(count.val);
|
||||||
$scope.countFinished = count.countFinished;
|
$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
|
// EVENT STUFF BELOW
|
||||||
|
|
||||||
// just putting the event queue on scope so it can be inspected in the
|
// just putting the event queue on scope so it can be inspected in the
|
||||||
// console
|
// console
|
||||||
$scope.event_queue = eventQueue.queue;
|
$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) {
|
var processEvent = function(event) {
|
||||||
// put the event in the queue
|
// 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 (change === 'countFinished') {
|
||||||
if (mungedEvent.changes) {
|
// the playbook_on_stats event actually lets
|
||||||
mungedEvent.changes.forEach(change => {
|
// us know that we don't need to iteratively
|
||||||
if (change === 'count' && !$scope.countFinished) {
|
// look at event to update the host counts
|
||||||
$scope.count = mungedEvent.count;
|
// any more.
|
||||||
$scope.hostCount = getTotalHostCount(mungedEvent
|
$scope.countFinished = true;
|
||||||
.count);
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (change === 'countFnished') {
|
// the changes have been processed in the ui, mark it in the queue
|
||||||
$scope.countFinished = true;
|
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) {
|
var getEvents = function(url) {
|
||||||
jobResultsService.getEvents(url)
|
jobResultsService.getEvents(url)
|
||||||
.then(events => {
|
.then(events => {
|
||||||
@@ -122,15 +141,14 @@ export default ['jobData', 'jobDataOptions', 'jobLabels', 'count', '$scope', 'Pa
|
|||||||
};
|
};
|
||||||
getEvents($scope.job.related.job_events);
|
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) {
|
$rootScope.event_socket.on("job_events-" + $scope.job.id, function(data) {
|
||||||
processEvent(data);
|
processEvent(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
// process incoming job status changes
|
// STOP! stop listening to job events
|
||||||
$rootScope.$on('JobStatusChange-jobDetails', function(e, data) {
|
$scope.$on('$destroy', function() {
|
||||||
if (parseInt(data.unified_job_id, 10) === parseInt($scope.job.id,10)) {
|
$rootScope.event_socket.removeAllListeners("job_events-" +
|
||||||
$scope.job.status = data.status;
|
$scope.job.id);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export default {
|
|||||||
label: '{{ job.id }} - {{ job.name }}'
|
label: '{{ job.id }} - {{ job.name }}'
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
|
// the GET for the particular job
|
||||||
jobData: ['Rest', 'GetBasePath', '$stateParams', '$q', '$state', 'Alert', function(Rest, GetBasePath, $stateParams, $q, $state, Alert) {
|
jobData: ['Rest', 'GetBasePath', '$stateParams', '$q', '$state', 'Alert', function(Rest, GetBasePath, $stateParams, $q, $state, Alert) {
|
||||||
Rest.setUrl(GetBasePath('jobs') + $stateParams.id);
|
Rest.setUrl(GetBasePath('jobs') + $stateParams.id);
|
||||||
var val = $q.defer();
|
var val = $q.defer();
|
||||||
@@ -35,6 +36,10 @@ export default {
|
|||||||
});
|
});
|
||||||
return val.promise;
|
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) {
|
count: ['jobData', 'jobResultsService', 'Rest', '$q', function(jobData, jobResultsService, Rest, $q) {
|
||||||
var defer = $q.defer();
|
var defer = $q.defer();
|
||||||
if (jobData.finished) {
|
if (jobData.finished) {
|
||||||
@@ -72,6 +77,8 @@ export default {
|
|||||||
}
|
}
|
||||||
return defer.promise;
|
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) {
|
jobLabels: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) {
|
||||||
var getNext = function(data, arr, resolve) {
|
var getNext = function(data, arr, resolve) {
|
||||||
Rest.setUrl(data.next);
|
Rest.setUrl(data.next);
|
||||||
@@ -101,6 +108,9 @@ export default {
|
|||||||
|
|
||||||
return seeMoreResolve.promise;
|
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) {
|
jobDataOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) {
|
||||||
Rest.setUrl(GetBasePath('jobs') + $stateParams.id);
|
Rest.setUrl(GetBasePath('jobs') + $stateParams.id);
|
||||||
var val = $q.defer();
|
var val = $q.defer();
|
||||||
@@ -112,6 +122,11 @@ export default {
|
|||||||
});
|
});
|
||||||
return val.promise;
|
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) {
|
jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) {
|
||||||
if (!$rootScope.event_socket) {
|
if (!$rootScope.event_socket) {
|
||||||
$rootScope.event_socket = Socket({
|
$rootScope.event_socket = Socket({
|
||||||
@@ -126,6 +141,8 @@ export default {
|
|||||||
return true;
|
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) {
|
eventQueueInit: ['eventQueue', function(eventQueue) {
|
||||||
eventQueue.initialize();
|
eventQueue.initialize();
|
||||||
}]
|
}]
|
||||||
|
|||||||
Reference in New Issue
Block a user