1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

Resolve fact versions before looking up fact views

This adds a step to the fact version lookup that attempts to resolve
fact versions before looking up their views. Resolving a fact version
means finding another version to use when there is a problem with the
one the user selected.

In this case, the resolution process works as follows:

1. Check if either request returned an empty list

If so, request again, changing the dates to look back a year. This
will almost always return something.

2. If we are requesting multiple facts for the same host, and both of
the resolved versions have the same timestamp, they are duplicates and
we cannot compare against them.

Instead we instruct it to grab the selected and the previous versions for
comparison.

For host-to-host view, this also updates the timestamp in the header to
reflect the actual timestamps. It _does not_ update the date picker
dates yet.
This commit is contained in:
Joe Fiorini 2015-06-03 00:12:00 -04:00
parent 0591812da6
commit 9526975318
7 changed files with 169 additions and 73 deletions

View File

@ -6,13 +6,36 @@
export default ['Rest', 'GetBasePath', 'ProcessErrors', 'lodashAsPromised',
function (Rest, GetBasePath, ProcessErrors, _) {
function buildUrl (host_id, module, startDate, endDate) {
var url = GetBasePath('hosts') + host_id + '/fact_versions/',
params= [["module", module] , ['from', startDate.format()], ['to', endDate.format()]];
params = params.filter(function(p){
return !_.isEmpty(p[1]);
});
params = params.map(function(p){
return p.join("=");
}).join("&");
url = _.compact([url, params]).join("?");
return url;
}
return {
getHostFacts: function(host, moduleName, date, fetchScanNumber) {
var version =this.getVersion(host, moduleName, date.from, date.to, fetchScanNumber);
var getVersion = _.partial(this.getVersion, host, moduleName);
var getFacts = this.getFacts;
return version
return getVersion(date.from, date.to, fetchScanNumber)
.then(function(versionData) {
if (_.isEmpty(versionData)) {
var retryStartDate = date.from.clone().subtract(1, 'year');
return getVersion(retryStartDate, date.from, fetchScanNumber);
} else {
return versionData;
}
})
.then(function(versionData) {
if (_.isEmpty(versionData)) {
return { fact: [] };
@ -37,18 +60,21 @@ function (Rest, GetBasePath, ProcessErrors, _) {
});
},
getVersion: function(host_id, module, startDate, endDate, fetchScanNumber){
getVersion: function(versionParams){
//move the build url into getVersion and have the
// parameters passed into this
var promise,
url = this.buildUrl(host_id, module, startDate, endDate);
var promise;
var hostId = versionParams.hostId;
var startDate = versionParams.dateRange.from;
var endDate = versionParams.dateRange.to;
var module = versionParams.moduleName;
fetchScanNumber = fetchScanNumber || 0;
var url = buildUrl(hostId, module, startDate, endDate);
Rest.setUrl(url);
promise = Rest.get();
return promise.then(function(data) {
return data.data.results[fetchScanNumber];
return promise.then(function(response) {
return response.data.results;
}).catch(function (response) {
ProcessErrors(null, response.data, response.status, null, {
hdr: 'Error!',
@ -56,20 +82,6 @@ function (Rest, GetBasePath, ProcessErrors, _) {
response.status
});
});
},
buildUrl: function(host_id, module, startDate, endDate){
var url = GetBasePath('hosts') + host_id + '/fact_versions/',
params= [["module", module] , ['from', startDate.format()], ['to', endDate.format()]];
params = params.filter(function(p){
return !_.isEmpty(p[1]);
});
params = params.map(function(p){
return p.join("=");
}).join("&");
url = _.compact([url, params]).join("?");
return url;
}
};
}];

View File

@ -7,8 +7,9 @@
export default
[ 'factScanDataService',
'getModuleOptions',
'resolveVersions',
'lodashAsPromised',
function(factScanDataService, getModuleOptions, _) {
function(factScanDataService, getModuleOptions, resolveVersions) {
return function(hostIds, moduleName, leftDate, rightDate) {
var moduleOptions;
@ -17,39 +18,40 @@ export default
hostIds = hostIds.concat(hostIds[0]);
}
var hostVersionParams =
[{ hostId: hostIds[0],
dateRange: leftDate,
moduleName: moduleName
},
{ hostId: hostIds[1],
dateRange: rightDate,
moduleName: moduleName
}
];
return getModuleOptions(hostIds[0])
.then(function(modules) {
moduleOptions = modules;
return modules;
}).then(function() {
return hostIds;
}).thenMap(function(hostId, index) {
var date = leftDate;
var fetchScanNumber;
if (index === 1) {
date = rightDate;
} else {
if (rightDate.from.isSame(leftDate.from, 'day')) {
fetchScanNumber = 1;
}
}
var params =
[ hostId,
moduleName,
date,
fetchScanNumber
return hostVersionParams;
}).thenMap(function(versionParam) {
var versionWithRequest =
[ versionParam,
factScanDataService.
getVersion(versionParam)
];
return params;
}).thenMap(function(params) {
var getHostFacts =
_.spread(factScanDataService.getHostFacts)
.bind(factScanDataService);
return getHostFacts(params);
}).then(function(hostFacts) {
return versionWithRequest;
}).thenAll(function(versions) {
return resolveVersions(versions);
}, true)
.thenMap(function(versionData) {
if (versionData) {
return factScanDataService.getFacts(versionData);
} else {
return { fact: [] };
}
})
.thenAll(function(hostFacts) {
return [moduleOptions, hostFacts];
});
};

View File

@ -0,0 +1,75 @@
function resolveVersions(service, _, results) {
function transformToObjects(versionArray) {
var converted = versionArray[0];
converted.versions = versionArray[1];
return converted;
}
function resolveEmpties(result) {
if (_.isEmpty(result.versions)) {
var originalStartDate = result.dateRange.from;
result.dateRange.from = originalStartDate.clone().subtract(1, 'year');
result.dateRange.to = originalStartDate;
return [result, service.getVersion(result)];
}
return [result, _.promise(result.versions)];
}
function resolveDuplicates(nonEmptyResults) {
var allSameHost =
_.every(nonEmptyResults, { 'hostId': nonEmptyResults[0].hostId });
if (allSameHost) {
var firstTimestamp = nonEmptyResults[0].versions[0].timestamp;
var hostIdsWithDupes =
_(nonEmptyResults)
.pluck('versions[0]')
.filter('timestamp', firstTimestamp)
.map(function(version, index) {
return nonEmptyResults[index].hostId;
})
.value();
if (hostIdsWithDupes.length === 1) {
return _.pluck(nonEmptyResults, 'versions[0]');
}
return nonEmptyResults.map(function(scan, index) {
var hasDupe =
_.include(hostIdsWithDupes, scan.hostId);
if (hasDupe && index === 1) {
return scan.versions[1];
} else {
return scan.versions[0];
}
});
} else {
return _.pluck(nonEmptyResults, 'versions[0]');
}
}
return _(results)
.map(transformToObjects)
.map(resolveEmpties)
.thenAll(function(resolved) {
var versionObjects = resolved.map(transformToObjects);
return resolveDuplicates(versionObjects);
}, true)
.value();
}
export default
[ 'factScanDataService',
'lodashAsPromised',
function(factScanDataService, lodash) {
return _.partial(resolveVersions, factScanDataService, lodash);
}
];

View File

@ -8,6 +8,7 @@ import route from './system-tracking.route';
import factScanDataService from './data-services/fact-scan-data.service';
import getDataForComparison from './data-services/get-data-for-comparison.factory';
import getModuleOptions from './data-services/get-module-options.factory';
import resolveVersions from './data-services/resolve-versions.factory';
import controller from './system-tracking.controller';
import stringOrDateFilter from './string-or-date.filter';
import shared from 'tower/shared/main';
@ -23,6 +24,7 @@ export default
.service('factScanDataService', factScanDataService)
.factory('getDataForComparison', getDataForComparison)
.factory('getModuleOptions', getModuleOptions)
.factory('resolveVersions', resolveVersions)
.filter('stringOrDate', stringOrDateFilter)
.controller('systemTracking', controller)
.config(['$routeProvider', function($routeProvider) {

View File

@ -24,8 +24,8 @@ function controller($rootScope,
$scope.hostIds = $routeParams.hosts;
$scope.inventory = $routeParams.model.inventory;
$scope.factModulePickersLabelLeft = "Compare facts collected on";
$scope.factModulePickersLabelRight = "To facts collected on";
$scope.factModulePickersLabelLeft = "Compare facts collected on or before";
$scope.factModulePickersLabelRight = "To facts collected on or before";
$scope.modules = initialFactData.moduleOptions;
@ -40,6 +40,9 @@ function controller($rootScope,
$scope.leftDate = initialFactData.leftSearchRange.from;
$scope.rightDate = initialFactData.rightSearchRange.from;
$scope.leftScanDate = initialFactData.leftScanDate;
$scope.rightScanDate = initialFactData.rightScanDate;
function setHeaderValues(viewType) {
if (viewType === 'singleHost') {
$scope.comparisonLeftHeader = $scope.leftScanDate;
@ -58,7 +61,6 @@ function controller($rootScope,
var leftRange = searchConfig.leftRange;
var rightRange = searchConfig.rightRange;
var activeModule = searchConfig.module;
var leftScanDate, rightScanDate;
if (!factData) {
@ -68,12 +70,12 @@ function controller($rootScope,
activeModule.name,
leftRange,
rightRange)
.thenAll(function(factDataAndModules) {
.then(function(factDataAndModules) {
var responses = factDataAndModules[1];
var data = _.pluck(responses, 'fact');
leftScanDate = moment(responses[0].timestamp);
rightScanDate = moment(responses[1].timestamp);
$scope.leftScanDate = moment(responses[0].timestamp);
$scope.rightScanDate = moment(responses[1].timestamp);
return data;
}, true);
@ -82,7 +84,8 @@ function controller($rootScope,
waitIndicator('start');
return _(factData)
.thenAll(function(facts) {
.promise()
.then(function(facts) {
// Make sure we always start comparison against
// a non-empty array
//
@ -132,7 +135,9 @@ function controller($rootScope,
$scope.factData = info;
setHeaderValues(viewType, leftScanDate, rightScanDate);
setHeaderValues(viewType);
return info;
}).finally(function() {
waitIndicator('stop');

View File

@ -31,10 +31,10 @@
<section class="FactDataError SystemTrackingContainer-main" ng-if="error" ng-switch="error.name">
<p class="FactDataError-message" ng-switch-when="NoScanData">
There were no facts collected on the dates you selected ({{error.dateValues.leftDate|amDateFormat:'L'}} and {{error.dateValues.rightDate|amDateFormat:'L'}}). Please pick a different range or module and try again.
There were no facts collected on or before the dates you selected ({{error.dateValues.leftDate|amDateFormat:'L'}} and {{error.dateValues.rightDate|amDateFormat:'L'}}). Please pick a different range or module and try again.
</p>
<p class="FactDataError-message" ng-switch-when="InsufficientScanData">
There were no facts collected on one of the dates you selected ({{error.dateValue|amDateFormat:'L'}}). Please select a different date and try again.
There were no facts collected on or before one of the dates you selected ({{error.dateValue|amDateFormat:'L'}}). Please select a different date and try again.
</p>
<p class="FactDataError-note">
To setup or run scan jobs, edit the "<a link-to="inventoryEdit" model="{ inventory_id: inventory }">{{inventory.name}}</a>" inventory and select "Scan Jobs Templates".

View File

@ -32,22 +32,22 @@ export default {
var data =
getDataForComparison(hostIds, moduleParam, leftDate, rightDate).
thenAll(function(factDataAndModules) {
var moduleOptions = factDataAndModules[0];
var factResponses = factDataAndModules[1];
var factData = _.pluck(factResponses, 'fact');
then(function(factDataAndModules) {
var moduleOptions = factDataAndModules[0];
var factResponses = factDataAndModules[1];
var factData = _.pluck(factResponses, 'fact');
factData.leftSearchRange = leftDate;
factData.rightSearchRange = rightDate;
factData.leftSearchRange = leftDate;
factData.rightSearchRange = rightDate;
factData.leftScanDate = moment(factResponses[0].timestamp);
factData.rightScanDate = moment(factResponses[0].timestamp);
factData.leftScanDate = moment(factResponses[0].timestamp);
factData.rightScanDate = moment(factResponses[1].timestamp);
factData.moduleName = moduleParam;
factData.moduleOptions = moduleOptions;
factData.moduleName = moduleParam;
factData.moduleOptions = moduleOptions;
return factData;
}, true)
return factData;
}, true)
.value();
return data;