added unsafe toggle to vars_prompt (#49219)
* added unsafe toggle to vars_prompt fixes #47534
This commit is contained in:
parent
4a0fceaa3b
commit
4ac0c23db6
7 changed files with 51 additions and 10 deletions
2
changelogs/fragments/unsafe_prompt.yml
Normal file
2
changelogs/fragments/unsafe_prompt.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- added 'unsafe' keyword to vars_prompt so users can signal 'template unsafe' content
|
|
@ -89,6 +89,16 @@ Depending on your platform at most the following crypt schemes are supported:
|
||||||
- *sha256_crypt* - SHA-256 Crypt
|
- *sha256_crypt* - SHA-256 Crypt
|
||||||
- *sha512_crypt* - SHA-512 Crypt
|
- *sha512_crypt* - SHA-512 Crypt
|
||||||
|
|
||||||
|
.. versionadded:: 2.8
|
||||||
|
|
||||||
|
If you need to put in special characters (i.e `{%`) that might create templating errors, use the ``unsafe`` option::
|
||||||
|
|
||||||
|
vars_prompt:
|
||||||
|
- name: "my_password_with_wierd_chars"
|
||||||
|
prompt: "Enter password"
|
||||||
|
unsafe: yes
|
||||||
|
private: yes
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
:doc:`playbooks`
|
:doc:`playbooks`
|
||||||
|
@ -101,6 +111,3 @@ Depending on your platform at most the following crypt schemes are supported:
|
||||||
Have a question? Stop by the google group!
|
Have a question? Stop by the google group!
|
||||||
`irc.freenode.net <http://irc.freenode.net>`_
|
`irc.freenode.net <http://irc.freenode.net>`_
|
||||||
#ansible IRC chat channel
|
#ansible IRC chat channel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,7 @@ class PlaybookExecutor:
|
||||||
templar = Templar(loader=self._loader, variables=all_vars)
|
templar = Templar(loader=self._loader, variables=all_vars)
|
||||||
setattr(play, 'vars_prompt', templar.template(play.vars_prompt))
|
setattr(play, 'vars_prompt', templar.template(play.vars_prompt))
|
||||||
|
|
||||||
|
# FIXME: this should be a play 'sub object' like loop_control
|
||||||
if play.vars_prompt:
|
if play.vars_prompt:
|
||||||
for var in play.vars_prompt:
|
for var in play.vars_prompt:
|
||||||
vname = var['name']
|
vname = var['name']
|
||||||
|
@ -121,11 +122,13 @@ class PlaybookExecutor:
|
||||||
encrypt = var.get("encrypt", None)
|
encrypt = var.get("encrypt", None)
|
||||||
salt_size = var.get("salt_size", None)
|
salt_size = var.get("salt_size", None)
|
||||||
salt = var.get("salt", None)
|
salt = var.get("salt", None)
|
||||||
|
unsafe = var.get("unsafe", None)
|
||||||
|
|
||||||
if vname not in self._variable_manager.extra_vars:
|
if vname not in self._variable_manager.extra_vars:
|
||||||
if self._tqm:
|
if self._tqm:
|
||||||
self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt,
|
||||||
play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
default, unsafe)
|
||||||
|
play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default, unsafe)
|
||||||
else: # we are either in --list-<option> or syntax check
|
else: # we are either in --list-<option> or syntax check
|
||||||
play.vars[vname] = default
|
play.vars[vname] = default
|
||||||
|
|
||||||
|
|
|
@ -303,7 +303,7 @@ class CallbackBase(AnsiblePlugin):
|
||||||
def playbook_on_task_start(self, name, is_conditional):
|
def playbook_on_task_start(self, name, is_conditional):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def playbook_on_setup(self):
|
def playbook_on_setup(self):
|
||||||
|
@ -387,8 +387,8 @@ class CallbackBase(AnsiblePlugin):
|
||||||
def v2_playbook_on_handler_task_start(self, task):
|
def v2_playbook_on_handler_task_start(self, task):
|
||||||
pass # no v1 correspondence
|
pass # no v1 correspondence
|
||||||
|
|
||||||
def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
|
||||||
self.playbook_on_vars_prompt(varname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
self.playbook_on_vars_prompt(varname, private, prompt, encrypt, confirm, salt_size, salt, default, unsafe)
|
||||||
|
|
||||||
# FIXME: not called
|
# FIXME: not called
|
||||||
def v2_playbook_on_import_for_host(self, result, imported_file):
|
def v2_playbook_on_import_for_host(self, result, imported_file):
|
||||||
|
|
|
@ -39,7 +39,7 @@ from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible.module_utils.six import with_metaclass
|
from ansible.module_utils.six import with_metaclass
|
||||||
from ansible.utils.color import stringc
|
from ansible.utils.color import stringc
|
||||||
from ansible.utils.singleton import Singleton
|
from ansible.utils.singleton import Singleton
|
||||||
|
from ansible.utils.unsafe_proxy import wrap_var
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Python 2
|
# Python 2
|
||||||
|
@ -305,7 +305,7 @@ class Display(with_metaclass(Singleton, object)):
|
||||||
else:
|
else:
|
||||||
return input(prompt_string)
|
return input(prompt_string)
|
||||||
|
|
||||||
def do_var_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
def do_var_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
|
||||||
|
|
||||||
result = None
|
result = None
|
||||||
if sys.__stdin__.isatty():
|
if sys.__stdin__.isatty():
|
||||||
|
@ -343,6 +343,9 @@ class Display(with_metaclass(Singleton, object)):
|
||||||
|
|
||||||
# handle utf-8 chars
|
# handle utf-8 chars
|
||||||
result = to_text(result, errors='surrogate_or_strict')
|
result = to_text(result, errors='surrogate_or_strict')
|
||||||
|
|
||||||
|
if unsafe:
|
||||||
|
result = wrap_var(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -109,6 +109,12 @@ tests = [
|
||||||
'test_spec': [
|
'test_spec': [
|
||||||
[('prompting for host:', 'testhost\r')],
|
[('prompting for host:', 'testhost\r')],
|
||||||
r'testhost.*ok=1']},
|
r'testhost.*ok=1']},
|
||||||
|
|
||||||
|
# Test play unsafe toggle
|
||||||
|
{'playbook': 'unsafe.yml',
|
||||||
|
'test_spec': [
|
||||||
|
[('prompting for variable:', '{{whole}}\r')],
|
||||||
|
r'testhost.*ok=2']},
|
||||||
]
|
]
|
||||||
|
|
||||||
for t in tests:
|
for t in tests:
|
||||||
|
|
20
test/integration/targets/vars_prompt/unsafe.yml
Normal file
20
test/integration/targets/vars_prompt/unsafe.yml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
- name: Test vars_prompt unsafe
|
||||||
|
hosts: testhost
|
||||||
|
become: no
|
||||||
|
gather_facts: no
|
||||||
|
vars:
|
||||||
|
whole: INVALID
|
||||||
|
vars_prompt:
|
||||||
|
- name: input
|
||||||
|
prompt: prompting for variable
|
||||||
|
unsafe: true
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name:
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- input != whole
|
||||||
|
- input != 'INVALID'
|
||||||
|
|
||||||
|
- debug:
|
||||||
|
var: input
|
Loading…
Reference in a new issue