mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 17:37:37 -02:30
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:
@@ -6,13 +6,36 @@
|
|||||||
|
|
||||||
export default ['Rest', 'GetBasePath', 'ProcessErrors', 'lodashAsPromised',
|
export default ['Rest', 'GetBasePath', 'ProcessErrors', 'lodashAsPromised',
|
||||||
function (Rest, GetBasePath, ProcessErrors, _) {
|
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 {
|
return {
|
||||||
getHostFacts: function(host, moduleName, date, fetchScanNumber) {
|
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;
|
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) {
|
.then(function(versionData) {
|
||||||
if (_.isEmpty(versionData)) {
|
if (_.isEmpty(versionData)) {
|
||||||
return { fact: [] };
|
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
|
//move the build url into getVersion and have the
|
||||||
// parameters passed into this
|
// parameters passed into this
|
||||||
var promise,
|
var promise;
|
||||||
url = this.buildUrl(host_id, module, startDate, endDate);
|
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);
|
Rest.setUrl(url);
|
||||||
promise = Rest.get();
|
promise = Rest.get();
|
||||||
return promise.then(function(data) {
|
return promise.then(function(response) {
|
||||||
return data.data.results[fetchScanNumber];
|
return response.data.results;
|
||||||
}).catch(function (response) {
|
}).catch(function (response) {
|
||||||
ProcessErrors(null, response.data, response.status, null, {
|
ProcessErrors(null, response.data, response.status, null, {
|
||||||
hdr: 'Error!',
|
hdr: 'Error!',
|
||||||
@@ -56,20 +82,6 @@ function (Rest, GetBasePath, ProcessErrors, _) {
|
|||||||
response.status
|
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
export default
|
export default
|
||||||
[ 'factScanDataService',
|
[ 'factScanDataService',
|
||||||
'getModuleOptions',
|
'getModuleOptions',
|
||||||
|
'resolveVersions',
|
||||||
'lodashAsPromised',
|
'lodashAsPromised',
|
||||||
function(factScanDataService, getModuleOptions, _) {
|
function(factScanDataService, getModuleOptions, resolveVersions) {
|
||||||
return function(hostIds, moduleName, leftDate, rightDate) {
|
return function(hostIds, moduleName, leftDate, rightDate) {
|
||||||
|
|
||||||
var moduleOptions;
|
var moduleOptions;
|
||||||
@@ -17,39 +18,40 @@ export default
|
|||||||
hostIds = hostIds.concat(hostIds[0]);
|
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])
|
return getModuleOptions(hostIds[0])
|
||||||
.then(function(modules) {
|
.then(function(modules) {
|
||||||
moduleOptions = modules;
|
moduleOptions = modules;
|
||||||
return modules;
|
return hostVersionParams;
|
||||||
}).then(function() {
|
}).thenMap(function(versionParam) {
|
||||||
return hostIds;
|
var versionWithRequest =
|
||||||
}).thenMap(function(hostId, index) {
|
[ versionParam,
|
||||||
var date = leftDate;
|
factScanDataService.
|
||||||
var fetchScanNumber;
|
getVersion(versionParam)
|
||||||
|
|
||||||
if (index === 1) {
|
|
||||||
date = rightDate;
|
|
||||||
} else {
|
|
||||||
if (rightDate.from.isSame(leftDate.from, 'day')) {
|
|
||||||
fetchScanNumber = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var params =
|
|
||||||
[ hostId,
|
|
||||||
moduleName,
|
|
||||||
date,
|
|
||||||
fetchScanNumber
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return params;
|
return versionWithRequest;
|
||||||
}).thenMap(function(params) {
|
}).thenAll(function(versions) {
|
||||||
var getHostFacts =
|
return resolveVersions(versions);
|
||||||
_.spread(factScanDataService.getHostFacts)
|
}, true)
|
||||||
.bind(factScanDataService);
|
.thenMap(function(versionData) {
|
||||||
|
if (versionData) {
|
||||||
return getHostFacts(params);
|
return factScanDataService.getFacts(versionData);
|
||||||
}).then(function(hostFacts) {
|
} else {
|
||||||
|
return { fact: [] };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.thenAll(function(hostFacts) {
|
||||||
return [moduleOptions, hostFacts];
|
return [moduleOptions, hostFacts];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -8,6 +8,7 @@ import route from './system-tracking.route';
|
|||||||
import factScanDataService from './data-services/fact-scan-data.service';
|
import factScanDataService from './data-services/fact-scan-data.service';
|
||||||
import getDataForComparison from './data-services/get-data-for-comparison.factory';
|
import getDataForComparison from './data-services/get-data-for-comparison.factory';
|
||||||
import getModuleOptions from './data-services/get-module-options.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 controller from './system-tracking.controller';
|
||||||
import stringOrDateFilter from './string-or-date.filter';
|
import stringOrDateFilter from './string-or-date.filter';
|
||||||
import shared from 'tower/shared/main';
|
import shared from 'tower/shared/main';
|
||||||
@@ -23,6 +24,7 @@ export default
|
|||||||
.service('factScanDataService', factScanDataService)
|
.service('factScanDataService', factScanDataService)
|
||||||
.factory('getDataForComparison', getDataForComparison)
|
.factory('getDataForComparison', getDataForComparison)
|
||||||
.factory('getModuleOptions', getModuleOptions)
|
.factory('getModuleOptions', getModuleOptions)
|
||||||
|
.factory('resolveVersions', resolveVersions)
|
||||||
.filter('stringOrDate', stringOrDateFilter)
|
.filter('stringOrDate', stringOrDateFilter)
|
||||||
.controller('systemTracking', controller)
|
.controller('systemTracking', controller)
|
||||||
.config(['$routeProvider', function($routeProvider) {
|
.config(['$routeProvider', function($routeProvider) {
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ function controller($rootScope,
|
|||||||
$scope.hostIds = $routeParams.hosts;
|
$scope.hostIds = $routeParams.hosts;
|
||||||
$scope.inventory = $routeParams.model.inventory;
|
$scope.inventory = $routeParams.model.inventory;
|
||||||
|
|
||||||
$scope.factModulePickersLabelLeft = "Compare facts collected on";
|
$scope.factModulePickersLabelLeft = "Compare facts collected on or before";
|
||||||
$scope.factModulePickersLabelRight = "To facts collected on";
|
$scope.factModulePickersLabelRight = "To facts collected on or before";
|
||||||
|
|
||||||
$scope.modules = initialFactData.moduleOptions;
|
$scope.modules = initialFactData.moduleOptions;
|
||||||
|
|
||||||
@@ -40,6 +40,9 @@ function controller($rootScope,
|
|||||||
$scope.leftDate = initialFactData.leftSearchRange.from;
|
$scope.leftDate = initialFactData.leftSearchRange.from;
|
||||||
$scope.rightDate = initialFactData.rightSearchRange.from;
|
$scope.rightDate = initialFactData.rightSearchRange.from;
|
||||||
|
|
||||||
|
$scope.leftScanDate = initialFactData.leftScanDate;
|
||||||
|
$scope.rightScanDate = initialFactData.rightScanDate;
|
||||||
|
|
||||||
function setHeaderValues(viewType) {
|
function setHeaderValues(viewType) {
|
||||||
if (viewType === 'singleHost') {
|
if (viewType === 'singleHost') {
|
||||||
$scope.comparisonLeftHeader = $scope.leftScanDate;
|
$scope.comparisonLeftHeader = $scope.leftScanDate;
|
||||||
@@ -58,7 +61,6 @@ function controller($rootScope,
|
|||||||
var leftRange = searchConfig.leftRange;
|
var leftRange = searchConfig.leftRange;
|
||||||
var rightRange = searchConfig.rightRange;
|
var rightRange = searchConfig.rightRange;
|
||||||
var activeModule = searchConfig.module;
|
var activeModule = searchConfig.module;
|
||||||
var leftScanDate, rightScanDate;
|
|
||||||
|
|
||||||
|
|
||||||
if (!factData) {
|
if (!factData) {
|
||||||
@@ -68,12 +70,12 @@ function controller($rootScope,
|
|||||||
activeModule.name,
|
activeModule.name,
|
||||||
leftRange,
|
leftRange,
|
||||||
rightRange)
|
rightRange)
|
||||||
.thenAll(function(factDataAndModules) {
|
.then(function(factDataAndModules) {
|
||||||
var responses = factDataAndModules[1];
|
var responses = factDataAndModules[1];
|
||||||
var data = _.pluck(responses, 'fact');
|
var data = _.pluck(responses, 'fact');
|
||||||
|
|
||||||
leftScanDate = moment(responses[0].timestamp);
|
$scope.leftScanDate = moment(responses[0].timestamp);
|
||||||
rightScanDate = moment(responses[1].timestamp);
|
$scope.rightScanDate = moment(responses[1].timestamp);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}, true);
|
}, true);
|
||||||
@@ -82,7 +84,8 @@ function controller($rootScope,
|
|||||||
waitIndicator('start');
|
waitIndicator('start');
|
||||||
|
|
||||||
return _(factData)
|
return _(factData)
|
||||||
.thenAll(function(facts) {
|
.promise()
|
||||||
|
.then(function(facts) {
|
||||||
// Make sure we always start comparison against
|
// Make sure we always start comparison against
|
||||||
// a non-empty array
|
// a non-empty array
|
||||||
//
|
//
|
||||||
@@ -132,7 +135,9 @@ function controller($rootScope,
|
|||||||
|
|
||||||
$scope.factData = info;
|
$scope.factData = info;
|
||||||
|
|
||||||
setHeaderValues(viewType, leftScanDate, rightScanDate);
|
setHeaderValues(viewType);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
|
||||||
}).finally(function() {
|
}).finally(function() {
|
||||||
waitIndicator('stop');
|
waitIndicator('stop');
|
||||||
|
|||||||
@@ -31,10 +31,10 @@
|
|||||||
|
|
||||||
<section class="FactDataError SystemTrackingContainer-main" ng-if="error" ng-switch="error.name">
|
<section class="FactDataError SystemTrackingContainer-main" ng-if="error" ng-switch="error.name">
|
||||||
<p class="FactDataError-message" ng-switch-when="NoScanData">
|
<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>
|
||||||
<p class="FactDataError-message" ng-switch-when="InsufficientScanData">
|
<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>
|
||||||
<p class="FactDataError-note">
|
<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".
|
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".
|
||||||
|
|||||||
@@ -32,22 +32,22 @@ export default {
|
|||||||
|
|
||||||
var data =
|
var data =
|
||||||
getDataForComparison(hostIds, moduleParam, leftDate, rightDate).
|
getDataForComparison(hostIds, moduleParam, leftDate, rightDate).
|
||||||
thenAll(function(factDataAndModules) {
|
then(function(factDataAndModules) {
|
||||||
var moduleOptions = factDataAndModules[0];
|
var moduleOptions = factDataAndModules[0];
|
||||||
var factResponses = factDataAndModules[1];
|
var factResponses = factDataAndModules[1];
|
||||||
var factData = _.pluck(factResponses, 'fact');
|
var factData = _.pluck(factResponses, 'fact');
|
||||||
|
|
||||||
factData.leftSearchRange = leftDate;
|
factData.leftSearchRange = leftDate;
|
||||||
factData.rightSearchRange = rightDate;
|
factData.rightSearchRange = rightDate;
|
||||||
|
|
||||||
factData.leftScanDate = moment(factResponses[0].timestamp);
|
factData.leftScanDate = moment(factResponses[0].timestamp);
|
||||||
factData.rightScanDate = moment(factResponses[0].timestamp);
|
factData.rightScanDate = moment(factResponses[1].timestamp);
|
||||||
|
|
||||||
factData.moduleName = moduleParam;
|
factData.moduleName = moduleParam;
|
||||||
factData.moduleOptions = moduleOptions;
|
factData.moduleOptions = moduleOptions;
|
||||||
|
|
||||||
return factData;
|
return factData;
|
||||||
}, true)
|
}, true)
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|||||||
Reference in New Issue
Block a user