Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
ansible
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
ansible
Commits
4ae98ed9
Commit
4ae98ed9
authored
Mar 13, 2012
by
Michael DeHaan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upgrades to error handling, now general try/catch available.
parent
2e1b59a9
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
91 additions
and
51 deletions
+91
-51
bin/ansible
+4
-1
lib/ansible/connection.py
+4
-15
lib/ansible/errors.py
+11
-11
lib/ansible/runner.py
+71
-23
lib/ansible/utils.py
+1
-1
No files found.
bin/ansible
View file @
4ae98ed9
...
@@ -198,7 +198,10 @@ if __name__ == '__main__':
...
@@ -198,7 +198,10 @@ if __name__ == '__main__':
(
runner
,
results
)
=
cli
.
run
(
options
,
args
)
(
runner
,
results
)
=
cli
.
run
(
options
,
args
)
except
AnsibleError
as
e
:
except
AnsibleError
as
e
:
# Generic handler for ansible specific errors
# Generic handler for ansible specific errors
print
e
print
"ERROR:
%
s"
%
str
(
e
)
sys
.
exit
(
1
)
sys
.
exit
(
1
)
except
Exception
as
e2
:
print
e2
.
__class__
else
:
else
:
cli
.
output
(
runner
,
results
,
options
,
args
)
cli
.
output
(
runner
,
results
,
options
,
args
)
lib/ansible/connection.py
View file @
4ae98ed9
...
@@ -21,6 +21,7 @@
...
@@ -21,6 +21,7 @@
import
paramiko
import
paramiko
import
exceptions
import
exceptions
import
os
import
os
from
ansible.errors
import
*
################################################
################################################
...
@@ -39,18 +40,6 @@ class Connection(object):
...
@@ -39,18 +40,6 @@ class Connection(object):
raise
Exception
(
"unsupported connection type"
)
raise
Exception
(
"unsupported connection type"
)
return
conn
.
connect
()
return
conn
.
connect
()
################################################
class
AnsibleConnectionException
(
exceptions
.
Exception
):
''' Subclass of exception for catching in Runner() code '''
def
__init__
(
self
,
value
):
self
.
value
=
value
def
__str__
(
self
):
return
repr
(
self
.
value
)
################################################
################################################
# want to implement another connection type?
# want to implement another connection type?
# follow duck-typing of ParamikoConnection
# follow duck-typing of ParamikoConnection
...
@@ -80,7 +69,7 @@ class ParamikoConnection(object):
...
@@ -80,7 +69,7 @@ class ParamikoConnection(object):
timeout
=
self
.
runner
.
timeout
timeout
=
self
.
runner
.
timeout
)
)
except
Exception
,
e
:
except
Exception
,
e
:
raise
AnsibleConnection
Exception
(
str
(
e
))
raise
AnsibleConnection
Failed
(
str
(
e
))
return
self
return
self
def
exec_command
(
self
,
cmd
):
def
exec_command
(
self
,
cmd
):
...
@@ -91,12 +80,12 @@ class ParamikoConnection(object):
...
@@ -91,12 +80,12 @@ class ParamikoConnection(object):
def
put_file
(
self
,
in_path
,
out_path
):
def
put_file
(
self
,
in_path
,
out_path
):
''' transfer a file from local to remote '''
''' transfer a file from local to remote '''
if
not
os
.
path
.
exists
(
in_path
):
if
not
os
.
path
.
exists
(
in_path
):
raise
Ansible
ConnectionException
(
"file or module does not exist:
%
s"
%
in_path
)
raise
Ansible
FileNotFound
(
"file or module does not exist:
%
s"
%
in_path
)
sftp
=
self
.
ssh
.
open_sftp
()
sftp
=
self
.
ssh
.
open_sftp
()
try
:
try
:
sftp
.
put
(
in_path
,
out_path
)
sftp
.
put
(
in_path
,
out_path
)
except
IOError
:
except
IOError
:
raise
Ansible
Connection
Exception
(
"failed to transfer file to
%
s"
%
out_path
)
raise
AnsibleException
(
"failed to transfer file to
%
s"
%
out_path
)
sftp
.
close
()
sftp
.
close
()
def
close
(
self
):
def
close
(
self
):
...
...
lib/ansible/errors.py
View file @
4ae98ed9
...
@@ -20,18 +20,18 @@ class AnsibleError(Exception):
...
@@ -20,18 +20,18 @@ class AnsibleError(Exception):
"""
"""
The base Ansible exception from which all others should subclass.
The base Ansible exception from which all others should subclass.
"""
"""
pass
class
AnsibleInventoryNotFoundError
(
AnsibleError
):
def
__init__
(
self
,
msg
):
"""
self
.
msg
=
msg
Exception raised when the default or provided host inventory file
does not exist.
"""
def
__init__
(
self
,
inventory
):
self
.
inventory
=
inventory
self
.
msg
=
"Unable to continue, inventory file not found:
%
s"
%
\
self
.
inventory
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
msg
return
self
.
msg
class
AnsibleFileNotFound
(
AnsibleError
):
pass
class
AnsibleConnectionFailed
(
AnsibleError
):
pass
lib/ansible/runner.py
View file @
4ae98ed9
...
@@ -18,11 +18,6 @@
...
@@ -18,11 +18,6 @@
################################################
################################################
# FIXME: need to add global error handling around
# executor_hook mapping all exceptions into failures
# with the traceback converted into a string and
# if the exception is typed, a *nice* string
try
:
try
:
import
json
import
json
except
ImportError
:
except
ImportError
:
...
@@ -38,15 +33,14 @@ import Queue
...
@@ -38,15 +33,14 @@ import Queue
import
random
import
random
import
jinja2
import
jinja2
import
time
import
time
from
ansible.utils
import
*
import
traceback
from
ansible.errors
import
AnsibleInventoryNotFoundError
# FIXME: stop importing *, use as utils/errors
from
ansible.utils
import
*
from
ansible.errors
import
*
################################################
################################################
def
noop
(
*
args
,
**
kwargs
):
pass
def
_executor_hook
(
job_queue
,
result_queue
):
def
_executor_hook
(
job_queue
,
result_queue
):
''' callback used by multiprocessing pool '''
''' callback used by multiprocessing pool '''
...
@@ -58,6 +52,14 @@ def _executor_hook(job_queue, result_queue):
...
@@ -58,6 +52,14 @@ def _executor_hook(job_queue, result_queue):
result_queue
.
put
(
runner
.
_executor
(
host
))
result_queue
.
put
(
runner
.
_executor
(
host
))
except
Queue
.
Empty
:
except
Queue
.
Empty
:
pass
pass
except
AnsibleError
,
ae
:
result_queue
.
put
([
host
,
False
,
str
(
ae
)])
except
Exception
,
ee
:
# probably should include the full trace
result_queue
.
put
([
host
,
False
,
traceback
.
format_exc
()])
################################################
class
Runner
(
object
):
class
Runner
(
object
):
...
@@ -116,6 +118,8 @@ class Runner(object):
...
@@ -116,6 +118,8 @@ class Runner(object):
self
.
generated_jid
=
str
(
random
.
randint
(
0
,
999999999999
))
self
.
generated_jid
=
str
(
random
.
randint
(
0
,
999999999999
))
self
.
connector
=
ansible
.
connection
.
Connection
(
self
,
transport
)
self
.
connector
=
ansible
.
connection
.
Connection
(
self
,
transport
)
# *****************************************************
@classmethod
@classmethod
def
parse_hosts
(
cls
,
host_list
):
def
parse_hosts
(
cls
,
host_list
):
'''
'''
...
@@ -131,7 +135,7 @@ class Runner(object):
...
@@ -131,7 +135,7 @@ class Runner(object):
host_list
=
os
.
path
.
expanduser
(
host_list
)
host_list
=
os
.
path
.
expanduser
(
host_list
)
if
not
os
.
path
.
exists
(
host_list
):
if
not
os
.
path
.
exists
(
host_list
):
raise
Ansible
InventoryNotFoundError
(
host_list
)
raise
Ansible
FileNotFound
(
"inventory file not found:
%
s"
%
host_list
)
lines
=
file
(
host_list
)
.
read
()
.
split
(
"
\n
"
)
lines
=
file
(
host_list
)
.
read
()
.
split
(
"
\n
"
)
groups
=
{}
groups
=
{}
...
@@ -154,9 +158,11 @@ class Runner(object):
...
@@ -154,9 +158,11 @@ class Runner(object):
return
(
results
,
groups
)
return
(
results
,
groups
)
# *****************************************************
def
_matches
(
self
,
host_name
,
pattern
=
None
):
def
_matches
(
self
,
host_name
,
pattern
=
None
):
''' returns if a hostname is matched by the pattern '''
''' returns if a hostname is matched by the pattern '''
# a pattern is in fnmatch format but more than one pattern
# a pattern is in fnmatch format but more than one pattern
# can be strung together with semicolons. ex:
# can be strung together with semicolons. ex:
# atlanta-web*.example.com;dc-web*.example.com
# atlanta-web*.example.com;dc-web*.example.com
...
@@ -177,19 +183,25 @@ class Runner(object):
...
@@ -177,19 +183,25 @@ class Runner(object):
return
True
return
True
return
False
return
False
# *****************************************************
def
_connect
(
self
,
host
):
def
_connect
(
self
,
host
):
'''
'''
obtains a connection to the host.
obtains a connection to the host.
on success, returns (True, connection)
on success, returns (True, connection)
on failure, returns (False, traceback str)
on failure, returns (False, traceback str)
'''
'''
try
:
try
:
return
[
True
,
self
.
connector
.
connect
(
host
)
]
return
[
True
,
self
.
connector
.
connect
(
host
)
]
except
ansible
.
connection
.
AnsibleConnectionException
,
e
:
except
AnsibleConnectionFailed
,
e
:
return
[
False
,
"FAILED:
%
s"
%
str
(
e
)
]
return
[
False
,
"FAILED:
%
s"
%
str
(
e
)
]
# *****************************************************
def
_return_from_module
(
self
,
conn
,
host
,
result
):
def
_return_from_module
(
self
,
conn
,
host
,
result
):
''' helper function to handle JSON parsing of results '''
''' helper function to handle JSON parsing of results '''
try
:
try
:
# try to parse the JSON response
# try to parse the JSON response
return
[
host
,
True
,
json
.
loads
(
result
)
]
return
[
host
,
True
,
json
.
loads
(
result
)
]
...
@@ -197,8 +209,11 @@ class Runner(object):
...
@@ -197,8 +209,11 @@ class Runner(object):
# it failed, say so, but return the string anyway
# it failed, say so, but return the string anyway
return
[
host
,
False
,
"
%
s/
%
s"
%
(
str
(
e
),
result
)
]
return
[
host
,
False
,
"
%
s/
%
s"
%
(
str
(
e
),
result
)
]
# *****************************************************
def
_delete_remote_files
(
self
,
conn
,
files
):
def
_delete_remote_files
(
self
,
conn
,
files
):
''' deletes one or more remote files '''
''' deletes one or more remote files '''
if
type
(
files
)
==
str
:
if
type
(
files
)
==
str
:
files
=
[
files
]
files
=
[
files
]
for
filename
in
files
:
for
filename
in
files
:
...
@@ -206,25 +221,34 @@ class Runner(object):
...
@@ -206,25 +221,34 @@ class Runner(object):
raise
Exception
(
"not going to happen"
)
raise
Exception
(
"not going to happen"
)
self
.
_exec_command
(
conn
,
"rm -rf
%
s"
%
filename
)
self
.
_exec_command
(
conn
,
"rm -rf
%
s"
%
filename
)
# *****************************************************
def
_transfer_file
(
self
,
conn
,
source
,
dest
):
def
_transfer_file
(
self
,
conn
,
source
,
dest
):
''' transfers a remote file '''
''' transfers a remote file '''
self
.
remote_log
(
conn
,
'COPY remote:
%
s local:
%
s'
%
(
source
,
dest
))
self
.
remote_log
(
conn
,
'COPY remote:
%
s local:
%
s'
%
(
source
,
dest
))
conn
.
put_file
(
source
,
dest
)
conn
.
put_file
(
source
,
dest
)
# *****************************************************
def
_transfer_module
(
self
,
conn
,
tmp
,
module
):
def
_transfer_module
(
self
,
conn
,
tmp
,
module
):
'''
'''
transfers a module file to the remote side to execute it,
transfers a module file to the remote side to execute it,
but does not execute it yet
but does not execute it yet
'''
'''
outpath
=
self
.
_copy_module
(
conn
,
tmp
,
module
)
outpath
=
self
.
_copy_module
(
conn
,
tmp
,
module
)
self
.
_exec_command
(
conn
,
"chmod +x
%
s"
%
outpath
)
self
.
_exec_command
(
conn
,
"chmod +x
%
s"
%
outpath
)
return
outpath
return
outpath
# *****************************************************
def
_execute_module
(
self
,
conn
,
tmp
,
remote_module_path
,
module_args
):
def
_execute_module
(
self
,
conn
,
tmp
,
remote_module_path
,
module_args
):
'''
'''
runs a module that has already been transferred, but first
runs a module that has already been transferred, but first
modifies the command using setup_cache variables (see playbook)
modifies the command using setup_cache variables (see playbook)
'''
'''
args
=
module_args
args
=
module_args
if
type
(
args
)
==
list
:
if
type
(
args
)
==
list
:
args
=
[
str
(
x
)
for
x
in
module_args
]
args
=
[
str
(
x
)
for
x
in
module_args
]
...
@@ -248,13 +272,15 @@ class Runner(object):
...
@@ -248,13 +272,15 @@ class Runner(object):
result
=
self
.
_exec_command
(
conn
,
cmd
)
result
=
self
.
_exec_command
(
conn
,
cmd
)
return
result
return
result
# *****************************************************
def
_execute_normal_module
(
self
,
conn
,
host
,
tmp
):
def
_execute_normal_module
(
self
,
conn
,
host
,
tmp
):
'''
'''
transfer & execute a module that is not 'copy' or 'template'
transfer & execute a module that is not 'copy' or 'template'
because those require extra work.
because those require extra work.
'''
'''
module
=
self
.
_transfer_module
(
conn
,
tmp
,
self
.
module_name
)
module
=
self
.
_transfer_module
(
conn
,
tmp
,
self
.
module_name
)
result
=
self
.
_execute_module
(
conn
,
tmp
,
module
,
self
.
module_args
)
result
=
self
.
_execute_module
(
conn
,
tmp
,
module
,
self
.
module_args
)
# when running the setup module, which pushes vars to the host and ALSO
# when running the setup module, which pushes vars to the host and ALSO
...
@@ -270,11 +296,14 @@ class Runner(object):
...
@@ -270,11 +296,14 @@ class Runner(object):
return
self
.
_return_from_module
(
conn
,
host
,
result
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_execute_async_module
(
self
,
conn
,
host
,
tmp
):
def
_execute_async_module
(
self
,
conn
,
host
,
tmp
):
'''
'''
transfer the given module name, plus the async module
transfer the given module name, plus the async module
and then run the async module wrapping the other module
and then run the async module wrapping the other module
'''
'''
async
=
self
.
_transfer_module
(
conn
,
tmp
,
'async_wrapper'
)
async
=
self
.
_transfer_module
(
conn
,
tmp
,
'async_wrapper'
)
module
=
self
.
_transfer_module
(
conn
,
tmp
,
self
.
module_name
)
module
=
self
.
_transfer_module
(
conn
,
tmp
,
self
.
module_name
)
new_args
=
[]
new_args
=
[]
...
@@ -283,8 +312,12 @@ class Runner(object):
...
@@ -283,8 +312,12 @@ class Runner(object):
result
=
self
.
_execute_module
(
conn
,
tmp
,
async
,
new_args
)
result
=
self
.
_execute_module
(
conn
,
tmp
,
async
,
new_args
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_parse_kv
(
self
,
args
):
def
_parse_kv
(
self
,
args
):
# FIXME: move to utils
''' helper function to convert a string of key/value items to a dict '''
''' helper function to convert a string of key/value items to a dict '''
options
=
{}
options
=
{}
for
x
in
args
:
for
x
in
args
:
if
x
.
find
(
"="
)
!=
-
1
:
if
x
.
find
(
"="
)
!=
-
1
:
...
@@ -292,6 +325,8 @@ class Runner(object):
...
@@ -292,6 +325,8 @@ class Runner(object):
options
[
k
]
=
v
options
[
k
]
=
v
return
options
return
options
# *****************************************************
def
_execute_copy
(
self
,
conn
,
host
,
tmp
):
def
_execute_copy
(
self
,
conn
,
host
,
tmp
):
''' handler for file transfer operations '''
''' handler for file transfer operations '''
...
@@ -314,6 +349,8 @@ class Runner(object):
...
@@ -314,6 +349,8 @@ class Runner(object):
result
=
self
.
_execute_module
(
conn
,
tmp
,
module
,
args
)
result
=
self
.
_execute_module
(
conn
,
tmp
,
module
,
args
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_execute_template
(
self
,
conn
,
host
,
tmp
):
def
_execute_template
(
self
,
conn
,
host
,
tmp
):
''' handler for template operations '''
''' handler for template operations '''
...
@@ -343,6 +380,7 @@ class Runner(object):
...
@@ -343,6 +380,7 @@ class Runner(object):
result
=
self
.
_execute_module
(
conn
,
tmp
,
template_module
,
args
)
result
=
self
.
_execute_module
(
conn
,
tmp
,
template_module
,
args
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_executor
(
self
,
host
):
def
_executor
(
self
,
host
):
'''
'''
...
@@ -382,47 +420,57 @@ class Runner(object):
...
@@ -382,47 +420,57 @@ class Runner(object):
return
result
return
result
# *****************************************************
def
remote_log
(
self
,
conn
,
msg
):
def
remote_log
(
self
,
conn
,
msg
):
''' this is the function we use to log things '''
''' this is the function we use to log things '''
# FIXME: TODO: make this optional as it's executed a lot
# FIXME: TODO: make this optional as it's executed a lot
stdin
,
stdout
,
stderr
=
conn
.
exec_command
(
'/usr/bin/logger -t ansible -p auth.info "
%
s"'
%
msg
)
stdin
,
stdout
,
stderr
=
conn
.
exec_command
(
'/usr/bin/logger -t ansible -p auth.info "
%
s"'
%
msg
)
# *****************************************************
def
_exec_command
(
self
,
conn
,
cmd
):
def
_exec_command
(
self
,
conn
,
cmd
):
''' execute a command string over SSH, return the output '''
''' execute a command string over SSH, return the output '''
msg
=
'
%
s:
%
s'
%
(
self
.
module_name
,
cmd
)
msg
=
'
%
s:
%
s'
%
(
self
.
module_name
,
cmd
)
self
.
remote_log
(
conn
,
msg
)
self
.
remote_log
(
conn
,
msg
)
stdin
,
stdout
,
stderr
=
conn
.
exec_command
(
cmd
)
stdin
,
stdout
,
stderr
=
conn
.
exec_command
(
cmd
)
results
=
"
\n
"
.
join
(
stdout
.
readlines
())
results
=
"
\n
"
.
join
(
stdout
.
readlines
())
return
results
return
results
# *****************************************************
def
_get_tmp_path
(
self
,
conn
):
def
_get_tmp_path
(
self
,
conn
):
''' gets a temporary path on a remote box '''
''' gets a temporary path on a remote box '''
result
=
self
.
_exec_command
(
conn
,
"mktemp -d /tmp/ansible.XXXXXX"
)
result
=
self
.
_exec_command
(
conn
,
"mktemp -d /tmp/ansible.XXXXXX"
)
return
result
.
split
(
"
\n
"
)[
0
]
+
'/'
return
result
.
split
(
"
\n
"
)[
0
]
+
'/'
# *****************************************************
def
_copy_module
(
self
,
conn
,
tmp
,
module
):
def
_copy_module
(
self
,
conn
,
tmp
,
module
):
''' transfer a module over SFTP, does not run it '''
''' transfer a module over SFTP, does not run it '''
if
module
.
startswith
(
"/"
):
if
module
.
startswith
(
"/"
):
# user probably did "/bin/foo" instead of "command /bin/foo" in a playbook
raise
AnsibleFileNotFound
(
"
%
s is not a module"
%
module
)
# or tried "-m /bin/foo" instead of "a /bin/foo"
in_path
=
os
.
path
.
expanduser
(
os
.
path
.
join
(
self
.
module_path
,
module
))
# FIXME: type this exception
raise
Exception
(
"
%
s is not a module"
%
module
)
in_path
=
os
.
path
.
expanduser
(
os
.
path
.
join
(
self
.
module_path
,
module
)
)
if
not
os
.
path
.
exists
(
in_path
):
if
not
os
.
path
.
exists
(
in_path
):
# FIXME: type this exception
raise
AnsibleFileNotFound
(
"module not found:
%
s"
%
in_path
)
raise
Exception
(
"module not found:
%
s"
%
in_path
)
out_path
=
tmp
+
module
out_path
=
tmp
+
module
conn
.
put_file
(
in_path
,
out_path
)
conn
.
put_file
(
in_path
,
out_path
)
return
out_path
return
out_path
# *****************************************************
def
match_hosts
(
self
,
pattern
):
def
match_hosts
(
self
,
pattern
):
''' return all matched hosts fitting a pattern '''
''' return all matched hosts fitting a pattern '''
return
[
h
for
h
in
self
.
host_list
if
self
.
_matches
(
h
,
pattern
)
]
return
[
h
for
h
in
self
.
host_list
if
self
.
_matches
(
h
,
pattern
)
]
# *****************************************************
def
run
(
self
):
def
run
(
self
):
''' xfer & run module on all matched hosts '''
''' xfer & run module on all matched hosts '''
...
...
lib/ansible/utils.py
View file @
4ae98ed9
...
@@ -136,7 +136,7 @@ def dark_hosts_msg(results):
...
@@ -136,7 +136,7 @@ def dark_hosts_msg(results):
''' summarize the results of all uncontactable hosts '''
''' summarize the results of all uncontactable hosts '''
buf
=
''
buf
=
''
if
len
(
results
[
'dark'
]
.
keys
())
>
0
:
if
len
(
results
[
'dark'
]
.
keys
())
>
0
:
buf
+=
"
\n
*** Hosts w
hich could not be contacted or did not respond
: ***
\n
"
buf
+=
"
\n
*** Hosts w
ith fatal errors
: ***
\n
"
for
hostname
in
results
[
'dark'
]
.
keys
():
for
hostname
in
results
[
'dark'
]
.
keys
():
buf
+=
"
%
s:
%
s
\n
"
%
(
hostname
,
results
[
'dark'
][
hostname
])
buf
+=
"
%
s:
%
s
\n
"
%
(
hostname
,
results
[
'dark'
][
hostname
])
buf
+=
"
\n
"
buf
+=
"
\n
"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment