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
Hide 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__':
(
runner
,
results
)
=
cli
.
run
(
options
,
args
)
except
AnsibleError
as
e
:
# Generic handler for ansible specific errors
print
e
print
"ERROR:
%
s"
%
str
(
e
)
sys
.
exit
(
1
)
except
Exception
as
e2
:
print
e2
.
__class__
else
:
cli
.
output
(
runner
,
results
,
options
,
args
)
lib/ansible/connection.py
View file @
4ae98ed9
...
...
@@ -21,6 +21,7 @@
import
paramiko
import
exceptions
import
os
from
ansible.errors
import
*
################################################
...
...
@@ -39,18 +40,6 @@ class Connection(object):
raise
Exception
(
"unsupported connection type"
)
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?
# follow duck-typing of ParamikoConnection
...
...
@@ -80,7 +69,7 @@ class ParamikoConnection(object):
timeout
=
self
.
runner
.
timeout
)
except
Exception
,
e
:
raise
AnsibleConnection
Exception
(
str
(
e
))
raise
AnsibleConnection
Failed
(
str
(
e
))
return
self
def
exec_command
(
self
,
cmd
):
...
...
@@ -91,12 +80,12 @@ class ParamikoConnection(object):
def
put_file
(
self
,
in_path
,
out_path
):
''' transfer a file from local to remote '''
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
()
try
:
sftp
.
put
(
in_path
,
out_path
)
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
()
def
close
(
self
):
...
...
lib/ansible/errors.py
View file @
4ae98ed9
...
...
@@ -20,18 +20,18 @@ class AnsibleError(Exception):
"""
The base Ansible exception from which all others should subclass.
"""
def
__init__
(
self
,
msg
):
self
.
msg
=
msg
def
__str__
(
self
):
return
self
.
msg
class
AnsibleFileNotFound
(
AnsibleError
):
pass
class
AnsibleConnectionFailed
(
AnsibleError
):
pass
class
AnsibleInventoryNotFoundError
(
AnsibleError
):
"""
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
):
return
self
.
msg
lib/ansible/runner.py
View file @
4ae98ed9
...
...
@@ -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
:
import
json
except
ImportError
:
...
...
@@ -38,15 +33,14 @@ import Queue
import
random
import
jinja2
import
time
from
ansible.utils
import
*
from
ansible.errors
import
AnsibleInventoryNotFoundError
import
traceback
# 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
):
''' callback used by multiprocessing pool '''
...
...
@@ -58,6 +52,14 @@ def _executor_hook(job_queue, result_queue):
result_queue
.
put
(
runner
.
_executor
(
host
))
except
Queue
.
Empty
:
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
):
...
...
@@ -116,6 +118,8 @@ class Runner(object):
self
.
generated_jid
=
str
(
random
.
randint
(
0
,
999999999999
))
self
.
connector
=
ansible
.
connection
.
Connection
(
self
,
transport
)
# *****************************************************
@classmethod
def
parse_hosts
(
cls
,
host_list
):
'''
...
...
@@ -131,7 +135,7 @@ class Runner(object):
host_list
=
os
.
path
.
expanduser
(
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
"
)
groups
=
{}
...
...
@@ -154,9 +158,11 @@ class Runner(object):
return
(
results
,
groups
)
# *****************************************************
def
_matches
(
self
,
host_name
,
pattern
=
None
):
''' returns if a hostname is matched by the pattern '''
# a pattern is in fnmatch format but more than one pattern
# can be strung together with semicolons. ex:
# atlanta-web*.example.com;dc-web*.example.com
...
...
@@ -177,19 +183,25 @@ class Runner(object):
return
True
return
False
# *****************************************************
def
_connect
(
self
,
host
):
'''
obtains a connection to the host.
on success, returns (True, connection)
on failure, returns (False, traceback str)
'''
try
:
return
[
True
,
self
.
connector
.
connect
(
host
)
]
except
ansible
.
connection
.
AnsibleConnectionException
,
e
:
except
AnsibleConnectionFailed
,
e
:
return
[
False
,
"FAILED:
%
s"
%
str
(
e
)
]
# *****************************************************
def
_return_from_module
(
self
,
conn
,
host
,
result
):
''' helper function to handle JSON parsing of results '''
try
:
# try to parse the JSON response
return
[
host
,
True
,
json
.
loads
(
result
)
]
...
...
@@ -197,8 +209,11 @@ class Runner(object):
# it failed, say so, but return the string anyway
return
[
host
,
False
,
"
%
s/
%
s"
%
(
str
(
e
),
result
)
]
# *****************************************************
def
_delete_remote_files
(
self
,
conn
,
files
):
''' deletes one or more remote files '''
if
type
(
files
)
==
str
:
files
=
[
files
]
for
filename
in
files
:
...
...
@@ -206,25 +221,34 @@ class Runner(object):
raise
Exception
(
"not going to happen"
)
self
.
_exec_command
(
conn
,
"rm -rf
%
s"
%
filename
)
# *****************************************************
def
_transfer_file
(
self
,
conn
,
source
,
dest
):
''' transfers a remote file '''
self
.
remote_log
(
conn
,
'COPY remote:
%
s local:
%
s'
%
(
source
,
dest
))
conn
.
put_file
(
source
,
dest
)
# *****************************************************
def
_transfer_module
(
self
,
conn
,
tmp
,
module
):
'''
transfers a module file to the remote side to execute it,
but does not execute it yet
'''
outpath
=
self
.
_copy_module
(
conn
,
tmp
,
module
)
self
.
_exec_command
(
conn
,
"chmod +x
%
s"
%
outpath
)
return
outpath
# *****************************************************
def
_execute_module
(
self
,
conn
,
tmp
,
remote_module_path
,
module_args
):
'''
runs a module that has already been transferred, but first
modifies the command using setup_cache variables (see playbook)
'''
args
=
module_args
if
type
(
args
)
==
list
:
args
=
[
str
(
x
)
for
x
in
module_args
]
...
...
@@ -248,13 +272,15 @@ class Runner(object):
result
=
self
.
_exec_command
(
conn
,
cmd
)
return
result
# *****************************************************
def
_execute_normal_module
(
self
,
conn
,
host
,
tmp
):
'''
transfer & execute a module that is not 'copy' or 'template'
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
)
# when running the setup module, which pushes vars to the host and ALSO
...
...
@@ -270,11 +296,14 @@ class Runner(object):
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_execute_async_module
(
self
,
conn
,
host
,
tmp
):
'''
transfer the given module name, plus the async module
and then run the async module wrapping the other module
'''
async
=
self
.
_transfer_module
(
conn
,
tmp
,
'async_wrapper'
)
module
=
self
.
_transfer_module
(
conn
,
tmp
,
self
.
module_name
)
new_args
=
[]
...
...
@@ -283,8 +312,12 @@ class Runner(object):
result
=
self
.
_execute_module
(
conn
,
tmp
,
async
,
new_args
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_parse_kv
(
self
,
args
):
# FIXME: move to utils
''' helper function to convert a string of key/value items to a dict '''
options
=
{}
for
x
in
args
:
if
x
.
find
(
"="
)
!=
-
1
:
...
...
@@ -292,6 +325,8 @@ class Runner(object):
options
[
k
]
=
v
return
options
# *****************************************************
def
_execute_copy
(
self
,
conn
,
host
,
tmp
):
''' handler for file transfer operations '''
...
...
@@ -314,6 +349,8 @@ class Runner(object):
result
=
self
.
_execute_module
(
conn
,
tmp
,
module
,
args
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_execute_template
(
self
,
conn
,
host
,
tmp
):
''' handler for template operations '''
...
...
@@ -343,6 +380,7 @@ class Runner(object):
result
=
self
.
_execute_module
(
conn
,
tmp
,
template_module
,
args
)
return
self
.
_return_from_module
(
conn
,
host
,
result
)
# *****************************************************
def
_executor
(
self
,
host
):
'''
...
...
@@ -382,47 +420,57 @@ class Runner(object):
return
result
# *****************************************************
def
remote_log
(
self
,
conn
,
msg
):
''' this is the function we use to log things '''
# 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
)
# *****************************************************
def
_exec_command
(
self
,
conn
,
cmd
):
''' execute a command string over SSH, return the output '''
msg
=
'
%
s:
%
s'
%
(
self
.
module_name
,
cmd
)
self
.
remote_log
(
conn
,
msg
)
stdin
,
stdout
,
stderr
=
conn
.
exec_command
(
cmd
)
results
=
"
\n
"
.
join
(
stdout
.
readlines
())
return
results
# *****************************************************
def
_get_tmp_path
(
self
,
conn
):
''' gets a temporary path on a remote box '''
result
=
self
.
_exec_command
(
conn
,
"mktemp -d /tmp/ansible.XXXXXX"
)
return
result
.
split
(
"
\n
"
)[
0
]
+
'/'
# *****************************************************
def
_copy_module
(
self
,
conn
,
tmp
,
module
):
''' transfer a module over SFTP, does not run it '''
if
module
.
startswith
(
"/"
):
# user probably did "/bin/foo" instead of "command /bin/foo" in a playbook
# or tried "-m /bin/foo" instead of "a /bin/foo"
# FIXME: type this exception
raise
Exception
(
"
%
s is not a module"
%
module
)
in_path
=
os
.
path
.
expanduser
(
os
.
path
.
join
(
self
.
module_path
,
module
)
)
raise
AnsibleFileNotFound
(
"
%
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
):
# FIXME: type this exception
raise
Exception
(
"module not found:
%
s"
%
in_path
)
raise
AnsibleFileNotFound
(
"module not found:
%
s"
%
in_path
)
out_path
=
tmp
+
module
conn
.
put_file
(
in_path
,
out_path
)
return
out_path
# *****************************************************
def
match_hosts
(
self
,
pattern
):
''' return all matched hosts fitting a pattern '''
return
[
h
for
h
in
self
.
host_list
if
self
.
_matches
(
h
,
pattern
)
]
# *****************************************************
def
run
(
self
):
''' xfer & run module on all matched hosts '''
...
...
lib/ansible/utils.py
View file @
4ae98ed9
...
...
@@ -136,7 +136,7 @@ def dark_hosts_msg(results):
''' summarize the results of all uncontactable hosts '''
buf
=
''
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
():
buf
+=
"
%
s:
%
s
\n
"
%
(
hostname
,
results
[
'dark'
][
hostname
])
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