mirror of
https://github.com/ansible/awx.git
synced 2026-02-13 09:45:50 -03:30
Merge pull request #1187 from ryanpetrello/file-your-vars-away-for-a-rainy-day
pass extra vars via file rather than via commandline
This commit is contained in:
@@ -654,11 +654,21 @@ class CredentialType(CommonModelNameNotUnique):
|
||||
extra_vars[var_name] = Template(tmpl).render(**namespace)
|
||||
safe_extra_vars[var_name] = Template(tmpl).render(**safe_namespace)
|
||||
|
||||
def build_extra_vars_file(vars, private_dir):
|
||||
handle, path = tempfile.mkstemp(dir = private_dir)
|
||||
f = os.fdopen(handle, 'w')
|
||||
f.write(json.dumps(vars))
|
||||
f.close()
|
||||
os.chmod(path, stat.S_IRUSR)
|
||||
return path
|
||||
|
||||
if extra_vars:
|
||||
args.extend(['-e', json.dumps(extra_vars)])
|
||||
path = build_extra_vars_file(extra_vars, private_data_dir)
|
||||
args.extend(['-e', '@%s' % path])
|
||||
|
||||
if safe_extra_vars:
|
||||
safe_args.extend(['-e', json.dumps(safe_extra_vars)])
|
||||
path = build_extra_vars_file(safe_extra_vars, private_data_dir)
|
||||
safe_args.extend(['-e', '@%s' % path])
|
||||
|
||||
|
||||
@CredentialType.default
|
||||
|
||||
@@ -727,6 +727,14 @@ class BaseTask(LogErrorsTask):
|
||||
'': '',
|
||||
}
|
||||
|
||||
def build_extra_vars_file(self, vars, **kwargs):
|
||||
handle, path = tempfile.mkstemp(dir=kwargs.get('private_data_dir', None))
|
||||
f = os.fdopen(handle, 'w')
|
||||
f.write(json.dumps(vars))
|
||||
f.close()
|
||||
os.chmod(path, stat.S_IRUSR)
|
||||
return path
|
||||
|
||||
def add_ansible_venv(self, venv_path, env, add_awx_lib=True):
|
||||
env['VIRTUAL_ENV'] = venv_path
|
||||
env['PATH'] = os.path.join(venv_path, "bin") + ":" + env['PATH']
|
||||
@@ -1236,7 +1244,8 @@ class RunJob(BaseTask):
|
||||
extra_vars.update(json.loads(job.display_extra_vars()))
|
||||
else:
|
||||
extra_vars.update(json.loads(job.decrypted_extra_vars()))
|
||||
args.extend(['-e', json.dumps(extra_vars)])
|
||||
extra_vars_path = self.build_extra_vars_file(vars=extra_vars, **kwargs)
|
||||
args.extend(['-e', '@%s' % (extra_vars_path)])
|
||||
|
||||
# Add path to playbook (relative to project.local_path).
|
||||
args.append(job.playbook)
|
||||
@@ -1466,7 +1475,8 @@ class RunProjectUpdate(BaseTask):
|
||||
'scm_revision_output': self.revision_path,
|
||||
'scm_revision': project_update.project.scm_revision,
|
||||
})
|
||||
args.extend(['-e', json.dumps(extra_vars)])
|
||||
extra_vars_path = self.build_extra_vars_file(vars=extra_vars, **kwargs)
|
||||
args.extend(['-e', '@%s' % (extra_vars_path)])
|
||||
args.append('project_update.yml')
|
||||
return args
|
||||
|
||||
@@ -2183,7 +2193,8 @@ class RunAdHocCommand(BaseTask):
|
||||
"{} are prohibited from use in ad hoc commands."
|
||||
).format(", ".join(removed_vars)))
|
||||
extra_vars.update(ad_hoc_command.extra_vars_dict)
|
||||
args.extend(['-e', json.dumps(extra_vars)])
|
||||
extra_vars_path = self.build_extra_vars_file(vars=extra_vars, **kwargs)
|
||||
args.extend(['-e', '@%s' % (extra_vars_path)])
|
||||
|
||||
args.extend(['-m', ad_hoc_command.module_name])
|
||||
args.extend(['-a', ad_hoc_command.module_args])
|
||||
|
||||
@@ -120,7 +120,9 @@ def test_job_safe_args_redacted_passwords(job):
|
||||
run_job = RunJob()
|
||||
safe_args = run_job.build_safe_args(job, **kwargs)
|
||||
ev_index = safe_args.index('-e') + 1
|
||||
extra_vars = json.loads(safe_args[ev_index])
|
||||
extra_var_file = open(safe_args[ev_index][1:], 'r')
|
||||
extra_vars = json.load(extra_var_file)
|
||||
extra_var_file.close()
|
||||
assert extra_vars['secret_key'] == '$encrypted$'
|
||||
|
||||
|
||||
@@ -129,7 +131,9 @@ def test_job_args_unredacted_passwords(job, tmpdir_factory):
|
||||
run_job = RunJob()
|
||||
args = run_job.build_args(job, **kwargs)
|
||||
ev_index = args.index('-e') + 1
|
||||
extra_vars = json.loads(args[ev_index])
|
||||
extra_var_file = open(args[ev_index][1:], 'r')
|
||||
extra_vars = json.load(extra_var_file)
|
||||
extra_var_file.close()
|
||||
assert extra_vars['secret_key'] == 'my_password'
|
||||
|
||||
|
||||
|
||||
@@ -174,6 +174,15 @@ def pytest_generate_tests(metafunc):
|
||||
)
|
||||
|
||||
|
||||
def parse_extra_vars(args):
|
||||
extra_vars = {}
|
||||
for chunk in args:
|
||||
if chunk.startswith('@/tmp/'):
|
||||
with open(chunk.strip('@'), 'r') as f:
|
||||
extra_vars.update(json.load(f))
|
||||
return extra_vars
|
||||
|
||||
|
||||
class TestJobExecution:
|
||||
"""
|
||||
For job runs, test that `ansible-playbook` is invoked with the proper
|
||||
@@ -318,15 +327,18 @@ class TestGenericRun(TestJobExecution):
|
||||
|
||||
def test_created_by_extra_vars(self):
|
||||
self.instance.created_by = User(pk=123, username='angry-spud')
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, _ = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
assert '"tower_user_id": 123,' in ' '.join(args)
|
||||
assert '"tower_user_name": "angry-spud"' in ' '.join(args)
|
||||
assert '"awx_user_id": 123,' in ' '.join(args)
|
||||
assert '"awx_user_name": "angry-spud"' in ' '.join(args)
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert extra_vars['tower_user_id'] == 123
|
||||
assert extra_vars['tower_user_name'] == "angry-spud"
|
||||
assert extra_vars['awx_user_id'] == 123
|
||||
assert extra_vars['awx_user_name'] == "angry-spud"
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
def test_survey_extra_vars(self):
|
||||
self.instance.extra_vars = json.dumps({
|
||||
@@ -335,12 +347,15 @@ class TestGenericRun(TestJobExecution):
|
||||
self.instance.survey_passwords = {
|
||||
'super_secret': '$encrypted$'
|
||||
}
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, _ = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
assert '"super_secret": "CLASSIFIED"' in ' '.join(args)
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert extra_vars['super_secret'] == "CLASSIFIED"
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
def test_awx_task_env(self):
|
||||
patch = mock.patch('awx.main.tasks.settings.AWX_TASK_ENV', {'FOO': 'BAR'})
|
||||
@@ -394,16 +409,19 @@ class TestAdhocRun(TestJobExecution):
|
||||
|
||||
def test_created_by_extra_vars(self):
|
||||
self.instance.created_by = User(pk=123, username='angry-spud')
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, _ = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
assert '"tower_user_id": 123,' in ' '.join(args)
|
||||
assert '"tower_user_name": "angry-spud"' in ' '.join(args)
|
||||
assert '"awx_user_id": 123,' in ' '.join(args)
|
||||
assert '"awx_user_name": "angry-spud"' in ' '.join(args)
|
||||
assert '"awx_foo": "awx-bar' in ' '.join(args)
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert extra_vars['tower_user_id'] == 123
|
||||
assert extra_vars['tower_user_name'] == "angry-spud"
|
||||
assert extra_vars['awx_user_id'] == 123
|
||||
assert extra_vars['awx_user_name'] == "angry-spud"
|
||||
assert extra_vars['awx_foo'] == "awx-bar"
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
|
||||
class TestIsolatedExecution(TestJobExecution):
|
||||
@@ -1082,14 +1100,16 @@ class TestJobCredentials(TestJobExecution):
|
||||
inputs = {'api_token': 'ABC123'}
|
||||
)
|
||||
self.instance.credentials.add(credential)
|
||||
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert extra_vars["api_token"] == "ABC123"
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, _ = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
|
||||
assert '-e {"api_token": "ABC123"}' in ' '.join(args)
|
||||
|
||||
def test_custom_environment_injectors_with_boolean_extra_vars(self):
|
||||
some_cloud = CredentialType(
|
||||
kind='cloud',
|
||||
@@ -1114,12 +1134,15 @@ class TestJobCredentials(TestJobExecution):
|
||||
inputs={'turbo_button': True}
|
||||
)
|
||||
self.instance.credentials.add(credential)
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, _ = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
assert '-e {"turbo_button": "True"}' in ' '.join(args)
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert extra_vars["turbo_button"] == "True"
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
def test_custom_environment_injectors_with_complicated_boolean_template(self):
|
||||
some_cloud = CredentialType(
|
||||
@@ -1145,12 +1168,15 @@ class TestJobCredentials(TestJobExecution):
|
||||
inputs={'turbo_button': True}
|
||||
)
|
||||
self.instance.credentials.add(credential)
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, _ = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
assert '-e {"turbo_button": "FAST!"}' in ' '.join(args)
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert extra_vars["turbo_button"] == "FAST!"
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
def test_custom_environment_injectors_with_secret_extra_vars(self):
|
||||
"""
|
||||
@@ -1181,13 +1207,16 @@ class TestJobCredentials(TestJobExecution):
|
||||
)
|
||||
credential.inputs['password'] = encrypt_field(credential, 'password')
|
||||
self.instance.credentials.add(credential)
|
||||
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert extra_vars["password"] == "SUPER-SECRET-123"
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, _ = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
|
||||
assert '-e {"password": "SUPER-SECRET-123"}' in ' '.join(args)
|
||||
assert 'SUPER-SECRET-123' not in json.dumps(self.task.update_model.call_args_list)
|
||||
|
||||
def test_custom_environment_injectors_with_file(self):
|
||||
@@ -1358,20 +1387,18 @@ class TestProjectUpdateCredentials(TestJobExecution):
|
||||
pk=1,
|
||||
credential_type=ssh,
|
||||
)
|
||||
|
||||
def run_pexpect_side_effect(*args, **kwargs):
|
||||
args, cwd, env, stdout = args
|
||||
extra_vars = parse_extra_vars(args)
|
||||
assert ' '.join(args).startswith('bwrap')
|
||||
assert ' '.join(['--bind', settings.PROJECTS_ROOT, settings.PROJECTS_ROOT]) in ' '.join(args)
|
||||
assert extra_vars["scm_revision_output"].startswith(settings.PROJECTS_ROOT)
|
||||
return ['successful', 0]
|
||||
|
||||
self.run_pexpect.side_effect = run_pexpect_side_effect
|
||||
self.task.run(self.pk)
|
||||
|
||||
assert self.run_pexpect.call_count == 1
|
||||
call_args, call_kwargs = self.run_pexpect.call_args_list[0]
|
||||
args, cwd, env, stdout = call_args
|
||||
|
||||
assert ' '.join(args).startswith('bwrap')
|
||||
' '.join([
|
||||
'--bind',
|
||||
settings.PROJECTS_ROOT,
|
||||
settings.PROJECTS_ROOT,
|
||||
]) in ' '.join(args)
|
||||
assert '"scm_revision_output": "/projects/tmp' in ' '.join(args)
|
||||
|
||||
def test_username_and_password_auth(self, scm_type):
|
||||
ssh = CredentialType.defaults['ssh']()
|
||||
self.instance.scm_type = scm_type
|
||||
|
||||
@@ -803,6 +803,8 @@ def wrap_args_with_proot(args, cwd, **kwargs):
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
path = os.path.realpath(path)
|
||||
if os.path.isdir(path):
|
||||
path = os.path.join(path, '') # add a trailing slash
|
||||
new_args.extend(['--bind', '%s' % (path,), '%s' % (path,)])
|
||||
if kwargs.get('isolated'):
|
||||
if 'ansible-playbook' in args:
|
||||
|
||||
Reference in New Issue
Block a user