AC-504 Capture role when available for job events.

This commit is contained in:
Chris Church
2014-04-15 00:22:57 -04:00
parent 1d417fe573
commit 2546cbdbb6
5 changed files with 81 additions and 16 deletions

View File

@@ -1328,7 +1328,7 @@ class JobEventSerializer(BaseSerializer):
model = JobEvent
fields = ('*', '-name', '-description', 'job', 'event',
'event_display', 'event_data', 'event_level', 'failed',
'changed', 'host', 'parent', 'play', 'task')
'changed', 'host', 'parent', 'play', 'task', 'role')
def get_related(self, obj):
res = super(JobEventSerializer, self).get_related(obj)

View File

@@ -512,7 +512,7 @@ class JobEvent(CreatedModifiedModel):
return reverse('api:job_event_detail', args=(self.pk,))
def __unicode__(self):
return u'%s @ %s' % (self.get_event_display(), self.created.isoformat())
return u'%s @ %s' % (self.get_event_display2(), self.created.isoformat())
@property
def event_level(self):
@@ -521,11 +521,14 @@ class JobEvent(CreatedModifiedModel):
def get_event_display2(self):
msg = self.get_event_display()
if self.event == 'playbook_on_play_start':
if self.play is not None:
if self.play:
msg = "%s (%s)" % (msg, self.play)
elif self.event == 'playbook_on_task_start':
if self.task is not None:
msg = "%s (%s)" % (msg, self.task)
if self.task:
if self.role:
msg = '%s (%s | %s)' % (msg, self.role, self.task)
else:
msg = "%s (%s)" % (msg, self.task)
# Change display for runner events trigged by async polling. Some of
# these events may not show in most cases, due to filterting them out
@@ -637,6 +640,9 @@ class JobEvent(CreatedModifiedModel):
self.task = self.event_data.get('task', '').strip()
if 'task' not in update_fields:
update_fields.append('task')
self.role = self.event_data.get('role', '').strip()
if 'role' not in update_fields:
update_fields.append('role')
# Only update job event hierarchy and related models during post
# processing (after running job).
post_process = kwargs.pop('post_process', False)

View File

@@ -126,7 +126,7 @@ class BaseTestMixin(object):
return results
def make_project(self, name, description='', created_by=None,
playbook_content=''):
playbook_content='', role_playbooks=None):
if not os.path.exists(settings.PROJECTS_ROOT):
os.makedirs(settings.PROJECTS_ROOT)
# Create temp project directory.
@@ -139,13 +139,24 @@ class BaseTestMixin(object):
test_playbook_file = os.fdopen(handle, 'w')
test_playbook_file.write(playbook_content)
test_playbook_file.close()
# Role playbooks are specified as a dict of role name and the
# content of tasks/main.yml playbook.
role_playbooks = role_playbooks or {}
for role_name, role_playbook_content in role_playbooks.items():
role_tasks_dir = os.path.join(project_dir, 'roles', role_name, 'tasks')
if not os.path.exists(role_tasks_dir):
os.makedirs(role_tasks_dir)
role_tasks_playbook_path = os.path.join(role_tasks_dir, 'main.yml')
with open(role_tasks_playbook_path, 'w') as f:
f.write(role_playbook_content)
return Project.objects.create(
name=name, description=description,
local_path=os.path.basename(project_dir), created_by=created_by,
#scm_type='git', default_playbook='foo.yml',
)
def make_projects(self, created_by, count=1, playbook_content=''):
def make_projects(self, created_by, count=1, playbook_content='',
role_playbooks=None):
results = []
for x in range(0, count):
self.object_ctr = self.object_ctr + 1
@@ -154,6 +165,7 @@ class BaseTestMixin(object):
description="proj%s" % x,
created_by=created_by,
playbook_content=playbook_content,
role_playbooks=role_playbooks,
))
return results

View File

@@ -88,6 +88,26 @@ TEST_ASYNC_NOWAIT_PLAYBOOK = '''
poll: 0
'''
TEST_PLAYBOOK_WITH_ROLES = '''
- hosts: test-group
gather_facts: false
roles:
- some_stuff
- more_stuff
- {role: stuff, tags: stuff}
'''
TEST_ROLE_PLAYBOOK = '''
- name: some task in a role
command: test 1 = 1
'''
TEST_ROLE_PLAYBOOKS = {
'some_stuff': TEST_ROLE_PLAYBOOK,
'more_stuff': TEST_ROLE_PLAYBOOK,
'stuff': TEST_ROLE_PLAYBOOK,
}
TEST_VAULT_PLAYBOOK = '''$ANSIBLE_VAULT;1.1;AES256
35623233333035633365383330323835353564346534363762366465316263363463396162656432
6562643539396330616265616532656466353639303338650a313466333663646431646663333739
@@ -230,8 +250,9 @@ class RunJobTest(BaseCeleryTest):
self.cloud_credential = Credential.objects.create(**opts)
return self.cloud_credential
def create_test_project(self, playbook_content):
self.project = self.make_projects(self.normal_django_user, 1, playbook_content)[0]
def create_test_project(self, playbook_content, role_playbooks=None):
self.project = self.make_projects(self.normal_django_user, 1,
playbook_content, role_playbooks)[0]
self.organization.projects.add(self.project)
def create_test_job_template(self, **kwargs):
@@ -299,7 +320,7 @@ class RunJobTest(BaseCeleryTest):
def check_job_events(self, job, runner_status='ok', plays=1, tasks=1,
async=False, async_timeout=False, async_nowait=False,
check_ignore_errors=False):
check_ignore_errors=False, has_roles=False):
job_events = job.job_events.all()
if False and async:
print
@@ -323,6 +344,7 @@ class RunJobTest(BaseCeleryTest):
self.assertFalse(evt.host, evt)
self.assertFalse(evt.play, evt)
self.assertFalse(evt.task, evt)
self.assertFalse(evt.role, evt)
self.assertEqual(evt.failed, should_be_failed)
if not async:
self.assertEqual(evt.changed, should_be_changed)
@@ -335,6 +357,7 @@ class RunJobTest(BaseCeleryTest):
self.assertFalse(evt.host, evt)
self.assertTrue(evt.play, evt)
self.assertFalse(evt.task, evt)
self.assertFalse(evt.role, evt)
self.assertEqual(evt.failed, should_be_failed)
if not async:
self.assertEqual(evt.changed, should_be_changed)
@@ -347,6 +370,10 @@ class RunJobTest(BaseCeleryTest):
self.assertFalse(evt.host, evt)
self.assertTrue(evt.play, evt)
self.assertTrue(evt.task, evt)
if has_roles:
self.assertTrue(evt.role, evt)
else:
self.assertFalse(evt.role, evt)
self.assertEqual(evt.failed, should_be_failed)
if not async:
self.assertEqual(evt.changed, should_be_changed)
@@ -367,6 +394,10 @@ class RunJobTest(BaseCeleryTest):
self.assertEqual(evt.host, self.host)
self.assertTrue(evt.play, evt)
self.assertTrue(evt.task, evt)
if has_roles:
self.assertTrue(evt.role, evt)
else:
self.assertFalse(evt.role, evt)
self.assertEqual(evt.failed, should_be_failed)
if not async:
self.assertEqual(evt.changed, should_be_changed)
@@ -1049,3 +1080,14 @@ class RunJobTest(BaseCeleryTest):
self.assertEqual(job.unreachable_hosts.count(), 0)
self.assertEqual(job.skipped_hosts.count(), 0)
self.assertEqual(job.processed_hosts.count(), 1)
def test_run_job_with_roles(self):
self.create_test_project(TEST_PLAYBOOK_WITH_ROLES, TEST_ROLE_PLAYBOOKS)
job_template = self.create_test_job_template()
job = self.create_test_job(job_template=job_template)
self.assertEqual(job.status, 'new')
self.assertFalse(job.passwords_needed_to_start)
self.assertTrue(job.signal_start())
job = Job.objects.get(pk=job.pk)
self.check_job_result(job, 'successful')
self.check_job_events(job, 'ok', 1, 3, has_roles=True)

View File

@@ -167,12 +167,17 @@ class CallbackModule(object):
response.raise_for_status()
def _log_event(self, event, **event_data):
play = getattr(getattr(self, 'play', None), 'name', '')
if play and event not in self.EVENTS_WITHOUT_PLAY:
event_data['play'] = play
task = getattr(getattr(self, 'task', None), 'name', '')
if task and event not in self.EVENTS_WITHOUT_TASK:
event_data['task'] = task
play = getattr(self, 'play', None)
play_name = getattr(play, 'name', '')
if play_name and event not in self.EVENTS_WITHOUT_PLAY:
event_data['play'] = play_name
task = getattr(self, 'task', None)
task_name = getattr(task, 'name', '')
role_name = getattr(task, 'role_name', '')
if task_name and event not in self.EVENTS_WITHOUT_TASK:
event_data['task'] = task_name
if role_name and event not in self.EVENTS_WITHOUT_TASK:
event_data['role'] = role_name
if self.callback_consumer_port:
self._post_job_event_queue_msg(event, event_data)
else: