2014-11-01 19:34:14 +00:00
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import ( absolute_import , division , print_function )
__metaclass__ = type
import os
from collections import defaultdict
2015-05-08 20:18:19 +00:00
from collections import MutableMapping
2014-11-01 19:34:14 +00:00
2015-10-16 00:55:23 +00:00
from ansible . compat . six import iteritems
2015-07-21 18:51:53 +00:00
from jinja2 . exceptions import UndefinedError
2015-01-23 03:45:25 +00:00
try :
from hashlib import sha1
except ImportError :
from sha import sha as sha1
2015-01-27 05:41:02 +00:00
from ansible import constants as C
2015-07-10 07:22:37 +00:00
from ansible . cli import CLI
2015-11-30 15:33:36 +00:00
from ansible . compat . six import string_types , text_type
2015-09-24 20:26:34 +00:00
from ansible . errors import AnsibleError , AnsibleParserError , AnsibleUndefinedVariable , AnsibleFileNotFound
2015-09-18 18:48:26 +00:00
from ansible . inventory . host import Host
2015-09-25 05:33:45 +00:00
from ansible . plugins import lookup_loader
2014-11-01 19:34:14 +00:00
from ansible . plugins . cache import FactCache
2014-11-14 22:14:08 +00:00
from ansible . template import Templar
2015-09-25 05:33:45 +00:00
from ansible . utils . listify import listify_lookup_plugin_terms
2015-09-01 18:20:16 +00:00
from ansible . utils . vars import combine_vars
2015-10-12 21:05:22 +00:00
from ansible . vars . unsafe_proxy import wrap_var
2014-11-14 22:14:08 +00:00
2015-11-09 21:28:05 +00:00
try :
from __main__ import display
except ImportError :
from ansible . utils . display import Display
display = Display ( )
2015-09-24 17:53:44 +00:00
VARIABLE_CACHE = dict ( )
HOSTVARS_CACHE = dict ( )
2014-11-01 19:34:14 +00:00
2016-06-02 20:08:52 +00:00
class AnsibleInventoryVarsData ( dict ) :
def __init__ ( self , * args , * * kwargs ) :
super ( AnsibleInventoryVarsData , self ) . __init__ ( * args , * * kwargs )
self . path = None
2015-09-09 21:52:44 +00:00
def preprocess_vars ( a ) :
'''
Ensures that vars contained in the parameter passed in are
returned as a list of dictionaries , to ensure for instance
that vars loaded from a file conform to an expected state .
'''
if a is None :
return None
elif not isinstance ( a , list ) :
data = [ a ]
else :
data = a
for item in data :
if not isinstance ( item , MutableMapping ) :
raise AnsibleError ( " variable files must contain either a dictionary of variables, or a list of dictionaries. Got: %s ( %s ) " % ( a , type ( a ) ) )
return data
2015-10-24 19:23:12 +00:00
def strip_internal_keys ( dirty ) :
'''
All keys stating with _ansible_ are internal , so create a copy of the ' dirty ' dict
and remove them from the clean one before returning it
'''
clean = dirty . copy ( )
for k in dirty . keys ( ) :
if isinstance ( k , string_types ) and k . startswith ( ' _ansible_ ' ) :
del clean [ k ]
2016-03-16 20:09:27 +00:00
elif isinstance ( dirty [ k ] , dict ) :
clean [ k ] = strip_internal_keys ( dirty [ k ] )
2015-10-24 19:23:12 +00:00
return clean
2014-11-01 19:34:14 +00:00
class VariableManager :
2014-11-14 22:14:08 +00:00
def __init__ ( self ) :
2014-11-01 19:34:14 +00:00
2015-09-09 16:21:07 +00:00
self . _fact_cache = FactCache ( )
self . _nonpersistent_fact_cache = defaultdict ( dict )
self . _vars_cache = defaultdict ( dict )
self . _extra_vars = defaultdict ( dict )
self . _host_vars_files = defaultdict ( dict )
2014-11-01 19:34:14 +00:00
self . _group_vars_files = defaultdict ( dict )
2015-09-09 16:21:07 +00:00
self . _inventory = None
2016-04-05 15:31:00 +00:00
self . _hostvars = None
2015-09-09 16:21:07 +00:00
self . _omit_token = ' __omit_place_holder__ %s ' % sha1 ( os . urandom ( 64 ) ) . hexdigest ( )
2016-01-20 18:47:09 +00:00
self . _options_vars = defaultdict ( dict )
2014-11-01 19:34:14 +00:00
2015-09-24 17:53:44 +00:00
def __getstate__ ( self ) :
data = dict (
2015-11-17 19:44:46 +00:00
fact_cache = self . _fact_cache ,
np_fact_cache = self . _nonpersistent_fact_cache ,
vars_cache = self . _vars_cache ,
extra_vars = self . _extra_vars ,
host_vars_files = self . _host_vars_files ,
group_vars_files = self . _group_vars_files ,
2015-09-24 17:53:44 +00:00
omit_token = self . _omit_token ,
2016-01-20 18:47:09 +00:00
options_vars = self . _options_vars ,
2015-11-17 19:44:46 +00:00
#inventory = self._inventory,
2015-09-24 17:53:44 +00:00
)
return data
def __setstate__ ( self , data ) :
self . _fact_cache = data . get ( ' fact_cache ' , defaultdict ( dict ) )
self . _nonpersistent_fact_cache = data . get ( ' np_fact_cache ' , defaultdict ( dict ) )
self . _vars_cache = data . get ( ' vars_cache ' , defaultdict ( dict ) )
self . _extra_vars = data . get ( ' extra_vars ' , dict ( ) )
self . _host_vars_files = data . get ( ' host_vars_files ' , defaultdict ( dict ) )
self . _group_vars_files = data . get ( ' group_vars_files ' , defaultdict ( dict ) )
self . _omit_token = data . get ( ' omit_token ' , ' __omit_place_holder__ %s ' % sha1 ( os . urandom ( 64 ) ) . hexdigest ( ) )
2015-11-17 14:15:10 +00:00
self . _inventory = data . get ( ' inventory ' , None )
2016-01-20 18:47:09 +00:00
self . _options_vars = data . get ( ' options_vars ' , dict ( ) )
2015-09-24 17:53:44 +00:00
2014-11-14 22:14:08 +00:00
def _get_cache_entry ( self , play = None , host = None , task = None ) :
play_id = " NONE "
if play :
play_id = play . _uuid
host_id = " NONE "
if host :
host_id = host . get_name ( )
task_id = " NONE "
if task :
task_id = task . _uuid
return " PLAY: %s ;HOST: %s ;TASK: %s " % ( play_id , host_id , task_id )
2014-11-01 19:34:14 +00:00
@property
def extra_vars ( self ) :
''' ensures a clean copy of the extra_vars are made '''
return self . _extra_vars . copy ( )
2015-05-15 01:10:31 +00:00
@extra_vars.setter
def extra_vars ( self , value ) :
2014-11-01 19:34:14 +00:00
''' ensures a clean copy of the extra_vars are used to set the value '''
2015-05-08 20:18:19 +00:00
assert isinstance ( value , MutableMapping )
2014-11-01 19:34:14 +00:00
self . _extra_vars = value . copy ( )
2015-01-23 03:45:25 +00:00
def set_inventory ( self , inventory ) :
self . _inventory = inventory
2016-01-20 18:47:09 +00:00
@property
def options_vars ( self ) :
''' ensures a clean copy of the options_vars are made '''
return self . _options_vars . copy ( )
@options_vars.setter
def options_vars ( self , value ) :
''' ensures a clean copy of the options_vars are used to set the value '''
assert isinstance ( value , dict )
self . _options_vars = value . copy ( )
2015-08-21 14:59:32 +00:00
def _preprocess_vars ( self , a ) :
'''
Ensures that vars contained in the parameter passed in are
returned as a list of dictionaries , to ensure for instance
that vars loaded from a file conform to an expected state .
'''
if a is None :
return None
elif not isinstance ( a , list ) :
data = [ a ]
else :
data = a
for item in data :
if not isinstance ( item , MutableMapping ) :
raise AnsibleError ( " variable files must contain either a dictionary of variables, or a list of dictionaries. Got: %s ( %s ) " % ( a , type ( a ) ) )
return data
2015-09-18 18:48:26 +00:00
def get_vars ( self , loader , play = None , host = None , task = None , include_hostvars = True , include_delegate_to = True , use_cache = True ) :
2014-11-01 19:34:14 +00:00
'''
Returns the variables , with optional " context " given via the parameters
for the play , host , and task ( which could possibly result in different
sets of variables being returned due to the additional context ) .
The order of precedence is :
- play - > roles - > get_default_vars ( if there is a play context )
- group_vars_files [ host ] ( if there is a host context )
- host_vars_files [ host ] ( if there is a host context )
- host - > get_vars ( if there is a host context )
- fact_cache [ host ] ( if there is a host context )
- play vars ( if there is a play context )
- play vars_files ( if there ' s no host context, ignore
file names that cannot be templated )
- task - > get_vars ( if there is a task context )
2015-09-04 20:41:38 +00:00
- vars_cache [ host ] ( if there is a host context )
2014-11-01 19:34:14 +00:00
- extra vars
'''
2016-04-05 15:31:00 +00:00
display . debug ( " in VariableManager get_vars() " )
2014-11-14 22:14:08 +00:00
cache_entry = self . _get_cache_entry ( play = play , host = host , task = task )
2015-09-24 17:53:44 +00:00
if cache_entry in VARIABLE_CACHE and use_cache :
2016-04-05 15:31:00 +00:00
display . debug ( " vars are cached, returning them now " )
2015-09-24 17:53:44 +00:00
return VARIABLE_CACHE [ cache_entry ]
2014-11-14 22:14:08 +00:00
2015-11-04 16:26:06 +00:00
all_vars = dict ( )
2015-10-05 20:31:08 +00:00
magic_variables = self . _get_magic_variables (
loader = loader ,
play = play ,
host = host ,
task = task ,
include_hostvars = include_hostvars ,
include_delegate_to = include_delegate_to ,
)
2014-11-01 19:34:14 +00:00
if play :
# first we compile any vars specified in defaults/main.yml
# for all roles within the specified play
for role in play . get_roles ( ) :
2015-09-01 18:20:16 +00:00
all_vars = combine_vars ( all_vars , role . get_default_vars ( ) )
2014-11-01 19:34:14 +00:00
2015-09-01 15:27:00 +00:00
# if we have a task in this context, and that task has a role, make
# sure it sees its defaults above any other roles, as we previously
# (v1) made sure each task had a copy of its roles default vars
if task and task . _role is not None :
2016-05-26 19:46:59 +00:00
all_vars = combine_vars ( all_vars , task . _role . get_default_vars ( dep_chain = task . _block . get_dep_chain ( ) ) )
2015-09-01 15:27:00 +00:00
2014-11-01 19:34:14 +00:00
if host :
# next, if a host is specified, we load any vars from group_vars
# files and then any vars from host_vars files which may apply to
# this host or the groups it belongs to
2014-11-14 22:14:08 +00:00
2016-04-19 16:40:08 +00:00
# we merge in the special 'all' group_vars first, if they exist
2014-11-14 22:14:08 +00:00
if ' all ' in self . _group_vars_files :
2015-09-09 21:52:44 +00:00
data = preprocess_vars ( self . _group_vars_files [ ' all ' ] )
2015-08-21 14:59:32 +00:00
for item in data :
2015-09-01 18:20:16 +00:00
all_vars = combine_vars ( all_vars , item )
2014-11-14 22:14:08 +00:00
2016-04-19 16:40:08 +00:00
# we merge in vars from groups specified in the inventory (INI or script)
all_vars = combine_vars ( all_vars , host . get_group_vars ( ) )
2015-12-03 19:22:27 +00:00
for group in sorted ( host . get_groups ( ) , key = lambda g : g . depth ) :
2015-03-25 18:51:40 +00:00
if group . name in self . _group_vars_files and group . name != ' all ' :
2015-09-04 20:41:38 +00:00
for data in self . _group_vars_files [ group . name ] :
2015-09-09 21:52:44 +00:00
data = preprocess_vars ( data )
2015-09-04 20:41:38 +00:00
for item in data :
all_vars = combine_vars ( all_vars , item )
# then we merge in vars from the host specified in the inventory (INI or script)
all_vars = combine_vars ( all_vars , host . get_vars ( ) )
2014-11-01 19:34:14 +00:00
2015-09-04 20:41:38 +00:00
# then we merge in the host_vars/<hostname> file, if it exists
2014-11-01 19:34:14 +00:00
host_name = host . get_name ( )
if host_name in self . _host_vars_files :
2015-09-04 20:41:38 +00:00
for data in self . _host_vars_files [ host_name ] :
2015-09-09 21:52:44 +00:00
data = preprocess_vars ( data )
2015-09-04 20:41:38 +00:00
for item in data :
all_vars = combine_vars ( all_vars , item )
2014-11-01 19:34:14 +00:00
2015-09-09 16:21:07 +00:00
# finally, the facts caches for this host, if it exists
2015-07-13 15:06:03 +00:00
try :
2015-10-12 21:05:22 +00:00
host_facts = wrap_var ( self . _fact_cache . get ( host . name , dict ( ) ) )
2015-09-03 22:08:34 +00:00
all_vars = combine_vars ( all_vars , host_facts )
2015-07-13 15:06:03 +00:00
except KeyError :
pass
2014-11-01 19:34:14 +00:00
if play :
2015-09-01 18:20:16 +00:00
all_vars = combine_vars ( all_vars , play . get_vars ( ) )
2015-08-13 02:39:06 +00:00
2015-07-13 19:18:05 +00:00
for vars_file_item in play . get_vars_files ( ) :
2015-10-05 20:31:08 +00:00
# create a set of temporary vars here, which incorporate the extra
# and magic vars so we can properly template the vars_files entries
2015-09-23 05:25:58 +00:00
temp_vars = combine_vars ( all_vars , self . _extra_vars )
2015-10-12 16:17:45 +00:00
temp_vars = combine_vars ( temp_vars , magic_variables )
2015-09-23 05:25:58 +00:00
templar = Templar ( loader = loader , variables = temp_vars )
# we assume each item in the list is itself a list, as we
# support "conditional includes" for vars_files, which mimics
# the with_first_found mechanism.
vars_file_list = vars_file_item
if not isinstance ( vars_file_list , list ) :
vars_file_list = [ vars_file_list ]
# now we iterate through the (potential) files, and break out
# as soon as we read one from the list. If none are found, we
# raise an error, which is silently ignored at this point.
2014-11-14 22:14:08 +00:00
try :
2015-07-13 19:18:05 +00:00
for vars_file in vars_file_list :
2015-09-23 05:25:58 +00:00
vars_file = templar . template ( vars_file )
try :
data = preprocess_vars ( loader . load_from_file ( vars_file ) )
if data is not None :
for item in data :
all_vars = combine_vars ( all_vars , item )
2015-09-24 20:26:34 +00:00
break
except AnsibleFileNotFound as e :
2015-09-23 05:25:58 +00:00
# we continue on loader failures
continue
2015-09-24 20:26:34 +00:00
except AnsibleParserError as e :
raise
2015-07-13 19:18:05 +00:00
else :
2015-09-24 20:26:34 +00:00
raise AnsibleFileNotFound ( " vars file %s was not found " % vars_file_item )
2015-09-21 13:32:35 +00:00
except ( UndefinedError , AnsibleUndefinedVariable ) :
2015-09-21 15:55:07 +00:00
if host is not None and self . _fact_cache . get ( host . name , dict ( ) ) . get ( ' module_setup ' ) and task is not None :
2015-09-22 16:13:32 +00:00
raise AnsibleUndefinedVariable ( " an undefined variable was found when attempting to template the vars_files item ' %s ' " % vars_file_item , obj = vars_file_item )
2015-09-21 15:55:07 +00:00
else :
# we do not have a full context here, and the missing variable could be
# because of that, so just show a warning and continue
2015-11-10 17:02:29 +00:00
display . vvv ( " skipping vars_file ' %s ' due to an undefined variable " % vars_file_item )
2015-09-21 15:55:07 +00:00
continue
2015-07-01 15:32:44 +00:00
2016-06-07 17:08:01 +00:00
# By default, we now merge in all vars from all roles in the play,
# unless the user has disabled this via a config option
2015-07-01 15:32:44 +00:00
if not C . DEFAULT_PRIVATE_ROLE_VARS :
for role in play . get_roles ( ) :
2015-09-22 06:13:46 +00:00
all_vars = combine_vars ( all_vars , role . get_vars ( include_params = False ) )
2014-11-01 19:34:14 +00:00
2016-06-07 17:08:01 +00:00
# next, we merge in the vars from the role, which will specifically
# follow the role dependency chain, and then we merge in the tasks
# vars (which will look at parent blocks/task includes)
if task :
if task . _role :
all_vars = combine_vars ( all_vars , task . _role . get_vars ( include_params = False ) )
all_vars = combine_vars ( all_vars , task . get_vars ( ) )
# next, we merge in the vars cache (include vars) and nonpersistent
# facts cache (set_fact/register), in that order
2016-06-07 16:14:43 +00:00
if host :
all_vars = combine_vars ( all_vars , self . _vars_cache . get ( host . get_name ( ) , dict ( ) ) )
all_vars = combine_vars ( all_vars , self . _nonpersistent_fact_cache . get ( host . name , dict ( ) ) )
2016-06-07 17:08:01 +00:00
# next, we merge in role params and task include params
2014-11-01 19:34:14 +00:00
if task :
2014-11-14 22:14:08 +00:00
if task . _role :
2016-05-26 19:46:59 +00:00
all_vars = combine_vars ( all_vars , task . _role . get_role_params ( task . _block . get_dep_chain ( ) ) )
2014-11-01 19:34:14 +00:00
2016-06-07 16:14:43 +00:00
# special case for include tasks, where the include params
# may be specified in the vars field for the task, which should
# have higher precedence than the vars/np facts above
2015-11-19 14:01:51 +00:00
all_vars = combine_vars ( all_vars , task . get_include_params ( ) )
2016-06-07 17:08:01 +00:00
# finally, we merge in extra vars and the magic variables
2015-09-01 18:20:16 +00:00
all_vars = combine_vars ( all_vars , self . _extra_vars )
2015-10-05 20:31:08 +00:00
all_vars = combine_vars ( all_vars , magic_variables )
2015-11-09 21:28:05 +00:00
# special case for the 'environment' magic variable, as someone
# may have set it as a variable and we don't want to stomp on it
2015-11-10 02:04:24 +00:00
if task :
if ' environment ' not in all_vars :
all_vars [ ' environment ' ] = task . environment
else :
display . warning ( " The variable ' environment ' appears to be used already, which is also used internally for environment variables set on the task/block/play. You should use a different variable name to avoid conflicts with this internal variable " )
2015-11-09 21:28:05 +00:00
2015-10-05 20:31:08 +00:00
# if we have a task and we're delegating to another host, figure out the
# variables for that host now so we don't have to rely on hostvars later
if task and task . delegate_to is not None and include_delegate_to :
all_vars [ ' ansible_delegated_vars ' ] = self . _get_delegated_vars ( loader , play , task , all_vars )
#VARIABLE_CACHE[cache_entry] = all_vars
2015-12-22 05:24:35 +00:00
if task or play :
all_vars [ ' vars ' ] = all_vars . copy ( )
2014-11-01 19:34:14 +00:00
2016-04-05 15:31:00 +00:00
display . debug ( " done with get_vars() " )
2015-10-05 20:31:08 +00:00
return all_vars
2015-10-27 18:12:17 +00:00
def invalidate_hostvars_cache ( self , play ) :
hostvars_cache_entry = self . _get_cache_entry ( play = play )
if hostvars_cache_entry in HOSTVARS_CACHE :
del HOSTVARS_CACHE [ hostvars_cache_entry ]
2015-10-05 20:31:08 +00:00
def _get_magic_variables ( self , loader , play , host , task , include_hostvars , include_delegate_to ) :
'''
Returns a dictionary of so - called " magic " variables in Ansible ,
which are special variables we set internally for use .
'''
2015-01-23 03:45:25 +00:00
2015-10-05 20:31:08 +00:00
variables = dict ( )
variables [ ' playbook_dir ' ] = loader . get_basedir ( )
2015-06-23 18:29:39 +00:00
2015-05-11 16:22:41 +00:00
if host :
2016-03-04 18:12:35 +00:00
variables [ ' group_names ' ] = sorted ( [ group . name for group in host . get_groups ( ) if group . name != ' all ' ] )
2015-05-11 16:22:41 +00:00
if self . _inventory is not None :
2015-10-05 20:31:08 +00:00
variables [ ' groups ' ] = dict ( )
2015-09-24 09:50:00 +00:00
for ( group_name , group ) in iteritems ( self . _inventory . groups ) :
2015-10-05 20:31:08 +00:00
variables [ ' groups ' ] [ group_name ] = [ h . name for h in group . get_hosts ( ) ]
2015-10-22 15:06:47 +00:00
if play :
variables [ ' role_names ' ] = [ r . _role_name for r in play . roles ]
2015-05-11 19:04:17 +00:00
if task :
if task . _role :
2015-11-28 14:08:10 +00:00
variables [ ' role_name ' ] = task . _role . get_name ( )
2015-10-05 20:31:08 +00:00
variables [ ' role_path ' ] = task . _role . _role_path
2015-11-30 15:33:36 +00:00
variables [ ' role_uuid ' ] = text_type ( task . _role . _uuid )
2015-09-18 18:48:26 +00:00
2015-01-29 22:43:50 +00:00
if self . _inventory is not None :
2015-10-05 20:31:08 +00:00
variables [ ' inventory_dir ' ] = self . _inventory . basedir ( )
2015-10-11 01:54:28 +00:00
variables [ ' inventory_file ' ] = self . _inventory . src ( )
2015-06-23 01:03:55 +00:00
if play :
# add the list of hosts in the play, as adjusted for limit/filters
2015-08-19 04:10:31 +00:00
# DEPRECATED: play_hosts should be deprecated in favor of ansible_play_hosts,
# however this would take work in the templating engine, so for now
# we'll add both so we can give users something transitional to use
2015-06-23 01:03:55 +00:00
host_list = [ x . name for x in self . _inventory . get_hosts ( ) ]
2015-10-05 20:31:08 +00:00
variables [ ' play_hosts ' ] = host_list
variables [ ' ansible_play_hosts ' ] = host_list
2015-06-23 01:03:55 +00:00
2015-01-23 03:45:25 +00:00
# the 'omit' value alows params to be left out if the variable they are based on is undefined
2015-10-05 20:31:08 +00:00
variables [ ' omit ' ] = self . _omit_token
variables [ ' ansible_version ' ] = CLI . version_info ( gitinfo = False )
2016-01-20 18:47:09 +00:00
# Set options vars
2016-04-08 02:16:15 +00:00
for option , option_value in iteritems ( self . _options_vars ) :
2016-01-20 18:47:09 +00:00
variables [ option ] = option_value
2015-10-05 20:31:08 +00:00
2016-04-05 15:31:00 +00:00
if self . _hostvars is not None and include_hostvars :
variables [ ' hostvars ' ] = self . _hostvars
2015-10-05 20:31:08 +00:00
return variables
def _get_delegated_vars ( self , loader , play , task , existing_variables ) :
# we unfortunately need to template the delegate_to field here,
# as we're fetching vars before post_validate has been called on
# the task that has been passed in
vars_copy = existing_variables . copy ( )
templar = Templar ( loader = loader , variables = vars_copy )
items = [ ]
if task . loop is not None :
if task . loop in lookup_loader :
try :
2016-04-05 15:31:00 +00:00
#TODO: remove convert_bare true and deprecate this in with_
2015-10-05 20:31:08 +00:00
loop_terms = listify_lookup_plugin_terms ( terms = task . loop_args , templar = templar , loader = loader , fail_on_undefined = True , convert_bare = True )
2016-04-05 15:31:00 +00:00
items = lookup_loader . get ( task . loop , loader = loader , templar = templar ) . run ( terms = loop_terms , variables = vars_copy )
2015-10-05 20:31:08 +00:00
except AnsibleUndefinedVariable as e :
2016-04-05 15:31:00 +00:00
# This task will be skipped later due to this, so we just setup
# a dummy array for the later code so it doesn't fail
items = [ None ]
2015-10-05 20:31:08 +00:00
else :
raise AnsibleError ( " Unexpected failure in finding the lookup named ' %s ' in the available lookup plugins " % task . loop )
else :
items = [ None ]
delegated_host_vars = dict ( )
for item in items :
# update the variables with the item value for templating, in case we need it
if item is not None :
vars_copy [ ' item ' ] = item
templar . set_available_variables ( vars_copy )
delegated_host_name = templar . template ( task . delegate_to , fail_on_undefined = False )
if delegated_host_name in delegated_host_vars :
# no need to repeat ourselves, as the delegate_to value
# does not appear to be tied to the loop item variable
continue
# a dictionary of variables to use if we have to create a new host below
2015-11-30 19:39:49 +00:00
# we set the default port based on the default transport here, to make sure
# we use the proper default for windows
new_port = C . DEFAULT_REMOTE_PORT
if C . DEFAULT_TRANSPORT == ' winrm ' :
new_port = 5986
2015-10-05 20:31:08 +00:00
new_delegated_host_vars = dict (
ansible_host = delegated_host_name ,
2015-11-30 19:39:49 +00:00
ansible_port = new_port ,
2015-10-05 20:31:08 +00:00
ansible_user = C . DEFAULT_REMOTE_USER ,
ansible_connection = C . DEFAULT_TRANSPORT ,
)
# now try to find the delegated-to host in inventory, or failing that,
# create a new host on the fly so we can fetch variables for it
delegated_host = None
if self . _inventory is not None :
delegated_host = self . _inventory . get_host ( delegated_host_name )
# try looking it up based on the address field, and finally
# fall back to creating a host on the fly to use for the var lookup
if delegated_host is None :
for h in self . _inventory . get_hosts ( ignore_limits_and_restrictions = True ) :
# check if the address matches, or if both the delegated_to host
# and the current host are in the list of localhost aliases
if h . address == delegated_host_name or h . name in C . LOCALHOST and delegated_host_name in C . LOCALHOST :
delegated_host = h
break
else :
delegated_host = Host ( name = delegated_host_name )
delegated_host . vars . update ( new_delegated_host_vars )
else :
delegated_host = Host ( name = delegated_host_name )
delegated_host . vars . update ( new_delegated_host_vars )
# now we go fetch the vars for the delegated-to host and save them in our
# master dictionary of variables to be used later in the TaskExecutor/PlayContext
delegated_host_vars [ delegated_host_name ] = self . get_vars (
loader = loader ,
play = play ,
host = delegated_host ,
task = task ,
include_delegate_to = False ,
include_hostvars = False ,
)
return delegated_host_vars
2014-11-01 19:34:14 +00:00
def _get_inventory_basename ( self , path ) :
'''
2015-09-09 15:55:40 +00:00
Returns the basename minus the extension of the given path , so the
2014-11-01 19:34:14 +00:00
bare filename can be matched against host / group names later
'''
( name , ext ) = os . path . splitext ( os . path . basename ( path ) )
2015-03-25 18:51:40 +00:00
if ext not in ( ' .yml ' , ' .yaml ' ) :
2014-11-14 22:14:08 +00:00
return os . path . basename ( path )
else :
return name
2014-11-01 19:34:14 +00:00
2014-11-14 22:14:08 +00:00
def _load_inventory_file ( self , path , loader ) :
2014-11-01 19:34:14 +00:00
'''
helper function , which loads the file and gets the
basename of the file without the extension
'''
2015-03-25 18:51:40 +00:00
if loader . is_directory ( path ) :
2015-01-28 20:06:10 +00:00
data = dict ( )
try :
2015-03-25 18:51:40 +00:00
names = loader . list_directory ( path )
2015-04-13 16:35:20 +00:00
except os . error as err :
2015-01-28 20:06:10 +00:00
raise AnsibleError ( " This folder cannot be listed: %s : %s . " % ( path , err . strerror ) )
# evaluate files in a stable order rather than whatever
# order the filesystem lists them.
names . sort ( )
# do not parse hidden files or dirs, e.g. .svn/
paths = [ os . path . join ( path , name ) for name in names if not name . startswith ( ' . ' ) ]
for p in paths :
2016-06-06 16:25:15 +00:00
results = self . _load_inventory_file ( path = p , loader = loader )
2015-07-13 22:14:13 +00:00
if results is not None :
2015-09-01 18:20:16 +00:00
data = combine_vars ( data , results )
2015-01-28 20:06:10 +00:00
else :
2015-06-16 15:55:26 +00:00
file_name , ext = os . path . splitext ( path )
data = None
2015-09-08 07:20:09 +00:00
if not ext or ext not in C . YAML_FILENAME_EXTENSIONS :
for test_ext in C . YAML_FILENAME_EXTENSIONS :
new_path = path + test_ext
2015-06-16 15:55:26 +00:00
if loader . path_exists ( new_path ) :
2015-07-13 22:20:04 +00:00
data = loader . load_from_file ( new_path )
break
2015-06-16 15:55:26 +00:00
else :
if loader . path_exists ( path ) :
data = loader . load_from_file ( path )
2015-01-28 20:06:10 +00:00
2016-06-02 20:08:52 +00:00
rval = AnsibleInventoryVarsData ( )
rval . path = path
if data is not None :
rval . update ( data )
return rval
2014-11-01 19:34:14 +00:00
2014-11-14 22:14:08 +00:00
def add_host_vars_file ( self , path , loader ) :
2014-11-01 19:34:14 +00:00
'''
Loads and caches a host_vars file in the _host_vars_files dict ,
where the key to that dictionary is the basename of the file , minus
the extension , for matching against a given inventory host name
'''
2016-06-02 20:08:52 +00:00
name = self . _get_inventory_basename ( path )
if name not in self . _host_vars_files :
self . _host_vars_files [ name ] = [ ]
for entry in self . _host_vars_files [ name ] :
if entry . path == path :
data = entry
break
2015-06-16 15:55:26 +00:00
else :
2016-06-02 20:08:52 +00:00
data = self . _load_inventory_file ( path , loader )
if data :
self . _host_vars_files [ name ] . append ( data )
return data
2014-11-01 19:34:14 +00:00
2014-11-14 22:14:08 +00:00
def add_group_vars_file ( self , path , loader ) :
2014-11-01 19:34:14 +00:00
'''
Loads and caches a host_vars file in the _host_vars_files dict ,
where the key to that dictionary is the basename of the file , minus
the extension , for matching against a given inventory host name
'''
2016-06-02 20:08:52 +00:00
name = self . _get_inventory_basename ( path )
if name not in self . _group_vars_files :
self . _group_vars_files [ name ] = [ ]
for entry in self . _group_vars_files [ name ] :
if entry . path == path :
data = entry
break
2015-06-16 15:55:26 +00:00
else :
2016-06-02 20:08:52 +00:00
data = self . _load_inventory_file ( path , loader )
if data :
self . _group_vars_files [ name ] . append ( data )
return data
2014-11-14 22:14:08 +00:00
2016-03-15 04:24:26 +00:00
def clear_facts ( self , hostname ) :
'''
Clears the facts for a host
'''
if hostname in self . _fact_cache :
del self . _fact_cache [ hostname ]
2014-11-14 22:14:08 +00:00
def set_host_facts ( self , host , facts ) :
'''
Sets or updates the given facts for a host in the fact cache .
'''
assert isinstance ( facts , dict )
2015-09-10 21:36:06 +00:00
if host . name not in self . _fact_cache :
self . _fact_cache [ host . name ] = facts
else :
try :
2015-10-09 15:16:41 +00:00
self . _fact_cache . update ( host . name , facts )
2015-09-10 21:36:06 +00:00
except KeyError :
self . _fact_cache [ host . name ] = facts
def set_nonpersistent_facts ( self , host , facts ) :
'''
Sets or updates the given facts for a host in the fact cache .
'''
assert isinstance ( facts , dict )
2015-09-09 22:28:39 +00:00
if host . name not in self . _nonpersistent_fact_cache :
2015-09-09 16:21:07 +00:00
self . _nonpersistent_fact_cache [ host . name ] = facts
2014-11-14 22:14:08 +00:00
else :
2015-07-13 15:06:03 +00:00
try :
2015-09-09 16:21:07 +00:00
self . _nonpersistent_fact_cache [ host . name ] . update ( facts )
2015-07-13 15:06:03 +00:00
except KeyError :
2015-09-09 16:21:07 +00:00
self . _nonpersistent_fact_cache [ host . name ] = facts
2014-11-14 22:14:08 +00:00
def set_host_variable ( self , host , varname , value ) :
'''
Sets a value in the vars_cache for a host .
'''
host_name = host . get_name ( )
if host_name not in self . _vars_cache :
self . _vars_cache [ host_name ] = dict ( )
2016-03-30 15:10:54 +00:00
if varname in self . _vars_cache [ host_name ] and isinstance ( self . _vars_cache [ host_name ] [ varname ] , MutableMapping ) and isinstance ( value , MutableMapping ) :
2016-02-12 05:49:25 +00:00
self . _vars_cache [ host_name ] [ varname ] = combine_vars ( self . _vars_cache [ host_name ] [ varname ] , value )
else :
self . _vars_cache [ host_name ] [ varname ] = value