@ -119,9 +119,64 @@ class Play(object):
# *************************************************
def _load_roles ( self , roles , ds ) :
def _get_role_path ( self , role ) :
"""
Returns the path on disk to the directory containing
the role directories like tasks , templates , etc . Also
returns any variables that were included with the role
"""
orig_path = template ( self . basedir , role , self . vars )
role_vars = { }
if type ( orig_path ) == dict :
# what, not a path?
role_name = orig_path . get ( ' role ' , None )
if role_name is None :
raise errors . AnsibleError ( " expected a role name in dictionary: %s " % orig_path )
role_vars = orig_path
orig_path = role_name
path = utils . path_dwim ( self . basedir , os . path . join ( ' roles ' , orig_path ) )
if not os . path . isdir ( path ) and not orig_path . startswith ( " . " ) and not orig_path . startswith ( " / " ) :
path2 = utils . path_dwim ( self . basedir , orig_path )
if not os . path . isdir ( path2 ) :
raise errors . AnsibleError ( " cannot find role in %s or %s " % ( path , path2 ) )
path = path2
elif not os . path . isdir ( path ) :
raise errors . AnsibleError ( " cannot find role in %s " % ( path ) )
return ( path , role_vars )
def _build_role_dependencies ( self , roles , dep_stack , vars = { } , level = 0 ) :
# this number is arbitrary, but it seems sane
if level > 20 :
raise errors . AnsibleError ( " too many levels of recursion while resolving role dependencies " )
for role in roles :
path , role_vars = self . _get_role_path ( role )
# the meta directory contains the yaml that should
# hold the list of dependencies (if any)
meta = self . _resolve_main ( utils . path_dwim ( self . basedir , os . path . join ( path , ' meta ' ) ) )
if os . path . isfile ( meta ) :
data = utils . parse_yaml_from_file ( meta )
if data :
dependencies = data . get ( ' dependencies ' , [ ] )
for dep in dependencies :
( dep_path , dep_vars ) = self . _get_role_path ( dep )
dep_vars . update ( role_vars )
for k in vars . keys ( ) :
if not k in dep_vars :
dep_vars [ k ] = vars [ k ]
if ' role ' in dep_vars :
del dep_vars [ ' role ' ]
self . _build_role_dependencies ( [ dep ] , dep_stack , vars = dep_vars , level = level + 1 )
dep_stack . append ( [ dep , dep_vars ] )
# only add the current role when we're at the top level,
# otherwise we'll end up in a recursive loop
if level == 0 :
dep_stack . append ( [ role , role_vars ] )
return dep_stack
def _load_roles ( self , roles , ds ) :
# a role is a name that auto-includes the following if they exist
# <rolename>/tasks/main.yml
# <rolename>/handlers/main.yml
@ -147,52 +202,37 @@ class Play(object):
# flush handlers after pre_tasks
new_tasks . append ( dict ( meta = ' flush_handlers ' ) )
# variables if the role was parameterized (i.e. given as a hash)
has_dict = { }
roles = self . _build_role_dependencies ( roles , [ ] , self . vars )
for role_path in roles :
orig_path = template ( self . basedir , role_path , self . vars )
if type ( orig_path ) == dict :
# what, not a path?
role_name = orig_path . get ( ' role ' , None )
if role_name is None :
raise errors . AnsibleError ( " expected a role name in dictionary: %s " % orig_path )
has_dict = orig_path
orig_path = role_name
for role , role_vars in roles :
path , ignore = self . _get_role_path ( role )
# special vars must be extracted from the dict to the included tasks
special_keys = [ " sudo " , " sudo_user " , " when " , " with_items " ]
special_vars = { }
for k in special_keys :
if k in has_dict :
special_vars [ k ] = has_dict [ k ]
path = utils . path_dwim ( self . basedir , os . path . join ( ' roles ' , orig_path ) )
if not os . path . isdir ( path ) and not orig_path . startswith ( " . " ) and not orig_path . startswith ( " / " ) :
path2 = utils . path_dwim ( self . basedir , orig_path )
if not os . path . isdir ( path2 ) :
raise errors . AnsibleError ( " cannot find role in %s or %s " % ( path , path2 ) )
path = path2
elif not os . path . isdir ( path ) :
raise errors . AnsibleError ( " cannot find role in %s " % ( path ) )
if k in role_vars :
special_vars [ k ] = role_vars [ k ]
task_basepath = utils . path_dwim ( self . basedir , os . path . join ( path , ' tasks ' ) )
handler_basepath = utils . path_dwim ( self . basedir , os . path . join ( path , ' handlers ' ) )
vars_basepath = utils . path_dwim ( self . basedir , os . path . join ( path , ' vars ' ) )
task = self . _resolve_main ( task_basepath )
handler = self . _resolve_main ( handler_basepath )
vars_file = self . _resolve_main ( vars_basepath )
library = utils . path_dwim ( self . basedir , os . path . join ( path , ' library ' ) )
if not os . path . isfile ( task ) and not os . path . isfile ( handler ) and not os . path . isfile ( vars_file ) and not os . path . isdir ( library ) :
raise errors . AnsibleError ( " found role at %s , but cannot find %s or %s or %s or %s " % ( path , task , handler , vars_file , library ) )
if os . path . isfile ( task ) :
nt = dict ( include = pipes . quote ( task ) , vars = has_dict )
nt = dict ( include = pipes . quote ( task ) , vars = role_vars )
for k in special_keys :
if k in special_vars :
nt [ k ] = special_vars [ k ]
new_tasks . append ( nt )
if os . path . isfile ( handler ) :
nt = dict ( include = pipes . quote ( handler ) , vars = has_dict )
nt = dict ( include = pipes . quote ( handler ) , vars = role_vars )
for k in special_keys :
if k in special_vars :
nt [ k ] = special_vars [ k ]
@ -202,10 +242,9 @@ class Play(object):
if os . path . isdir ( library ) :
utils . plugins . module_finder . add_directory ( library )
tasks = ds . get ( ' tasks ' , None )
tasks = ds . get ( ' tasks ' , None )
post_tasks = ds . get ( ' post_tasks ' , None )
handlers = ds . get ( ' handlers ' , None )
handlers = ds . get ( ' handlers ' , None )
vars_files = ds . get ( ' vars_files ' , None )
if type ( tasks ) != list :
@ -223,8 +262,10 @@ class Play(object):
new_tasks . extend ( post_tasks )
# flush handlers after post tasks
new_tasks . append ( dict ( meta = ' flush_handlers ' ) )
new_handlers . extend ( handlers )
new_vars_files . extend ( vars_files )
ds [ ' tasks ' ] = new_tasks
ds [ ' handlers ' ] = new_handlers
ds [ ' vars_files ' ] = new_vars_files