From eecf997856736d3b5ac6b1c94c15cae7c96f5f39 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Mon, 4 Dec 2017 14:55:20 -0500 Subject: [PATCH] add AWX meta extra_vars: WFJT + schedule --- awx/main/models/jobs.py | 11 +++++ awx/main/models/unified_jobs.py | 41 ++++++++++++++-- awx/main/tasks.py | 27 +---------- .../functional/models/test_unified_job.py | 38 ++++++++++++++- .../tests/unit/models/test_survey_models.py | 1 + .../unit/models/test_unified_job_unit.py | 47 ++++++++++++++++++- 6 files changed, 135 insertions(+), 30 deletions(-) diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index a8dfa9388e..2e8902cc53 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -701,6 +701,17 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana return self.global_instance_groups return selected_groups + def awx_meta_vars(self): + r = super(Job, self).awx_meta_vars() + if self.project: + for name in ('awx', 'tower'): + r['{}_project_revision'.format(name)] = self.project.scm_revision + if self.job_template: + for name in ('awx', 'tower'): + r['{}_job_template_id'.format(name)] = self.job_template.pk + r['{}_job_template_name'.format(name)] = self.job_template.name + return r + ''' JobNotificationMixin ''' diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index 3e3a88246d..3f063f2731 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -854,15 +854,21 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique def result_stdout_limited(self, start_line=0, end_line=None, redact_sensitive=False): return self._result_stdout_raw_limited(start_line, end_line, redact_sensitive, escape_ascii=True) + @property + def workflow_job_id(self): + workflow_job = self.get_workflow_job() + if workflow_job: + return workflow_job.pk + return None + @property def spawned_by_workflow(self): return self.launch_type == 'workflow' - @property - def workflow_job_id(self): + def get_workflow_job(self): if self.spawned_by_workflow: try: - return self.unified_job_node.workflow_job.pk + return self.unified_job_node.workflow_job except UnifiedJob.unified_job_node.RelatedObjectDoesNotExist: pass return None @@ -1129,3 +1135,32 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique if default_instance_group.exists(): return [default_instance_group.first()] return [] + + def awx_meta_vars(self): + ''' + The result of this method is used as extra_vars of a job launched + by AWX, for purposes of client playbook hooks + ''' + r = {} + for name in ('awx', 'tower'): + r['{}_job_id'.format(name)] = self.pk + r['{}_job_launch_type'.format(name)] = self.launch_type + if self.created_by: + for name in ('awx', 'tower'): + r['{}_user_id'.format(name)] = self.created_by.pk + r['{}_user_name'.format(name)] = self.created_by.username + else: + wj = self.get_workflow_job() + if wj: + for name in ('awx', 'tower'): + r['{}_workflow_job_id'.format(name)] = wj.pk + r['{}_workflow_job_name'.format(name)] = wj.name + if wj.created_by: + for name in ('awx', 'tower'): + r['{}_user_id'.format(name)] = wj.created_by.pk + r['{}_user_name'.format(name)] = wj.created_by.username + if self.schedule: + for name in ('awx', 'tower'): + r['{}_schedule_id'.format(name)] = self.schedule.pk + r['{}_schedule_name'.format(name)] = self.schedule.name + return r diff --git a/awx/main/tasks.py b/awx/main/tasks.py index b3cc37c752..48e1a15509 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1145,31 +1145,8 @@ class RunJob(BaseTask): args.append('--start-at-task=%s' % job.start_at_task) # Define special extra_vars for AWX, combine with job.extra_vars. - extra_vars = { - 'tower_job_id': job.pk, - 'tower_job_launch_type': job.launch_type, - 'awx_job_id': job.pk, - 'awx_job_launch_type': job.launch_type, - } - if job.project: - extra_vars.update({ - 'tower_project_revision': job.project.scm_revision, - 'awx_project_revision': job.project.scm_revision, - }) - if job.job_template: - extra_vars.update({ - 'tower_job_template_id': job.job_template.pk, - 'tower_job_template_name': job.job_template.name, - 'awx_job_template_id': job.job_template.pk, - 'awx_job_template_name': job.job_template.name, - }) - if job.created_by: - extra_vars.update({ - 'tower_user_id': job.created_by.pk, - 'tower_user_name': job.created_by.username, - 'awx_user_id': job.created_by.pk, - 'awx_user_name': job.created_by.username, - }) + extra_vars = job.awx_meta_vars() + if job.extra_vars_dict: if kwargs.get('display', False) and job.job_template: extra_vars.update(json.loads(job.display_extra_vars())) diff --git a/awx/main/tests/functional/models/test_unified_job.py b/awx/main/tests/functional/models/test_unified_job.py index 13ff92877b..2532ce28fd 100644 --- a/awx/main/tests/functional/models/test_unified_job.py +++ b/awx/main/tests/functional/models/test_unified_job.py @@ -5,7 +5,7 @@ import mock from django.contrib.contenttypes.models import ContentType # AWX -from awx.main.models import UnifiedJobTemplate, Job, JobTemplate, WorkflowJobTemplate, Project +from awx.main.models import UnifiedJobTemplate, Job, JobTemplate, WorkflowJobTemplate, Project, WorkflowJob, Schedule from awx.main.models.ha import InstanceGroup @@ -110,3 +110,39 @@ class TestIsolatedRuns: link=success_callback, queue='thepentagon', task_id='something') + + +@pytest.mark.django_db +class TestMetaVars: + ''' + Extension of unit tests with same class name + ''' + + def test_workflow_job_metavars(self, admin_user): + workflow_job = WorkflowJob.objects.create( + name='workflow-job', + created_by=admin_user + ) + job = Job.objects.create( + name='fake-job', + launch_type='workflow' + ) + workflow_job.workflow_nodes.create(job=job) + data = job.awx_meta_vars() + assert data['awx_user_name'] == admin_user.username + assert data['awx_workflow_job_id'] == workflow_job.pk + + def test_scheduled_job_metavars(self, job_template, admin_user): + schedule = Schedule.objects.create( + name='job-schedule', + rrule='DTSTART:20171129T155939z\nFREQ=MONTHLY', + unified_job_template=job_template + ) + job = Job.objects.create( + name='fake-job', + launch_type='workflow', + schedule=schedule, + job_template=job_template + ) + data = job.awx_meta_vars() + assert data['awx_schedule_id'] == schedule.pk diff --git a/awx/main/tests/unit/models/test_survey_models.py b/awx/main/tests/unit/models/test_survey_models.py index cd42e8bb3d..882d90abe7 100644 --- a/awx/main/tests/unit/models/test_survey_models.py +++ b/awx/main/tests/unit/models/test_survey_models.py @@ -19,6 +19,7 @@ def job(mocker): 'pk': 1, 'job_template.pk': 1, 'job_template.name': '', 'created_by.pk': 1, 'created_by.username': 'admin', 'launch_type': 'manual', + 'awx_meta_vars.return_value': {}, 'inventory.get_script_data.return_value': {}}) ret.project = mocker.MagicMock(scm_revision='asdf1234') return ret diff --git a/awx/main/tests/unit/models/test_unified_job_unit.py b/awx/main/tests/unit/models/test_unified_job_unit.py index 62858ab032..d1d358c058 100644 --- a/awx/main/tests/unit/models/test_unified_job_unit.py +++ b/awx/main/tests/unit/models/test_unified_job_unit.py @@ -5,7 +5,10 @@ from awx.main.models import ( UnifiedJob, WorkflowJob, WorkflowJobNode, - Job + Job, + User, + Project, + JobTemplate ) @@ -61,3 +64,45 @@ def test_log_representation(): assert job.log_format == 'job 4 (running)' assert uj.log_format == 'unified_job 4 (running)' + +class TestMetaVars: + ''' + Corresponding functional test exists for cases with indirect relationships + ''' + + def test_job_metavars(self): + maker = User(username='joe', pk=47, id=47) + assert Job( + name='fake-job', + pk=42, id=42, + launch_type='manual', + created_by=maker + ).awx_meta_vars() == { + 'tower_job_id': 42, + 'awx_job_id': 42, + 'tower_job_launch_type': 'manual', + 'awx_job_launch_type': 'manual', + 'awx_user_name': 'joe', + 'tower_user_name': 'joe', + 'awx_user_id': 47, + 'tower_user_id': 47 + } + + def test_project_update_metavars(self): + data = Job( + name='fake-job', + pk=40, id=40, + launch_type='manual', + project=Project( + name='jobs-sync', + scm_revision='12345444' + ), + job_template=JobTemplate( + name='jobs-jt', + id=92, pk=92 + ) + ).awx_meta_vars() + assert data['awx_project_revision'] == '12345444' + assert 'tower_job_template_id' in data + assert data['tower_job_template_id'] == 92 + assert data['tower_job_template_name'] == 'jobs-jt'