@ -56,6 +56,16 @@ DOCUMENTATION = '''
tls_hostname :
tls_hostname :
description : When verifying the authenticity of the Docker Host server , provide the expected name of the server .
description : When verifying the authenticity of the Docker Host server , provide the expected name of the server .
type : str
type : str
include_host_uri :
description : Toggle to return the additional attribute I ( ansible_host_uri ) which contains the URI of the
swarm leader in format of M ( tcp : / / 172.16 .0 .1 : 2376 ) . This value may be used without additional
modification as value of option I ( docker_host ) in Docker Swarm modules when connecting via API .
The port always defaults to M ( 2376 ) .
type : bool
default : no
include_host_uri_port :
description : Override the detected port number included in I ( ansible_host_uri )
type : int
'''
'''
EXAMPLES = '''
EXAMPLES = '''
@ -125,7 +135,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
def _get_tls_connect_params ( self ) :
def _get_tls_connect_params ( self ) :
if self . get_option ( ' tls ' ) and self . get_option ( ' cert_path ' ) and self . get_option ( ' key_path ' ) :
if self . get_option ( ' tls ' ) and self . get_option ( ' cert_path ' ) and self . get_option ( ' key_path ' ) :
# TLS with certs and no host verification
# TLS with certs and no host verification
tls_config = self . _get_tls_config ( client_cert = ( self . get_option ( ' cert_path ' ) , self . get_option ( ' key_path ' ) ) ,
tls_config = self . _get_tls_config ( client_cert = ( self . get_option ( ' cert_path ' ) ,
self . get_option ( ' key_path ' ) ) ,
verify = False )
verify = False )
return tls_config
return tls_config
@ -137,12 +148,14 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if self . get_option ( ' tls_verify ' ) and self . get_option ( ' cert_path ' ) and self . get_option ( ' key_path ' ) :
if self . get_option ( ' tls_verify ' ) and self . get_option ( ' cert_path ' ) and self . get_option ( ' key_path ' ) :
# TLS with certs and host verification
# TLS with certs and host verification
if self . get_option ( ' cacert_path ' ) :
if self . get_option ( ' cacert_path ' ) :
tls_config = self . _get_tls_config ( client_cert = ( self . get_option ( ' cert_path ' ) , self . get_option ( ' key_path ' ) ) ,
tls_config = self . _get_tls_config ( client_cert = ( self . get_option ( ' cert_path ' ) ,
self . get_option ( ' key_path ' ) ) ,
ca_cert = self . get_option ( ' cacert_path ' ) ,
ca_cert = self . get_option ( ' cacert_path ' ) ,
verify = True ,
verify = True ,
assert_hostname = self . get_option ( ' tls_hostname ' ) )
assert_hostname = self . get_option ( ' tls_hostname ' ) )
else :
else :
tls_config = self . _get_tls_config ( client_cert = ( self . get_option ( ' cert_path ' ) , self . get_option ( ' key_path ' ) ) ,
tls_config = self . _get_tls_config ( client_cert = ( self . get_option ( ' cert_path ' ) ,
self . get_option ( ' key_path ' ) ) ,
verify = True ,
verify = True ,
assert_hostname = self . get_option ( ' tls_hostname ' ) )
assert_hostname = self . get_option ( ' tls_hostname ' ) )
@ -165,37 +178,65 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
return None
return None
def _populate ( self ) :
def _populate ( self ) :
self . client = docker . DockerClient ( base_url = self . get_option ( ' host ' ) , tls = self . _get_tls_connect_params ( ) )
self . client = docker . DockerClient ( base_url = self . get_option ( ' host ' ) ,
tls = self . _get_tls_connect_params ( ) )
self . inventory . add_group ( ' all ' )
self . inventory . add_group ( ' all ' )
self . inventory . add_group ( ' manager ' )
self . inventory . add_group ( ' manager ' )
self . inventory . add_group ( ' worker ' )
self . inventory . add_group ( ' worker ' )
self . inventory . add_group ( ' leader ' )
self . inventory . add_group ( ' leader ' )
if self . get_option ( ' include_host_uri ' , True ) :
if self . get_option ( ' include_host_uri_port ' ) :
host_uri_port = self . get_option ( ' include_host_uri_port ' )
elif self . get_option ( ' tls ' ) or self . get_option ( ' tls_verify ' ) :
host_uri_port = " 2376 "
else :
host_uri_port = " 2375 "
try :
try :
self . nodes = self . client . nodes . list ( )
self . nodes = self . client . nodes . list ( )
for self . node in self . nodes :
for self . node in self . nodes :
self . node_attrs = self . client . nodes . get ( self . node . id ) . attrs
self . node_attrs = self . client . nodes . get ( self . node . id ) . attrs
self . inventory . add_host ( self . node_attrs [ ' ID ' ] )
self . inventory . add_host ( self . node_attrs [ ' ID ' ] )
self . inventory . add_host ( self . node_attrs [ ' ID ' ] , group = self . node_attrs [ ' Spec ' ] [ ' Role ' ] )
self . inventory . add_host ( self . node_attrs [ ' ID ' ] , group = self . node_attrs [ ' Spec ' ] [ ' Role ' ] )
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' ansible_host ' , self . node_attrs [ ' Status ' ] [ ' Addr ' ] )
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' ansible_host ' ,
self . node_attrs [ ' Status ' ] [ ' Addr ' ] )
if self . get_option ( ' include_host_uri ' , True ) :
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' ansible_host_uri ' ,
" tcp:// " + self . node_attrs [ ' Status ' ] [ ' Addr ' ] + " : " + host_uri_port )
if self . get_option ( ' verbose_output ' , True ) :
if self . get_option ( ' verbose_output ' , True ) :
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' docker_swarm_node_attributes ' , self . node_attrs )
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' docker_swarm_node_attributes ' , self . node_attrs )
if ' ManagerStatus ' in self . node_attrs :
if ' ManagerStatus ' in self . node_attrs :
if self . node_attrs [ ' ManagerStatus ' ] . get ( ' Leader ' ) :
if self . node_attrs [ ' ManagerStatus ' ] . get ( ' Leader ' ) :
# This is workaround of bug in Docker when in some cases the Leader IP is 0.0.0.0
# This is workaround of bug in Docker when in some cases the Leader IP is 0.0.0.0
# Check moby/moby#35437 for details
# Check moby/moby#35437 for details
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' ansible_host ' ,
swarm_leader_ip = parse_address ( self . node_attrs [ ' ManagerStatus ' ] [ ' Addr ' ] ) [ 0 ] or \
parse_address ( self . node_attrs [ ' ManagerStatus ' ] [ ' Addr ' ] ) [ 0 ] )
self . node_attrs [ ' Status ' ] [ ' Addr ' ]
if self . get_option ( ' include_host_uri ' , True ) :
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' ansible_host_uri ' , " tcp:// " +
swarm_leader_ip + " : " + host_uri_port )
self . inventory . set_variable ( self . node_attrs [ ' ID ' ] , ' ansible_host ' , swarm_leader_ip )
self . inventory . add_host ( self . node_attrs [ ' ID ' ] , group = ' leader ' )
self . inventory . add_host ( self . node_attrs [ ' ID ' ] , group = ' leader ' )
# Use constructed if applicable
# Use constructed if applicable
strict = self . get_option ( ' strict ' )
strict = self . get_option ( ' strict ' )
# Composed variables
# Composed variables
self . _set_composite_vars ( self . get_option ( ' compose ' ) , self . node_attrs , self . node_attrs [ ' ID ' ] , strict = strict )
self . _set_composite_vars ( self . get_option ( ' compose ' ) ,
self . node_attrs ,
self . node_attrs [ ' ID ' ] ,
strict = strict )
# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
self . _add_host_to_composed_groups ( self . get_option ( ' groups ' ) , self . node_attrs , self . node_attrs [ ' ID ' ] , strict = strict )
self . _add_host_to_composed_groups ( self . get_option ( ' groups ' ) ,
self . node_attrs ,
self . node_attrs [ ' ID ' ] ,
strict = strict )
# Create groups based on variable values and add the corresponding hosts to it
# Create groups based on variable values and add the corresponding hosts to it
self . _add_host_to_keyed_groups ( self . get_option ( ' keyed_groups ' ) , self . node_attrs , self . node_attrs [ ' ID ' ] , strict = strict )
self . _add_host_to_keyed_groups ( self . get_option ( ' keyed_groups ' ) ,
self . node_attrs ,
self . node_attrs [ ' ID ' ] ,
strict = strict )
except Exception as e :
except Exception as e :
raise AnsibleError ( ' Unable to fetch hosts from Docker swarm API, this was the original exception: %s ' % to_native ( e ) )
raise AnsibleError ( ' Unable to fetch hosts from Docker swarm API, this was the original exception: %s ' %
to_native ( e ) )
def verify_file ( self , path ) :
def verify_file ( self , path ) :
""" Return the possibly of a file being consumable by this plugin. """
""" Return the possibly of a file being consumable by this plugin. """
@ -205,7 +246,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
def parse ( self , inventory , loader , path , cache = True ) :
def parse ( self , inventory , loader , path , cache = True ) :
if not HAS_DOCKER :
if not HAS_DOCKER :
raise AnsibleError ( ' The Docker swarm dynamic inventory plugin requires the Docker SDK for Python: https://github.com/docker/docker-py. ' )
raise AnsibleError ( ' The Docker swarm dynamic inventory plugin requires the Docker SDK for Python: '
' https://github.com/docker/docker-py. ' )
super ( InventoryModule , self ) . parse ( inventory , loader , path , cache )
super ( InventoryModule , self ) . parse ( inventory , loader , path , cache )
self . _read_config_data ( path )
self . _read_config_data ( path )
self . _populate ( )
self . _populate ( )