@ -1,4 +1,5 @@
# (c) 2013, Daniel Hokka Zakrisson <daniel@hozac.com>
# (c) 2013, Daniel Hokka Zakrisson <daniel@hozac.com>
# (c) 2014, Serge van Ginderachter <serge@vanginderachter.be>
#
#
# This file is part of Ansible
# This file is part of Ansible
#
#
@ -36,9 +37,9 @@ class InventoryDirectory(object):
self . parsers = [ ]
self . parsers = [ ]
self . hosts = { }
self . hosts = { }
self . groups = { }
self . groups = { }
for i in self . names :
for i in self . names :
if i . endswith ( " ~ " ) or i . endswith ( " .orig " ) or i . endswith ( " .bak " ) :
if i . endswith ( " ~ " ) or i . endswith ( " .orig " ) or i . endswith ( " .bak " ) :
continue
continue
if i . endswith ( " .ini " ) :
if i . endswith ( " .ini " ) :
@ -62,31 +63,149 @@ class InventoryDirectory(object):
else :
else :
parser = InventoryParser ( filename = fullpath )
parser = InventoryParser ( filename = fullpath )
self . parsers . append ( parser )
self . parsers . append ( parser )
# This takes a lot of code because we can't directly use any of the objects, as they have to blend
for name , group in parser . groups . iteritems ( ) :
# retrieve all groups and hosts form the parser and add them to
if name not in self . groups :
# self, don't look at group lists yet, to avoid
self . groups [ name ] = group
# recursion trouble, but just make sure all objects exist in self
else :
newgroups = parser . groups . values ( )
# group is already there, copy variables
for group in newgroups :
for k , v in group . get_variables ( ) . iteritems ( ) :
self . groups [ name ] . set_variable ( k , v )
for host in group . hosts :
for host in group . hosts :
if host . name not in self . hosts :
self . _add_host ( host )
self . hosts [ host . name ] = host
for group in newgroups :
else :
self . _add_group ( group )
# host is already there, copy variables
# note: depth numbers on duplicates may be bogus
# now check the objects lists so they contain only objects from
for k , v in host . vars . iteritems ( ) :
# self; membership data in groups is already fine (except all &
self . hosts [ host . name ] . set_variable ( k , v )
# ungrouped, see later), but might still reference objects not in self
# host can already exist from other source (same name,
for group in self . groups . values ( ) :
# different object):
# iterate on a copy of the lists, as those lists get changed in
if host . name not in [ h . name for h in self . groups [ name ] . hosts ] :
# the loop
self . groups [ name ] . add_host ( self . hosts [ host . name ] )
# list with group's child group objects:
for child in group . child_groups [ : ] :
# This needs to be a second loop to ensure all the parent groups exist
if child != self . groups [ child . name ] :
for name , group in parser . groups . iteritems ( ) :
group . child_groups . remove ( child )
for parent in group . parent_groups :
group . child_groups . append ( self . groups [ child . name ] )
self . groups [ parent . name ] . add_child_group ( self . groups [ name ] )
# list with group's parent group objects:
for parent in group . parent_groups [ : ] :
if parent != self . groups [ parent . name ] :
group . parent_groups . remove ( parent )
group . parent_groups . append ( self . groups [ parent . name ] )
# list with group's host objects:
for host in group . hosts [ : ] :
if host != self . hosts [ host . name ] :
group . hosts . remove ( host )
group . hosts . append ( self . hosts [ host . name ] )
# also check here that the group that contains host, is
# also contained in the host's group list
if group not in self . hosts [ host . name ] . groups :
self . hosts [ host . name ] . groups . append ( group )
# extra checks on special groups all and ungrouped
# remove hosts from 'ungrouped' if they became member of other groups
if ' ungrouped ' in self . groups :
ungrouped = self . groups [ ' ungrouped ' ]
# loop on a copy of ungrouped hosts, as we want to change that list
for host in ungrouped . hosts [ : ] :
if len ( host . groups ) > 1 :
host . groups . remove ( ungrouped )
ungrouped . hosts . remove ( host )
# remove hosts from 'all' if they became member of other groups
# all should only contain direct children, not grandchildren
# direct children should have dept == 1
if ' all ' in self . groups :
allgroup = self . groups [ ' all ' ]
# loop on a copy of all's child groups, as we want to change that list
for group in allgroup . child_groups [ : ] :
# groups might once have beeen added to all, and later be added
# to another group: we need to remove the link wit all then
if len ( group . parent_groups ) > 1 :
# real children of all have just 1 parent, all
# this one has more, so not a direct child of all anymore
group . parent_groups . remove ( allgroup )
allgroup . child_groups . remove ( group )
elif allgroup not in group . parent_groups :
# this group was once added to all, but doesn't list it as
# a parent any more; the info in the group is the correct
# info
allgroup . child_groups . remove ( group )
def _add_group ( self , group ) :
""" Merge an existing group or add a new one;
Track parent and child groups , and hosts of the new one """
if group . name not in self . groups :
# it's brand new, add him!
self . groups [ group . name ] = group
if self . groups [ group . name ] != group :
# different object, merge
self . _merge_groups ( self . groups [ group . name ] , group )
def _add_host ( self , host ) :
if host . name not in self . hosts :
# Papa's got a brand new host
self . hosts [ host . name ] = host
if self . hosts [ host . name ] != host :
# different object, merge
self . _merge_hosts ( self . hosts [ host . name ] , host )
def _merge_groups ( self , group , newgroup ) :
""" Merge all of instance newgroup into group,
update parent / child relationships
group lists may still contain group objects that exist in self with
same name , but was instanciated as a different object in some other
inventory parser ; these are handled later """
# name
if group . name != newgroup . name :
raise errors . AnsibleError ( " Cannot merge group %s with %s " % ( group . name , newgroup . name ) )
# depth
group . depth = max ( [ group . depth , newgroup . depth ] )
# hosts list (host objects are by now already added to self.hosts)
for host in newgroup . hosts :
grouphosts = dict ( [ ( h . name , h ) for h in group . hosts ] )
if host . name in grouphosts :
# same host name but different object, merge
self . _merge_hosts ( grouphosts [ host . name ] , host )
else :
# new membership
group . add_host ( self . hosts [ host . name ] )
# group child membership relation
for newchild in newgroup . child_groups :
# dict with existing child groups:
childgroups = dict ( [ ( g . name , g ) for g in group . child_groups ] )
# check if child of new group is already known as a child
if newchild . name not in childgroups :
self . groups [ group . name ] . add_child_group ( newchild )
# group parent membership relation
for newparent in newgroup . parent_groups :
# dict with existing parent groups:
parentgroups = dict ( [ ( g . name , g ) for g in group . parent_groups ] )
# check if parent of new group is already known as a parent
if newparent . name not in parentgroups :
if newparent . name not in self . groups :
# group does not exist yet in self, import him
self . groups [ newparent . name ] = newparent
# group now exists but not yet as a parent here
self . groups [ newparent . name ] . add_child_group ( group )
# variables
group . vars = utils . combine_vars ( group . vars , newgroup . vars )
def _merge_hosts ( self , host , newhost ) :
""" Merge all of instance newhost into host """
# name
if host . name != newhost . name :
raise errors . AnsibleError ( " Cannot merge host %s with %s " % ( host . name , newhost . name ) )
# variables
host . vars = utils . combine_vars ( host . vars , newhost . vars )
def get_host_variables ( self , host ) :
def get_host_variables ( self , host ) :
""" Gets additional host variables from all inventories """
""" Gets additional host variables from all inventories """