1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

cleanup example config file + Squashed commit of the following:

commit c36b66dc952dfff91043ecbca56cf3f1f8f00703
Merge: 240d7bf f4cf934
Author: Michael DeHaan <michael@ansibleworks.com>
Date:   Tue Jun 18 13:04:51 2013 -0400

    Merge branch 'unevaluated-vars' of git://github.com/lorin/ansible into lorin_undefined

    Conflicts:
    	lib/ansible/runner/__init__.py

commit f4cf93436767f73b62a16067ab5e628830045896
Merge: 2531440 07a1365
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Thu Jun 6 11:07:41 2013 -0400

    Merge branch 'devel' into unevaluated-vars

commit 253144045cbafd7d72836f1017c62ac4ba623186
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Thu Jun 6 11:06:37 2013 -0400

    Fail template from file on undefined vars

    If config option is set, raise an exception if templating from a
    file and a variable is undefined.

commit aecb71d8b75257f0f3e11a9b176fc3737aecef8d
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Wed Jun 5 17:12:12 2013 -0400

    Add fail_on_undefined flag

    Add a fail_on_undefined flag to the template and template_from_string methods.

    If this flag is true, then re-raise the ninja2.excpetions.UndefinedError instead of
    swallowing it.

commit cbb1808f0585f01536240aee05a1bfd06c4b4647
Merge: d4bbf49 41425fb
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Wed Jun 5 16:14:12 2013 -0400

    Merge branch 'devel' into unevaluated-vars

commit d4bbf492b0b63c789d66ab60d0ec634d100fca82
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Mon Jun 3 19:46:13 2013 -0400

    template: Raise UndefinedError exception

    In template_from_string, raise an undefined error if it occurs.

    Have the caller catch it and throw an AnsibleUndefinedVariable

commit c94780280515f1f3756fdc429b2b1e87b365e9b7
Merge: 8d919d6 be33bcf
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Mon Jun 3 10:09:43 2013 -0400

    Merge branch 'devel' into unevaluated-vars

commit 8d919d6c97b28a42f47ca7248c542695baf6175f
Merge: 0f68ad8 b8630d2
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Thu May 30 16:27:48 2013 -0400

    Merge branch 'devel' into unevaluated-vars

commit 0f68ad8193ac17488e339a258f8c63fdae399c26
Author: Lorin Hochstein <lorin@nimbisservices.com>
Date:   Thu May 30 14:32:03 2013 -0400

    Optionally fail task on undefined variables

    This patch introduces a new configuration option called
    error_on_undefined_vars, which defaults to false.

    If this option is set to true, then a task which has unevaluated
    variables in its arguments will fail instead of running. Output looks
    like this:

        TASK: [set rabbitmq password] *************************************************
        fatal: [10.20.0.7] => Undefined variables: rabbitmq_user, rabbitmq_password
This commit is contained in:
Michael DeHaan 2013-06-18 13:24:30 -04:00
parent 240d7bf197
commit 637983cf31
5 changed files with 102 additions and 144 deletions

View file

@ -1,138 +1,75 @@
# config file for ansible -- http://ansible.github.com # config file for ansible -- http://ansibleworks.com/
# # ==================================================
# nearly all parameters can be overridden in ansible-playbook or with command line flags
# ansible will read ~/.ansible.cfg, ansible.cfg in the current working directory or # nearly all parameters can be overridden in ansible-playbook
# or with command line flags. ansible will read ~/.ansible.cfg,
# ansible.cfg in the current working directory or
# /etc/ansible/ansible.cfg, whichever it finds first # /etc/ansible/ansible.cfg, whichever it finds first
[defaults] [defaults]
# location of inventory file, eliminates need to specify -i # some basic default values...
hostfile = /etc/ansible/hosts hostfile = /etc/ansible/hosts
library = /usr/share/ansible
remote_tmp = $HOME/.ansible/tmp
pattern = *
forks = 5
poll_interval = 15
sudo_user = root
#ask_sudo_pass = True
#ask_pass = True
transport = paramiko
remote_port = 22
# location of ansible library, eliminates need to specify --module-path # change this for alternative sudo implementations
sudo_exe = sudo
library = /usr/share/ansible # what flags to pass to sudo
# default module name used in /usr/bin/ansible when -m is not specified
module_name = command
# location for ansible log file. If set, will store output from ansible
# and ansible-playbook. If enabling, you may wish to configure
# logrotate.
#log_path = /var/log/ansible.log
# home directory where temp files are stored on remote systems. Should
# almost always contain $HOME or be a directory writeable by all users
remote_tmp = $HOME/.ansible/tmp
# the default pattern for ansible-playbooks ("hosts:")
pattern = *
# the default number of forks (parallelism) to be used. Usually you
# can crank this up.
forks=5
# the timeout used by various connection types. Usually this corresponds
# to an SSH timeout
timeout=10
# when using --poll or "poll:" in an ansible playbook, and not specifying
# an explicit poll interval, use this interval
poll_interval=15
# when specifying --sudo to /usr/bin/ansible or "sudo:" in a playbook,
# and not specifying "--sudo-user" or "sudo_user" respectively, sudo
# to this user account
sudo_user=root
# the following forces ansible to always ask for the sudo password (instead of having
# to add -K to the commandline). Or you can use the environment variable (ANSIBLE_ASK_SUDO_PASS)
#ask_sudo_pass=True
# the following forces ansible to always ask for the ssh-password (-k)
# can also be set by the environment variable ANSIBLE_ASK_PASS
#ask_pass=True
# connection to use when -c <connection_type> is not specified
transport=paramiko
# remote SSH port to be used when --port or "port:" or an equivalent inventory
# variable is not specified.
remote_port=22
# if set, always run /usr/bin/ansible commands as this user, and assume this value
# if "user:" is not set in a playbook. If not set, use the current Unix user
# as the default
#remote_user=root
# the default sudo executable. If a sudo alternative with a sudo-compatible interface
# is used, specify its executable name as the default
sudo_exe=sudo
# the default flags passed to sudo
# sudo_flags=-H # sudo_flags=-H
# all commands executed under sudo are passed as arguments to a shell command # SSH timeout
# This shell command defaults to /bin/sh timeout = 10
# Changing this helps the situation where a user is only allowed to run
# e.g. /bin/bash with sudo privileges
# default user to use for playbooks if user is not specified
# (/usr/bin/ansible will use current user as default)
remote_user=root
# logging is off by default unless this path is defined
# if so defined, consider logrotate
# log_path = /var/log/ansible.log
# default module name for /usr/bin/ansible
module_name = command
# use this shell for commands executed under sudo
# you may need to change this to bin/bash in rare instances
# if sudo is constrained
# executable = /bin/sh # executable = /bin/sh
# how to handle hash defined in several places # if inventory variables overlap, does the higher precedence one win
# hash can be merged, or replaced # or are hash values merged together? The default is 'replace' but
# if you use replace, and have multiple hashes named 'x', the last defined # this can also be set to 'merge'.
# will override the previously defined one
# if you use merge here, hash will cumulate their keys, but keys will still
# override each other
# replace is the default value, and is how ansible always handled hash variables
#
# hash_behaviour=replace # hash_behaviour=replace
# How to handle variable replacement - as of 1.2, Jinja2 variable syntax is # How to handle variable replacement - as of 1.2, Jinja2 variable syntax is
# preferred, but we still support the old $variable replacement too. # preferred, but we still support the old $variable replacement too.
# If you change legacy_playbook_variables to no then Ansible will no longer # Turn off ${old_style} variables here if you like.
# try to do replacement on $variable style variables.
#
# legacy_playbook_variables=yes # legacy_playbook_variables=yes
# if you need to use jinja2 extensions, you can list them here # list any Jinja2 extensions to enable here:
# use a coma to separate extensions, e.g. :
# jinja2_extensions=jinja2.ext.do,jinja2.ext.i18n # jinja2_extensions=jinja2.ext.do,jinja2.ext.i18n
# no extensions are loaded by default
#jinja2_extensions=
# if set, always use this private key file for authentication, same as if passing
# --private-key to ansible or ansible-playbook
# if set, always use this private key file for authentication, same as
# if passing --private-key to ansible or ansible-playbook
#private_key_file=/path/to/file #private_key_file=/path/to/file
# format of string $ansible_managed available within Jinja2 templates, replacing # format of string {{ ansible_managed }} available within Jinja2
# {file}, {host} and {uid} with template filename, host and owner respectively. # templates indicates to users editing templates files will be replaced.
# The resulting string is passed through strftime(3) so it may contain any , replacing {file}, {host} and {uid} and strftime codes with proper values.
# time-formatting specifiers.
#
# Example: ansible_managed = DONT TOUCH {file}: call {uid} at {host} for changes
ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host} ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}
# additional plugin paths for non-core plugins # set plugin path directories here, seperate with colons
action_plugins = /usr/share/ansible_plugins/action_plugins action_plugins = /usr/share/ansible_plugins/action_plugins
callback_plugins = /usr/share/ansible_plugins/callback_plugins callback_plugins = /usr/share/ansible_plugins/callback_plugins
connection_plugins = /usr/share/ansible_plugins/connection_plugins connection_plugins = /usr/share/ansible_plugins/connection_plugins
@ -140,24 +77,23 @@ lookup_plugins = /usr/share/ansible_plugins/lookup_plugins
vars_plugins = /usr/share/ansible_plugins/vars_plugins vars_plugins = /usr/share/ansible_plugins/vars_plugins
filter_plugins = /usr/share/ansible_plugins/filter_plugins filter_plugins = /usr/share/ansible_plugins/filter_plugins
# set to 1 if you don't want cowsay support. Alternatively, set ANSIBLE_NOCOWS=1 # don't like cows? that's unfortunate.
# in your environment # set to 1 if you don't want cowsay support or export ANSIBLE_NOCOWS=1
# nocows = 1 # nocows = 1
[paramiko_connection] [paramiko_connection]
# nothing to configure yet # nothing configurable yet
[ssh_connection] [ssh_connection]
# if uncommented, sets the ansible ssh arguments to the following. Leaving off ControlPersist # ssh arguments to use
# will result in poor performance, so use transport=paramiko on older platforms rather than # Leaving off ControlPersist will result in poor performance, so use
# removing it # paramiko on older platforms rather than removing it
ssh_args=-o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r ssh_args=-o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r
# the following makes ansible use scp if the connection type is ssh (default is sftp) # if True, make ansible use scp if the connection type is ssh
# (default is sftp)
#scp_if_ssh=True #scp_if_ssh=True

View file

@ -110,6 +110,8 @@ ANSIBLE_NOCOWS = get_config(p, DEFAULTS, 'nocows', 'ANSIBLE_NOCO
ANSIBLE_SSH_ARGS = get_config(p, 'ssh_connection', 'ssh_args', 'ANSIBLE_SSH_ARGS', None) ANSIBLE_SSH_ARGS = get_config(p, 'ssh_connection', 'ssh_args', 'ANSIBLE_SSH_ARGS', None)
ZEROMQ_PORT = int(get_config(p, 'fireball', 'zeromq_port', 'ANSIBLE_ZEROMQ_PORT', 5099)) ZEROMQ_PORT = int(get_config(p, 'fireball', 'zeromq_port', 'ANSIBLE_ZEROMQ_PORT', 5099))
DEFAULT_UNDEFINED_VAR_BEHAVIOR = get_config(p, DEFAULTS, 'error_on_undefined_vars', 'ANSIBLE_ERROR_ON_UNDEFINED_VARS', False)
# non-configurable things # non-configurable things
DEFAULT_SUDO_PASS = None DEFAULT_SUDO_PASS = None
DEFAULT_REMOTE_PASS = None DEFAULT_REMOTE_PASS = None

View file

@ -32,3 +32,6 @@ class AnsibleConnectionFailed(AnsibleError):
class AnsibleYAMLValidationFailed(AnsibleError): class AnsibleYAMLValidationFailed(AnsibleError):
pass pass
class AnsibleUndefinedVariable(AnsibleError):
pass

View file

@ -30,6 +30,7 @@ import base64
import sys import sys
import shlex import shlex
import pipes import pipes
import jinja2
import ansible.constants as C import ansible.constants as C
import ansible.inventory import ansible.inventory
@ -128,7 +129,8 @@ class Runner(object):
check=False, # don't make any changes, just try to probe for potential changes check=False, # don't make any changes, just try to probe for potential changes
diff=False, # whether to show diffs for template files that change diff=False, # whether to show diffs for template files that change
environment=None, # environment variables (as dict) to use inside the command environment=None, # environment variables (as dict) to use inside the command
complex_args=None # structured data in addition to module_args, must be a dict complex_args=None, # structured data in addition to module_args, must be a dict
error_on_undefined_vars=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR # ex. False
): ):
if not complex_args: if not complex_args:
@ -164,6 +166,7 @@ class Runner(object):
self.environment = environment self.environment = environment
self.complex_args = complex_args self.complex_args = complex_args
self.module_with_list = False self.module_with_list = False
self.error_on_undefined_vars = error_on_undefined_vars
self.callbacks.runner = self self.callbacks.runner = self
@ -446,11 +449,11 @@ class Runner(object):
if type(complex_args) != dict: if type(complex_args) != dict:
raise errors.AnsibleError("args must be a dictionary, received %s" % complex_args) raise errors.AnsibleError("args must be a dictionary, received %s" % complex_args)
result = self._executor_internal_inner( result = self._executor_internal_inner(
host, host,
self.module_name, self.module_name,
self.module_args, self.module_args,
inject, inject,
port, port,
complex_args=complex_args complex_args=complex_args
) )
results.append(result.result) results.append(result.result)
@ -576,8 +579,12 @@ class Runner(object):
tmp = self._make_tmp_path(conn) tmp = self._make_tmp_path(conn)
# render module_args and complex_args templates # render module_args and complex_args templates
module_args = template.template(self.basedir, module_args, inject) try:
complex_args = template.template(self.basedir, complex_args, inject) module_args = template.template(self.basedir, module_args, inject, fail_on_undefined=self.error_on_undefined_vars)
complex_args = template.template(self.basedir, complex_args, inject, fail_on_undefined=self.error_on_undefined_vars)
except jinja2.exceptions.UndefinedError, e:
raise errors.AnsibleUndefinedVariable("Undefined variables: %s" % str(e))
result = handler.run(conn, tmp, module_name, module_args, inject, complex_args) result = handler.run(conn, tmp, module_name, module_args, inject, complex_args)
@ -644,7 +651,7 @@ class Runner(object):
path = pipes.quote(path) path = pipes.quote(path)
# The following test needs to be SH-compliant. BASH-isms will # The following test needs to be SH-compliant. BASH-isms will
# not work if /bin/sh points to a non-BASH shell. # not work if /bin/sh points to a non-BASH shell.
test = "rc=0; [ -r \"%s\" ] || rc=2; [ -f \"%s\" ] || rc=1; [ -d \"%s\" ] && rc=3" % ((path,) * 3) test = "rc=0; [ -r \"%s\" ] || rc=2; [ -f \"%s\" ] || rc=1; [ -d \"%s\" ] && rc=3" % ((path,) * 3)
md5s = [ md5s = [
"(/usr/bin/md5sum %s 2>/dev/null)" % path, # Linux "(/usr/bin/md5sum %s 2>/dev/null)" % path, # Linux
"(/sbin/md5sum -q %s 2>/dev/null)" % path, # ? "(/sbin/md5sum -q %s 2>/dev/null)" % path, # ?

View file

@ -34,7 +34,7 @@ class Globals(object):
FILTERS = None FILTERS = None
def __init__(self): def __init__(self):
pass pass
def _get_filters(): def _get_filters():
''' return filter plugin instances ''' ''' return filter plugin instances '''
@ -48,7 +48,7 @@ def _get_filters():
for fp in plugins: for fp in plugins:
filters.update(fp.filters()) filters.update(fp.filters())
Globals.FILTERS = filters Globals.FILTERS = filters
return Globals.FILTERS return Globals.FILTERS
def _get_extensions(): def _get_extensions():
@ -90,7 +90,7 @@ def lookup(name, *args, **kwargs):
def _legacy_varFindLimitSpace(basedir, vars, space, part, lookup_fatal, depth, expand_lists): def _legacy_varFindLimitSpace(basedir, vars, space, part, lookup_fatal, depth, expand_lists):
''' limits the search space of space to part ''' limits the search space of space to part
basically does space.get(part, None), but with basically does space.get(part, None), but with
templating for part and a few more things templating for part and a few more things
''' '''
@ -295,7 +295,7 @@ def legacy_varReplace(basedir, raw, vars, lookup_fatal=True, depth=0, expand_lis
# TODO: varname is misnamed here # TODO: varname is misnamed here
def template(basedir, varname, vars, lookup_fatal=True, depth=0, expand_lists=True, convert_bare=False): def template(basedir, varname, vars, lookup_fatal=True, depth=0, expand_lists=True, convert_bare=False, fail_on_undefined=False):
''' templates a data structure by traversing it and substituting for other data structures ''' ''' templates a data structure by traversing it and substituting for other data structures '''
if convert_bare and isinstance(varname, basestring): if convert_bare and isinstance(varname, basestring):
@ -305,7 +305,7 @@ def template(basedir, varname, vars, lookup_fatal=True, depth=0, expand_lists=Tr
if isinstance(varname, basestring): if isinstance(varname, basestring):
if '{{' in varname or '{%' in varname: if '{{' in varname or '{%' in varname:
varname = template_from_string(basedir, varname, vars) varname = template_from_string(basedir, varname, vars, fail_on_undefined)
if not '$' in varname: if not '$' in varname:
return varname return varname
@ -341,7 +341,7 @@ class _jinja2_vars(object):
is avoiding duplicating the large hashes that inject tends to be. is avoiding duplicating the large hashes that inject tends to be.
To facilitate using builtin jinja2 things like range, globals are handled To facilitate using builtin jinja2 things like range, globals are handled
here. here.
extras is a list of locals to also search for variables. extras is a list of locals to also search for variables.
''' '''
def __init__(self, basedir, vars, globals, *extras): def __init__(self, basedir, vars, globals, *extras):
@ -398,6 +398,8 @@ class J2Template(jinja2.environment.Template):
def template_from_file(basedir, path, vars): def template_from_file(basedir, path, vars):
''' run a file through the templating engine ''' ''' run a file through the templating engine '''
fail_on_undefined = C.DEFAULT_UNDEFINED_VAR_BEHAVIOR
from ansible import utils from ansible import utils
realpath = utils.path_dwim(basedir, path) realpath = utils.path_dwim(basedir, path)
loader=jinja2.FileSystemLoader([basedir,os.path.dirname(realpath)]) loader=jinja2.FileSystemLoader([basedir,os.path.dirname(realpath)])
@ -409,6 +411,8 @@ def template_from_file(basedir, path, vars):
environment = jinja2.Environment(loader=loader, trim_blocks=True, extensions=_get_extensions()) environment = jinja2.Environment(loader=loader, trim_blocks=True, extensions=_get_extensions())
environment.filters.update(_get_filters()) environment.filters.update(_get_filters())
environment.globals['lookup'] = my_lookup environment.globals['lookup'] = my_lookup
if fail_on_undefined:
environment.undefined = StrictUndefined
try: try:
data = codecs.open(realpath, encoding="utf8").read() data = codecs.open(realpath, encoding="utf8").read()
@ -417,7 +421,7 @@ def template_from_file(basedir, path, vars):
except: except:
raise errors.AnsibleError("unable to read %s" % realpath) raise errors.AnsibleError("unable to read %s" % realpath)
# Get jinja env overrides from template # Get jinja env overrides from template
if data.startswith(JINJA2_OVERRIDE): if data.startswith(JINJA2_OVERRIDE):
eol = data.find('\n') eol = data.find('\n')
@ -455,15 +459,18 @@ def template_from_file(basedir, path, vars):
# This line performs deep Jinja2 magic that uses the _jinja2_vars object for vars # This line performs deep Jinja2 magic that uses the _jinja2_vars object for vars
# Ideally, this could use some API where setting shared=True and the object won't get # Ideally, this could use some API where setting shared=True and the object won't get
# passed through dict(o), but I have not found that yet. # passed through dict(o), but I have not found that yet.
res = jinja2.utils.concat(t.root_render_func(t.new_context(_jinja2_vars(basedir, vars, t.globals), shared=True))) try:
res = jinja2.utils.concat(t.root_render_func(t.new_context(_jinja2_vars(basedir, vars, t.globals), shared=True)))
except jinja2.exceptions.UndefinedError, e:
raise errors.AnsibleUndefinedVariable("Undefined variables: %s" % str(e))
if data.endswith('\n') and not res.endswith('\n'): if data.endswith('\n') and not res.endswith('\n'):
res = res + '\n' res = res + '\n'
return template(basedir, res, vars) return template(basedir, res, vars)
def template_from_string(basedir, data, vars): def template_from_string(basedir, data, vars, fail_on_undefined=False):
''' run a string through the (Jinja2) templating engine ''' ''' run a string through the (Jinja2) templating engine '''
try: try:
if type(data) == str: if type(data) == str:
data = unicode(data, 'utf-8') data = unicode(data, 'utf-8')
@ -487,16 +494,19 @@ def template_from_string(basedir, data, vars):
raise errors.AnsibleError("recursive loop detected in template string: %s" % data) raise errors.AnsibleError("recursive loop detected in template string: %s" % data)
else: else:
return data return data
def my_lookup(*args, **kwargs): def my_lookup(*args, **kwargs):
kwargs['vars'] = vars kwargs['vars'] = vars
return lookup(*args, basedir=basedir, **kwargs) return lookup(*args, basedir=basedir, **kwargs)
t.globals['lookup'] = my_lookup t.globals['lookup'] = my_lookup
res = jinja2.utils.concat(t.root_render_func(t.new_context(_jinja2_vars(basedir, vars, t.globals), shared=True))) res = jinja2.utils.concat(t.root_render_func(t.new_context(_jinja2_vars(basedir, vars, t.globals), shared=True)))
return res return res
except jinja2.exceptions.UndefinedError: except jinja2.exceptions.UndefinedError:
if fail_on_undefined:
raise
else:
# this shouldn't happen due to undeclared check above # this shouldn't happen due to undeclared check above
return data return data