Fix issues with vars_prompt and vars_files
* Prompt had to be moved up, as it needed to be done before the first templating of the play occurs, otherwise vars_files won't be templated properly * Fixed a bug related to an earlier fix of vars_files incorporating extra vars to do the templating of the file name Fixes #11404
This commit is contained in:
parent
491a4f2a25
commit
4c733fe4b7
3 changed files with 76 additions and 69 deletions
|
@ -19,7 +19,9 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import getpass
|
||||||
import signal
|
import signal
|
||||||
|
import sys
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import *
|
from ansible.errors import *
|
||||||
|
@ -87,6 +89,25 @@ class PlaybookExecutor:
|
||||||
# clear any filters which may have been applied to the inventory
|
# clear any filters which may have been applied to the inventory
|
||||||
self._inventory.remove_restriction()
|
self._inventory.remove_restriction()
|
||||||
|
|
||||||
|
if play.vars_prompt:
|
||||||
|
for var in play.vars_prompt:
|
||||||
|
if 'name' not in var:
|
||||||
|
raise AnsibleError("'vars_prompt' item is missing 'name:'", obj=play._ds)
|
||||||
|
|
||||||
|
vname = var['name']
|
||||||
|
prompt = var.get("prompt", vname)
|
||||||
|
default = var.get("default", None)
|
||||||
|
private = var.get("private", True)
|
||||||
|
|
||||||
|
confirm = var.get("confirm", False)
|
||||||
|
encrypt = var.get("encrypt", None)
|
||||||
|
salt_size = var.get("salt_size", None)
|
||||||
|
salt = var.get("salt", None)
|
||||||
|
|
||||||
|
if vname not in play.vars:
|
||||||
|
self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
||||||
|
play.vars[vname] = self._do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
||||||
|
|
||||||
# Create a temporary copy of the play here, so we can run post_validate
|
# Create a temporary copy of the play here, so we can run post_validate
|
||||||
# on it without the templating changes affecting the original object.
|
# on it without the templating changes affecting the original object.
|
||||||
all_vars = self._variable_manager.get_vars(loader=self._loader, play=play)
|
all_vars = self._variable_manager.get_vars(loader=self._loader, play=play)
|
||||||
|
@ -233,3 +254,49 @@ class PlaybookExecutor:
|
||||||
serialized_batches.append(play_hosts)
|
serialized_batches.append(play_hosts)
|
||||||
|
|
||||||
return serialized_batches
|
return serialized_batches
|
||||||
|
|
||||||
|
def _do_var_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
||||||
|
|
||||||
|
if prompt and default is not None:
|
||||||
|
msg = "%s [%s]: " % (prompt, default)
|
||||||
|
elif prompt:
|
||||||
|
msg = "%s: " % prompt
|
||||||
|
else:
|
||||||
|
msg = 'input for %s: ' % varname
|
||||||
|
|
||||||
|
def do_prompt(prompt, private):
|
||||||
|
if sys.stdout.encoding:
|
||||||
|
msg = prompt.encode(sys.stdout.encoding)
|
||||||
|
else:
|
||||||
|
# when piping the output, or at other times when stdout
|
||||||
|
# may not be the standard file descriptor, the stdout
|
||||||
|
# encoding may not be set, so default to something sane
|
||||||
|
msg = prompt.encode(locale.getpreferredencoding())
|
||||||
|
if private:
|
||||||
|
return getpass.getpass(msg)
|
||||||
|
return raw_input(msg)
|
||||||
|
|
||||||
|
if confirm:
|
||||||
|
while True:
|
||||||
|
result = do_prompt(msg, private)
|
||||||
|
second = do_prompt("confirm " + msg, private)
|
||||||
|
if result == second:
|
||||||
|
break
|
||||||
|
display("***** VALUES ENTERED DO NOT MATCH ****")
|
||||||
|
else:
|
||||||
|
result = do_prompt(msg, private)
|
||||||
|
|
||||||
|
# if result is false and default is not None
|
||||||
|
if not result and default is not None:
|
||||||
|
result = default
|
||||||
|
|
||||||
|
# FIXME: make this work with vault or whatever this old method was
|
||||||
|
#if encrypt:
|
||||||
|
# result = utils.do_encrypt(result, encrypt, salt_size, salt)
|
||||||
|
|
||||||
|
# handle utf-8 chars
|
||||||
|
# FIXME: make this work
|
||||||
|
#result = to_unicode(result, errors='strict')
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import getpass
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
@ -155,50 +154,6 @@ class TaskQueueManager:
|
||||||
|
|
||||||
self._callbacks_loaded = True
|
self._callbacks_loaded = True
|
||||||
|
|
||||||
def _do_var_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
|
||||||
|
|
||||||
if prompt and default is not None:
|
|
||||||
msg = "%s [%s]: " % (prompt, default)
|
|
||||||
elif prompt:
|
|
||||||
msg = "%s: " % prompt
|
|
||||||
else:
|
|
||||||
msg = 'input for %s: ' % varname
|
|
||||||
|
|
||||||
def do_prompt(prompt, private):
|
|
||||||
if sys.stdout.encoding:
|
|
||||||
msg = prompt.encode(sys.stdout.encoding)
|
|
||||||
else:
|
|
||||||
# when piping the output, or at other times when stdout
|
|
||||||
# may not be the standard file descriptor, the stdout
|
|
||||||
# encoding may not be set, so default to something sane
|
|
||||||
msg = prompt.encode(locale.getpreferredencoding())
|
|
||||||
if private:
|
|
||||||
return getpass.getpass(msg)
|
|
||||||
return raw_input(msg)
|
|
||||||
|
|
||||||
if confirm:
|
|
||||||
while True:
|
|
||||||
result = do_prompt(msg, private)
|
|
||||||
second = do_prompt("confirm " + msg, private)
|
|
||||||
if result == second:
|
|
||||||
break
|
|
||||||
display("***** VALUES ENTERED DO NOT MATCH ****")
|
|
||||||
else:
|
|
||||||
result = do_prompt(msg, private)
|
|
||||||
|
|
||||||
# if result is false and default is not None
|
|
||||||
if not result and default is not None:
|
|
||||||
result = default
|
|
||||||
|
|
||||||
# FIXME: make this work with vault or whatever this old method was
|
|
||||||
#if encrypt:
|
|
||||||
# result = utils.do_encrypt(result, encrypt, salt_size, salt)
|
|
||||||
|
|
||||||
# handle utf-8 chars
|
|
||||||
# FIXME: make this work
|
|
||||||
#result = to_unicode(result, errors='strict')
|
|
||||||
return result
|
|
||||||
|
|
||||||
def run(self, play):
|
def run(self, play):
|
||||||
'''
|
'''
|
||||||
Iterates over the roles/tasks in a play, using the given (or default)
|
Iterates over the roles/tasks in a play, using the given (or default)
|
||||||
|
@ -211,25 +166,6 @@ class TaskQueueManager:
|
||||||
if not self._callbacks_loaded:
|
if not self._callbacks_loaded:
|
||||||
self.load_callbacks()
|
self.load_callbacks()
|
||||||
|
|
||||||
if play.vars_prompt:
|
|
||||||
for var in play.vars_prompt:
|
|
||||||
if 'name' not in var:
|
|
||||||
raise AnsibleError("'vars_prompt' item is missing 'name:'", obj=play._ds)
|
|
||||||
|
|
||||||
vname = var['name']
|
|
||||||
prompt = var.get("prompt", vname)
|
|
||||||
default = var.get("default", None)
|
|
||||||
private = var.get("private", True)
|
|
||||||
|
|
||||||
confirm = var.get("confirm", False)
|
|
||||||
encrypt = var.get("encrypt", None)
|
|
||||||
salt_size = var.get("salt_size", None)
|
|
||||||
salt = var.get("salt", None)
|
|
||||||
|
|
||||||
if vname not in play.vars:
|
|
||||||
self.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
|
||||||
play.vars[vname] = self._do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
|
||||||
|
|
||||||
all_vars = self._variable_manager.get_vars(loader=self._loader, play=play)
|
all_vars = self._variable_manager.get_vars(loader=self._loader, play=play)
|
||||||
templar = Templar(loader=self._loader, variables=all_vars)
|
templar = Templar(loader=self._loader, variables=all_vars)
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ import os
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections import MutableMapping
|
from collections import MutableMapping
|
||||||
|
|
||||||
|
from jinja2.exceptions import UndefinedError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -189,13 +191,13 @@ class VariableManager:
|
||||||
if play:
|
if play:
|
||||||
all_vars = self._combine_vars(all_vars, play.get_vars())
|
all_vars = self._combine_vars(all_vars, play.get_vars())
|
||||||
|
|
||||||
# create a set of temporary vars here, which incorporate any extra vars
|
|
||||||
# which may have been specified, so we can properly template vars_files
|
|
||||||
temp_vars = self._combine_vars(all_vars, self.extra_vars)
|
|
||||||
templar = Templar(loader=loader, variables=temp_vars)
|
|
||||||
|
|
||||||
for vars_file_item in play.get_vars_files():
|
for vars_file_item in play.get_vars_files():
|
||||||
try:
|
try:
|
||||||
|
# create a set of temporary vars here, which incorporate the
|
||||||
|
# extra vars so we can properly template the vars_files entries
|
||||||
|
temp_vars = self._combine_vars(all_vars, self._extra_vars)
|
||||||
|
templar = Templar(loader=loader, variables=temp_vars)
|
||||||
|
|
||||||
# we assume each item in the list is itself a list, as we
|
# we assume each item in the list is itself a list, as we
|
||||||
# support "conditional includes" for vars_files, which mimics
|
# support "conditional includes" for vars_files, which mimics
|
||||||
# the with_first_found mechanism.
|
# the with_first_found mechanism.
|
||||||
|
@ -218,6 +220,8 @@ class VariableManager:
|
||||||
# whether or not vars files errors should be fatal at this
|
# whether or not vars files errors should be fatal at this
|
||||||
# stage, or just base it on whether a host was specified?
|
# stage, or just base it on whether a host was specified?
|
||||||
pass
|
pass
|
||||||
|
except UndefinedError, e:
|
||||||
|
continue
|
||||||
|
|
||||||
if not C.DEFAULT_PRIVATE_ROLE_VARS:
|
if not C.DEFAULT_PRIVATE_ROLE_VARS:
|
||||||
for role in play.get_roles():
|
for role in play.get_roles():
|
||||||
|
|
Loading…
Reference in a new issue