Merge branch 'master' into fix-license_2

This commit is contained in:
Chris Meyers 2015-06-08 14:40:19 -04:00
commit 9f48f127db
18 changed files with 112 additions and 60 deletions

View File

@ -413,11 +413,11 @@ rpm-build/$(RPM_NVR).noarch.rpm: rpm-build/$(RPM_NVR).src.rpm
mock-rpm: rpmtar rpm-build/$(RPM_NVR).noarch.rpm
ifeq ($(OFFICIAL),yes)
rpm-build/$(GPG_FILE): rpm-build
gpg --export -a "${GPG_KEY}" > "$@"
rpm-build/$(GPG_FILE): rpm-build
gpg --export -a "${GPG_KEY}" > "$@"
rpm-sign: rpm-build/$(GPG_FILE) rpmtar rpm-build/$(RPM_NVR).noarch.rpm
rpm --define "_signature gpg" --define "_gpg_name $(GPG_KEY)" --addsign rpm-build/$(RPM_NVR).noarch.rpm
rpm-sign: rpm-build/$(GPG_FILE) rpmtar rpm-build/$(RPM_NVR).noarch.rpm
rpm --define "_signature gpg" --define "_gpg_name $(GPG_KEY)" --addsign rpm-build/$(RPM_NVR).noarch.rpm
endif
deb-build/$(SDIST_TAR_NAME):

View File

@ -273,7 +273,7 @@ class ApiV1ConfigView(APIView):
mongodb_control.delay('stop')
except OSError:
pass
return Response()
return Response(status=status.HTTP_204_NO_CONTENT)
class DashboardView(APIView):

View File

@ -182,6 +182,7 @@ class FactVersion(Document):
meta = {
'indexes': [
'-timestamp',
'module'
'module',
'host',
]
}

View File

@ -31,53 +31,48 @@ class CleanupFacts(object):
# pivot -= granularity
# group by host
def cleanup(self, older_than_abs, granularity, module=None):
flag_delete_all = False
fact_oldest = FactVersion.objects.all().order_by('timestamp').first()
if not fact_oldest:
return 0
kv = {
'timestamp__lte': older_than_abs
}
if module:
kv['module'] = module
# Special case, granularity=0x where x is d, w, or y
# The intent is to delete all facts < older_than_abs
if granularity == relativedelta():
flag_delete_all = True
return FactVersion.objects.filter(**kv).order_by('-timestamp').delete()
total = 0
date_pivot = older_than_abs
while date_pivot > fact_oldest.timestamp:
date_pivot_next = date_pivot - granularity
# For the current time window.
# Delete all facts expect the fact that matches the largest timestamp.
kv = {
'timestamp__lte': date_pivot
}
if not flag_delete_all:
kv['timestamp__gt'] = date_pivot_next
if module:
kv['module'] = module
version_objs = FactVersion.objects.filter(**kv).order_by('-timestamp')
if flag_delete_all:
total = version_objs.delete()
break
# Transform array -> {host_id} = [<fact_version>, <fact_version>, ...]
# TODO: If this set gets large then we can use mongo to transform the data set for us.
host_ids = {}
for obj in version_objs:
k = obj.host.id
if k not in host_ids:
host_ids[k] = []
host_ids[k].append(obj)
for k in host_ids:
ids = [fact.id for fact in host_ids[k]]
fact_ids = [fact.fact.id for fact in host_ids[k]]
# Remove 1 entry
ids.pop()
fact_ids.pop()
# delete the rest
count = FactVersion.objects.filter(id__in=ids).delete()
# FIXME: if this crashes here then we are inconsistent
count = Fact.objects.filter(id__in=fact_ids).delete()
fact_version_objs = FactVersion.objects.filter(**kv).order_by('-timestamp').limit(1)
if fact_version_objs:
fact_version_obj = fact_version_objs[0]
kv = {
'timestamp__lt': fact_version_obj.timestamp,
'timestamp__gt': date_pivot_next
}
if module:
kv['module'] = module
count = FactVersion.objects.filter(**kv).delete()
# FIXME: These two deletes should be a transaction
count = Fact.objects.filter(**kv).delete()
total += count
date_pivot = date_pivot_next

View File

@ -21,6 +21,7 @@ __all__ = ['CommandTest','CleanupFactsUnitTest', 'CleanupFactsCommandFunctionalT
class CleanupFactsCommandFunctionalTest(BaseCommandMixin, BaseTest, MongoDBRequired):
def setUp(self):
super(CleanupFactsCommandFunctionalTest, self).setUp()
self.create_test_license_file()
self.builder = FactScanBuilder()
self.builder.add_fact('ansible', TEST_FACT_ANSIBLE)
@ -55,6 +56,10 @@ class CleanupFactsCommandFunctionalTest(BaseCommandMixin, BaseTest, MongoDBRequi
self.assertEqual(stdout, 'Deleted 25 facts.\n')
class CommandTest(BaseTest):
def setUp(self):
super(CommandTest, self).setUp()
self.create_test_license_file()
@mock.patch('awx.main.management.commands.cleanup_facts.CleanupFacts.run')
def test_parameters_ok(self, run):
@ -149,11 +154,11 @@ class CleanupFactsUnitTest(BaseCommandMixin, BaseTest, MongoDBRequired):
self.builder = FactScanBuilder()
self.builder.add_fact('ansible', TEST_FACT_ANSIBLE)
self.builder.add_fact('packages', TEST_FACT_PACKAGES)
self.builder.build(scan_count=20, host_count=10)
'''
Create 10 hosts with 20 facts each. A single fact a year for 20 years.
After cleanup, there should be 10 facts for each host.
Create 10 hosts with 40 facts each. After cleanup, there should be 20 facts for each host.
Then ensure the correct facts are deleted.
'''
def test_cleanup_logic(self):
@ -162,17 +167,18 @@ class CleanupFactsUnitTest(BaseCommandMixin, BaseTest, MongoDBRequired):
granularity = relativedelta(years=2)
deleted_count = cleanup_facts.cleanup(self.builder.get_timestamp(0), granularity)
self.assertEqual(deleted_count, (self.builder.get_scan_count() * self.builder.get_host_count()) / 2)
self.assertEqual(deleted_count, 2 * (self.builder.get_scan_count() * self.builder.get_host_count()) / 2)
# Check the number of facts per host
for host in self.builder.get_hosts():
count = FactVersion.objects.filter(host=host).count()
self.assertEqual(count, self.builder.get_scan_count() / 2, "should have half the number of FactVersion per host for host %s")
scan_count = (2 * self.builder.get_scan_count()) / 2
self.assertEqual(count, scan_count)
count = Fact.objects.filter(host=host).count()
self.assertEqual(count, self.builder.get_scan_count() / 2, "should have half the number of Fact per host")
self.assertEqual(count, scan_count)
# Ensure that only 1 fact exists per granularity time
# Ensure that only 2 facts (ansible and packages) exists per granularity time
date_pivot = self.builder.get_timestamp(0)
for host in self.builder.get_hosts():
while date_pivot > fact_oldest.timestamp:
@ -183,11 +189,50 @@ class CleanupFactsUnitTest(BaseCommandMixin, BaseTest, MongoDBRequired):
'host': host,
}
count = FactVersion.objects.filter(**kv).count()
self.assertEqual(count, 1, "should only be 1 FactVersion per the 2 year granularity")
self.assertEqual(count, 2, "should only be 2 FactVersion per the 2 year granularity")
count = Fact.objects.filter(**kv).count()
self.assertEqual(count, 1, "should only be 1 Fact per the 2 year granularity")
self.assertEqual(count, 2, "should only be 2 Fact per the 2 year granularity")
date_pivot = date_pivot_next
'''
Create 10 hosts with 40 facts each. After cleanup, there should be 30 facts for each host.
Then ensure the correct facts are deleted.
'''
def test_cleanup_module(self):
cleanup_facts = CleanupFacts()
fact_oldest = FactVersion.objects.all().order_by('timestamp').first()
granularity = relativedelta(years=2)
deleted_count = cleanup_facts.cleanup(self.builder.get_timestamp(0), granularity, module='ansible')
self.assertEqual(deleted_count, (self.builder.get_scan_count() * self.builder.get_host_count()) / 2)
# Check the number of facts per host
for host in self.builder.get_hosts():
count = FactVersion.objects.filter(host=host).count()
self.assertEqual(count, 30)
count = Fact.objects.filter(host=host).count()
self.assertEqual(count, 30)
# Ensure that only 1 ansible fact exists per granularity time
date_pivot = self.builder.get_timestamp(0)
for host in self.builder.get_hosts():
while date_pivot > fact_oldest.timestamp:
date_pivot_next = date_pivot - granularity
kv = {
'timestamp__lte': date_pivot,
'timestamp__gt': date_pivot_next,
'host': host,
'module': 'ansible',
}
count = FactVersion.objects.filter(**kv).count()
self.assertEqual(count, 1)
count = Fact.objects.filter(**kv).count()
self.assertEqual(count, 1)
date_pivot = date_pivot_next

View File

@ -440,6 +440,10 @@ var tower = angular.module('Tower', [
}
}).
when('/inventories/:inventory_id/job_templates/', {
redirectTo: '/inventories/:inventory_id'
}).
when('/inventories/:inventory_id/job_templates/:template_id', {
name: 'inventoryJobTemplateEdit',
templateUrl: urlPrefix + 'partials/job_templates.html',

View File

@ -173,6 +173,7 @@ export default
// ignore
}
Alert('License Accepted', 'The Ansible Tower license was updated. To view or update license information in the future choose View License from the Account menu.','alert-info');
$rootScope.features = undefined;
$location.path('/home');
})
.error(function (data, status) {

View File

@ -29,6 +29,7 @@
@media screen and (min-width: (@menu-breakpoint + 1px)) {
padding: 0 20px;
padding-right: 23px;
}
&-menuContainer {

View File

@ -14,7 +14,7 @@ export default ['$route', '$rootScope', function($route, $rootScope) {
});
scope.$on('$routeChangeSuccess', function(e, nextRoute) {
if (nextRoute.$$route.name === routeName) {
if (nextRoute.$$route && nextRoute.$$route.name === routeName) {
element.addClass('MenuItem--active');
} else {
element.removeClass('MenuItem--active');

View File

@ -14,7 +14,7 @@ export default ['$scope', '$filter',
}
var sparkData =
recentJobs.map(function(job) {
_.sortBy(recentJobs.map(function(job) {
var data = {};
@ -28,10 +28,10 @@ export default ['$scope', '$filter',
data.jobId = job.id;
data.smartStatus = job.status;
data.finished = $filter('longDate')(job.finished);
data.finished = $filter('longDate')(job.finished) || "running";
return data;
});
}), "finished").reverse();
$scope.sparkArray = _.pluck(sparkData, 'value');
$scope.jobIds = _.pluck(sparkData, 'jobId');

View File

@ -18,10 +18,13 @@ export default [ function() {
//capitalize first letter
if (status) {
status = status.charAt(0).toUpperCase() + status.slice(1);
return "<div class=\"smart-status-tooltip\">Job ID: " +
var tooltip = "<div class=\"smart-status-tooltip\">Job ID: " +
options.userOptions.tooltipValueLookups.jobs[point.offset] +
"<br>Status: <span style=\"color: " + point.color + "\">&#9679;</span>"+status+
"<br>Finished: " + finished +"</div>" ;
"<br>Status: <span style=\"color: " + point.color + "\">&#9679;</span>"+status;
if (finished !== "running") {
tooltip += "<br>Finished: " + finished +"</div>" ;
}
return tooltip;
}
};

View File

@ -9,7 +9,9 @@ import compareFlatFacts from './compare-facts/flat';
export function compareFacts(module, facts) {
if (module.displayType === 'nested') {
return compareNestedFacts(facts);
return { factData: compareNestedFacts(facts),
isNestedDisplay: true
};
} else {
// For flat structures we compare left-to-right, then right-to-left to
// make sure we get a good comparison between both hosts

View File

@ -127,8 +127,8 @@ export function formatFacts(diffedResults) {
}
export function findFacts(factData) {
var rightData = factData[0];
var leftData = factData[1];
var rightData = factData[0].facts;
var leftData = factData[1].facts;
function factObject(keyPath, key, leftValue, rightValue) {
var obj =

View File

@ -45,11 +45,10 @@ function controller($rootScope,
$scope.leftHostname = hosts[0].name;
$scope.rightHostname = hosts.length > 1 ? hosts[1].name : hosts[0].name;
function reloadData(params, initialData) {
function reloadData(params) {
searchConfig = _.assign({}, searchConfig, params);
var factData = initialData;
var leftRange = searchConfig.leftRange;
var rightRange = searchConfig.rightRange;
var activeModule = searchConfig.module;
@ -80,9 +79,6 @@ function controller($rootScope,
// arrays in index 1
//
// Save the position of the data so we
// don't lose it later
var wrappedFacts =
facts.map(function(facts, index) {
return { position: index === 0 ? 'left' : 'right',

View File

@ -1984,3 +1984,7 @@ tr td button i {
.job-stdout-panel {
margin: 0 15px;
}
.panel-title {
font-weight: bold;
}

View File

@ -13,7 +13,7 @@ body {
font-family: 'Open Sans', sans-serif;
font-weight: 400;
color: @black;
padding-top: 75px;
padding-top: 58px;
}
#main-menu-container {

View File

@ -21,7 +21,7 @@
<div class="row">
<div class="panel panel-default job-stdout-panel">
<div class="panel-heading">
<h3 class="panel-title">{{ job.name }} standard out</h3>
<h3 class="panel-title">Standard Out</h3>
</div>
<div class="panel-body stdout-panel-body">
<div class="row">

View File

@ -146,7 +146,7 @@
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ job.name }} standard out</h3>
<h3 class="panel-title">Standard Out</h3>
</div>
<div class="panel-body stdout-panel-body">
<div class="row">