Expose JOB_VARIABLE_PREFIXES as a configurable setting (#16452)

*  INCLUDE_AWX_VAR_PREFIX to USE_TOWER_VAR_PREFIX boolean toggle replace the include legacy prefix boolean with a tower-or-awx toggle USE_TOWER_VAR_PREFIX=True (default) emits only tower_ prefixed variables, false emits only awx_ (deprecated)

* Clean up dead constant and cache get_job_variable_prefixes() calls

* Revise tests to reflect new behavior

* Fix fragile fallback test to actually exercise getattr default

* Fix mock target for settings fallback test
This commit is contained in:
Lila Yasin
2026-05-26 16:43:50 -04:00
committed by GitHub
parent b37f3892b6
commit e4fa4810eb
9 changed files with 107 additions and 30 deletions

View File

@@ -8,7 +8,7 @@ from crum import impersonate
# AWX
from awx.main.models import UnifiedJobTemplate, Job, JobTemplate, WorkflowJobTemplate, Project, WorkflowJob, Schedule, Credential
from awx.api.versioning import reverse
from awx.main.constants import JOB_VARIABLE_PREFIXES
from awx.main.utils.common import get_job_variable_prefixes
@pytest.mark.django_db
@@ -160,7 +160,13 @@ class TestMetaVars:
job = Job.objects.create(name='job', created_by=admin_user)
job.save()
user_vars = ['_'.join(x) for x in itertools.product(['tower', 'awx'], ['user_name', 'user_id', 'user_email', 'user_first_name', 'user_last_name'])]
user_vars = [
'_'.join(x)
for x in itertools.product(
get_job_variable_prefixes(),
['user_name', 'user_id', 'user_email', 'user_first_name', 'user_last_name'],
)
]
for key in user_vars:
assert key in job.awx_meta_vars()
@@ -179,7 +185,7 @@ class TestMetaVars:
workflow_job.workflow_nodes.create(job=job)
data = job.awx_meta_vars()
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
assert data['{}_user_id'.format(name)] == admin_user.id
assert data['{}_user_name'.format(name)] == admin_user.username
assert data['{}_workflow_job_id'.format(name)] == workflow_job.pk
@@ -189,7 +195,7 @@ class TestMetaVars:
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()
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
assert data['{}_schedule_id'.format(name)] == schedule.pk
assert '{}_user_name'.format(name) not in data
@@ -201,7 +207,7 @@ class TestMetaVars:
job = Job.objects.create(launch_type='workflow')
workflow_job.workflow_nodes.create(job=job)
result_hash = {}
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
result_hash['{}_job_id'.format(name)] = job.id
result_hash['{}_job_launch_type'.format(name)] = 'workflow'
result_hash['{}_workflow_job_name'.format(name)] = 'workflow-job'

View File

@@ -1,7 +1,7 @@
from unittest import mock
from awx.main.models import UnifiedJob, UnifiedJobTemplate, WorkflowJob, WorkflowJobNode, WorkflowApprovalTemplate, Job, User, Project, JobTemplate, Inventory
from awx.main.constants import JOB_VARIABLE_PREFIXES
from awx.main.utils.common import get_job_variable_prefixes
def test_incorrectly_formatted_variables():
@@ -50,7 +50,7 @@ class TestMetaVars:
maker = User(username='joe', pk=47, id=47)
inv = Inventory(name='example-inv', id=45)
result_hash = {}
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
result_hash['{}_job_id'.format(name)] = 42
result_hash['{}_job_launch_type'.format(name)] = 'manual'
result_hash['{}_user_name'.format(name)] = 'joe'
@@ -75,8 +75,48 @@ class TestMetaVars:
project=Project(name='jobs-sync', scm_revision='12345444'),
job_template=JobTemplate(name='jobs-jt', id=92, pk=92),
).awx_meta_vars()
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
assert data['{}_project_revision'.format(name)] == '12345444'
assert '{}_job_template_id'.format(name) in data
assert data['{}_job_template_id'.format(name)] == 92
assert data['{}_job_template_name'.format(name)] == 'jobs-jt'
class TestGetJobVariablePrefixes:
"""Tests for the get_job_variable_prefixes() helper function."""
def test_default_returns_both(self):
from django.conf import settings
with mock.patch.object(settings, 'INCLUDE_DEPRECATED_AWX_VAR_PREFIX', True, create=True):
assert get_job_variable_prefixes() == ['awx', 'tower']
def test_disabled_returns_tower_only(self):
from django.conf import settings
with mock.patch.object(settings, 'INCLUDE_DEPRECATED_AWX_VAR_PREFIX', False, create=True):
assert get_job_variable_prefixes() == ['tower']
def test_fallback_when_setting_not_available(self):
"""When setting is not available, falls back to both prefixes for backward compatibility."""
fake_settings = mock.MagicMock(spec=[])
with mock.patch('django.conf.settings', fake_settings):
assert get_job_variable_prefixes() == ['awx', 'tower']
def test_job_metavars_both_prefixes(self):
"""With INCLUDE_DEPRECATED_AWX_VAR_PREFIX=True, both awx_ and tower_ variables."""
from django.conf import settings
with mock.patch.object(settings, 'INCLUDE_DEPRECATED_AWX_VAR_PREFIX', True, create=True):
data = Job(name='fake-job', pk=1, id=1, launch_type='manual').awx_meta_vars()
assert 'awx_job_id' in data
assert 'tower_job_id' in data
def test_job_metavars_tower_only(self):
"""With INCLUDE_DEPRECATED_AWX_VAR_PREFIX=False, only tower_ prefixed variables."""
from django.conf import settings
with mock.patch.object(settings, 'INCLUDE_DEPRECATED_AWX_VAR_PREFIX', False, create=True):
data = Job(name='fake-job', pk=1, id=1, launch_type='manual').awx_meta_vars()
assert 'tower_job_id' in data
assert 'awx_job_id' not in data

View File

@@ -37,7 +37,7 @@ from awx.main.utils import encrypt_field, encrypt_value
from awx.main.utils.safe_yaml import SafeLoader
from awx.main.utils.licensing import Licenser
from awx.main.constants import JOB_VARIABLE_PREFIXES
from awx.main.utils.common import get_job_variable_prefixes
from receptorctl.socket_interface import ReceptorControl
@@ -372,12 +372,12 @@ class TestExtraVarSanitation(TestJobExecution):
extra_vars = yaml.load(fd, Loader=SafeLoader)
# ensure that strings are marked as unsafe
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
for variable_name in ['_job_template_name', '_user_name', '_job_launch_type', '_project_revision', '_inventory_name']:
assert hasattr(extra_vars['{}{}'.format(name, variable_name)], '__UNSAFE__')
# ensure that non-strings are marked as safe
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
for variable_name in ['_job_template_id', '_job_id', '_user_id', '_inventory_id']:
assert not hasattr(extra_vars['{}{}'.format(name, variable_name)], '__UNSAFE__')
@@ -524,7 +524,7 @@ class TestGenericRun:
call_args, _ = task._write_extra_vars_file.call_args_list[0]
private_data_dir, extra_vars, safe_dict = call_args
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
assert extra_vars['{}_user_id'.format(name)] == 123
assert extra_vars['{}_user_name'.format(name)] == "angry-spud"
@@ -615,7 +615,7 @@ class TestAdhocRun(TestJobExecution):
call_args, _ = task._write_extra_vars_file.call_args_list[0]
private_data_dir, extra_vars = call_args
for name in JOB_VARIABLE_PREFIXES:
for name in get_job_variable_prefixes():
assert extra_vars['{}_user_id'.format(name)] == 123
assert extra_vars['{}_user_name'.format(name)] == "angry-spud"