Numerous model-related updates and supporing changes, including:

- Add variables field on Host/Group models and remove separate VariableData model.
- Add data migrations for existing variable data.
- Update views, serializers and tests to keep roughly the same API interface for variable data.
- Add has_active_failures properties on Group/Host models to provide indication of last job status.
- Add job_tags field on JobTemplate/Job models to specify tags to ansible-playbook.
- Add host_config_key field to JobTemplate model for use by empheral hosts.
- Add job_args, job_cwd and job_env fields to Job model to capture more info from running the job.
- Add failed flag on JobHostSummary model.
- Add play/task fields on JobEvent model to capture new context variables from callback.
- Add parent field on JobEvent model to capture hierarchy of job events.
- Add hosts field on JobEvent model to capture all hosts associated with the event (especially useful for parent events in the hierarchy).
- Removed existing Tag model, replace with django-taggit instead.
- Removed existing AuditLog model, replacement TBD.
This commit is contained in:
Chris Church
2013-06-10 17:21:04 -04:00
parent 7b0bbff376
commit cba55a061a
24 changed files with 1924 additions and 498 deletions

View File

@@ -111,23 +111,23 @@ class AcomInventoryTest(BaseCommandTest):
hosts = []
for x in xrange(10):
if n > 0:
variable_data = VariableData.objects.create(data=json.dumps({'ho': 'hum-%d' % x}))
variables = json.dumps({'ho': 'hum-%d' % x})
else:
variable_data = None
variables = ''
host = inventory.hosts.create(name='host-%02d-%02d.example.com' % (n, x),
inventory=inventory,
variable_data=variable_data)
variables=variables)
hosts.append(host)
self.hosts.extend(hosts)
groups = []
for x in xrange(5):
if n > 0:
variable_data = VariableData.objects.create(data=json.dumps({'gee': 'whiz-%d' % x}))
variables = json.dumps({'gee': 'whiz-%d' % x})
else:
variable_data = None
variables = ''
group = inventory.groups.create(name='group-%d' % x,
inventory=inventory,
variable_data=variable_data)
variables=variables)
groups.append(group)
group.hosts.add(hosts[x])
group.hosts.add(hosts[x + 5])
@@ -184,9 +184,9 @@ class AcomInventoryTest(BaseCommandTest):
group = inventory.groups.get(name=k)
self.assertEqual(set(v.get('hosts', [])),
set(group.hosts.values_list('name', flat=True)))
if group.variable_data:
if group.variables:
self.assertEqual(v.get('vars', {}),
json.loads(group.variable_data.data))
json.loads(group.variables))
if k == 'group-3':
self.assertEqual(set(v.get('children', [])),
set(group.children.values_list('name', flat=True)))
@@ -211,7 +211,7 @@ class AcomInventoryTest(BaseCommandTest):
host=host.name)
self.assertEqual(result, None)
data = json.loads(stdout)
self.assertEqual(data, json.loads(host.variable_data.data))
self.assertEqual(data, json.loads(host.variables))
def test_invalid_host(self):
# Valid host, but not part of the specified inventory.

View File

@@ -250,7 +250,7 @@ class InventoryTest(BaseTest):
# attempting to get a variable object creates it, even though it does not already exist
vdata_url = "/api/v1/hosts/%s/variable_data/" % (added_by_collection_a['id'])
got = self.get(vdata_url, expect=200, auth=self.get_super_credentials())
self.assertEquals(got, dict())
self.assertEquals(got, {})
# super user can create variable objects
# an org admin can create variable objects (defers to inventory permissions)
@@ -267,16 +267,16 @@ class InventoryTest(BaseTest):
self.put(vdata_url, data=vars_a, expect=403, auth=self.get_nobody_credentials())
# a normal user with inventory write permissions can edit variable objects
vdata_url = "/api/v1/hosts/1/variable_data/"
got = self.put(vdata_url, data=vars_b, expect=200, auth=self.get_normal_credentials())
self.assertEquals(got, vars_b)
#vdata_url = "/api/v1/hosts/1/variable_data/"
#got = self.put(vdata_url, data=vars_b, expect=200, auth=self.get_normal_credentials())
#self.assertEquals(got, vars_b)
# this URL is not one end users will use, but is what you get back from a put
# as a result, it also needs to be access controlled and working. You will not
# be able to put to it.
backend_url = '/api/v1/variable_data/1/'
got = self.get(backend_url, expect=200, auth=self.get_normal_credentials())
got = self.put(backend_url, data=dict(), expect=403, auth=self.get_super_credentials())
#backend_url = '/api/v1/variable_data/1/'
#got = self.get(backend_url, expect=200, auth=self.get_normal_credentials())
#got = self.put(backend_url, data=dict(), expect=403, auth=self.get_super_credentials())
###################################################
# VARIABLES -> GROUPS
@@ -443,7 +443,96 @@ class InventoryTest(BaseTest):
# on a group resource, I can see related resources for variables, inventories, and children
# and these work
def test_group_parents_and_children(self):
# Test for various levels of group parent/child relations, with hosts,
# to verify that helper properties return the correct querysets.
# Group A is parent of B, B is parent of C, C is parent of D. Group E
# is part of the inventory, but outside of the ABCD tree.
g_a = self.inventory_a.groups.create(name='A')
g_b = self.inventory_a.groups.create(name='B')
g_b.parents.add(g_a)
g_c = self.inventory_a.groups.create(name='C')
g_c.parents.add(g_b)
g_d = self.inventory_a.groups.create(name='D')
g_d.parents.add(g_c)
g_e = self.inventory_a.groups.create(name='E')
# Each group "X" contains one host "x".
h_a = self.inventory_a.hosts.create(name='a')
h_a.groups.add(g_a)
h_b = self.inventory_a.hosts.create(name='b')
h_b.groups.add(g_b)
h_c = self.inventory_a.hosts.create(name='c')
h_c.groups.add(g_c)
h_d = self.inventory_a.hosts.create(name='d')
h_d.groups.add(g_d)
h_e = self.inventory_a.hosts.create(name='e')
h_e.groups.add(g_e)
# Test all_children property on groups.
self.assertEqual(set(g_a.all_children.values_list('pk', flat=True)),
set([g_b.pk, g_c.pk, g_d.pk]))
self.assertEqual(set(g_b.all_children.values_list('pk', flat=True)),
set([g_c.pk, g_d.pk]))
self.assertEqual(set(g_c.all_children.values_list('pk', flat=True)),
set([g_d.pk]))
self.assertEqual(set(g_d.all_children.values_list('pk', flat=True)),
set([]))
self.assertEqual(set(g_e.all_children.values_list('pk', flat=True)),
set([]))
# Test all_parents property on groups.
self.assertEqual(set(g_a.all_parents.values_list('pk', flat=True)),
set([]))
self.assertEqual(set(g_b.all_parents.values_list('pk', flat=True)),
set([g_a.pk]))
self.assertEqual(set(g_c.all_parents.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk]))
self.assertEqual(set(g_d.all_parents.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk, g_c.pk]))
self.assertEqual(set(g_e.all_parents.values_list('pk', flat=True)),
set([]))
# Test all_hosts property on groups.
self.assertEqual(set(g_a.all_hosts.values_list('pk', flat=True)),
set([h_a.pk, h_b.pk, h_c.pk, h_d.pk]))
self.assertEqual(set(g_b.all_hosts.values_list('pk', flat=True)),
set([h_b.pk, h_c.pk, h_d.pk]))
self.assertEqual(set(g_c.all_hosts.values_list('pk', flat=True)),
set([h_c.pk, h_d.pk]))
self.assertEqual(set(g_d.all_hosts.values_list('pk', flat=True)),
set([h_d.pk]))
self.assertEqual(set(g_e.all_hosts.values_list('pk', flat=True)),
set([h_e.pk]))
# Test all_groups property on hosts.
self.assertEqual(set(h_a.all_groups.values_list('pk', flat=True)),
set([g_a.pk]))
self.assertEqual(set(h_b.all_groups.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk]))
self.assertEqual(set(h_c.all_groups.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk, g_c.pk]))
self.assertEqual(set(h_d.all_groups.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk, g_c.pk, g_d.pk]))
self.assertEqual(set(h_e.all_groups.values_list('pk', flat=True)),
set([g_e.pk]))
# Now create a circular relationship from D back to A.
g_a.parents.add(g_d)
# All groups "ABCD" should be parents of each other, and children of
# each other, and contain all hosts "abcd".
for g in [g_a, g_b, g_c, g_d]:
self.assertEqual(set(g.all_children.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk, g_c.pk, g_d.pk]))
self.assertEqual(set(g.all_parents.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk, g_c.pk, g_d.pk]))
self.assertEqual(set(g.all_hosts.values_list('pk', flat=True)),
set([h_a.pk, h_b.pk, h_c.pk, h_d.pk]))
# All hosts "abcd" should be members of all groups "ABCD".
for h in [h_a, h_b, h_c, h_d]:
self.assertEqual(set(h.all_groups.values_list('pk', flat=True)),
set([g_a.pk, g_b.pk, g_c.pk, g_d.pk]))
# Group E and host e should not be affected.
self.assertEqual(set(g_e.all_children.values_list('pk', flat=True)),
set([]))
self.assertEqual(set(g_e.all_parents.values_list('pk', flat=True)),
set([]))
self.assertEqual(set(g_e.all_hosts.values_list('pk', flat=True)),
set([h_e.pk]))
self.assertEqual(set(h_e.all_groups.values_list('pk', flat=True)),
set([g_e.pk]))

View File

@@ -779,7 +779,8 @@ class JobStartCancelTest(BaseJobTestMixin, django.test.TransactionTestCase):
self.assertFalse(response['passwords_needed_to_start'])
response = self.post(url, {}, expect=202)
job = Job.objects.get(pk=job.pk)
self.assertEqual(job.status, 'successful')
self.assertEqual(job.status, 'successful',
job.result_stdout)
else:
self.assertFalse(response['can_start'])
response = self.post(url, {}, expect=405)

View File

@@ -79,7 +79,7 @@ class OrganizationsTest(BaseTest):
# check that the related URL functionality works
related = response['results'][0]['related']
for x in [ 'audit_trail', 'projects', 'users', 'admins', 'tags' ]:
for x in ['projects', 'users', 'admins']:
self.assertTrue(x in related and related[x].endswith("/%s/" % x), "looking for %s in related" % x)
# normal credentials == 200, get only organizations of which user is a member
@@ -163,7 +163,8 @@ class OrganizationsTest(BaseTest):
org1_users = self.get(org1_users_url, expect=200, auth=self.get_super_credentials())
self.assertEquals(org1_users['count'], 1)
def test_get_item_subobjects_tags(self):
def _test_get_item_subobjects_tags(self):
# FIXME: Update to support taggit!
# put some tags on the org
org1 = Organization.objects.get(pk=2)
@@ -181,7 +182,8 @@ class OrganizationsTest(BaseTest):
self.assertEquals(org1_tags['count'], 2)
org1_tags = self.get(org1_tags_url, expect=403, auth=self.get_other_credentials())
def test_get_item_subobjects_audit_trail(self):
def _test_get_item_subobjects_audit_trail(self):
# FIXME: Update to support whatever audit trail framework is used.
url = '/api/v1/organizations/2/audit_trail/'
self.get(url, expect=200, auth=self.get_normal_credentials())
# FIXME: verify that some audit trail records are auto-created on save AND post
@@ -291,7 +293,8 @@ class OrganizationsTest(BaseTest):
admins = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEqual(admins['count'], 1)
def test_post_item_subobjects_tags(self):
def _test_post_item_subobjects_tags(self):
# FIXME: Update to support taggit!
tag = Tag.objects.create(name='blippy')
url = '/api/v1/organizations/2/tags/'
@@ -305,7 +308,8 @@ class OrganizationsTest(BaseTest):
tags = self.get(url, expect=200, auth=self.get_normal_credentials())
self.assertEqual(tags['count'], 0)
def test_post_item_subobjects_audit_trail(self):
def _test_post_item_subobjects_audit_trail(self):
# FIXME: Update to support whatever audit trail framework is used.
# audit trails are system things, and no user can post to them.
url = '/api/v1/organizations/2/audit_trail/'
self.post(url, dict(id=1), expect=405, auth=self.get_super_credentials())