commit
d81ea397aa
62 changed files with 259 additions and 357 deletions
|
@ -10,9 +10,10 @@ include examples/ansible.cfg
|
|||
include lib/ansible/module_utils/powershell.ps1
|
||||
recursive-include lib/ansible/modules *
|
||||
recursive-include docs *
|
||||
recursive-include plugins *
|
||||
include Makefile
|
||||
include VERSION
|
||||
include MANIFEST.in
|
||||
include contrib/README.md
|
||||
include contrib/inventory *
|
||||
prune lib/ansible/modules/core/.git
|
||||
prune lib/ansible/modules/extras/.git
|
||||
|
|
17
contrib/README.md
Normal file
17
contrib/README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
inventory
|
||||
=========
|
||||
|
||||
Inventory scripts allow you to store your hosts, groups, and variables in any way
|
||||
you like. Examples include discovering inventory from EC2 or pulling it from
|
||||
Cobbler. These could also be used to interface with LDAP or database.
|
||||
|
||||
chmod +x an inventory plugin and either name it /etc/ansible/hosts or use ansible
|
||||
with -i to designate the path to the script. You might also need to copy a configuration
|
||||
file with the same name and/or set environment variables, the scripts or configuration
|
||||
files have more details.
|
||||
|
||||
contributions welcome
|
||||
=====================
|
||||
|
||||
Send in pull requests to add plugins of your own. The sky is the limit!
|
||||
|
0
plugins/inventory/nova.py → contrib/inventory/nova.py
Normal file → Executable file
0
plugins/inventory/nova.py → contrib/inventory/nova.py
Normal file → Executable file
0
plugins/inventory/rax.py → contrib/inventory/rax.py
Normal file → Executable file
0
plugins/inventory/rax.py → contrib/inventory/rax.py
Normal file → Executable file
|
@ -296,7 +296,7 @@ class TaskQueueManager:
|
|||
continue
|
||||
methods = [
|
||||
getattr(callback_plugin, method_name, None),
|
||||
getattr(callback_plugin, 'on_any', None)
|
||||
getattr(callback_plugin, 'v2_on_any', None)
|
||||
]
|
||||
for method in methods:
|
||||
if method is not None:
|
||||
|
|
|
@ -36,9 +36,7 @@ class CallbackBase:
|
|||
self._display = display
|
||||
|
||||
def set_connection_info(self, conn_info):
|
||||
# FIXME: this is a temporary hack, as the connection info object
|
||||
# should be created early and passed down through objects
|
||||
self._display._verbosity = conn_info.verbosity
|
||||
pass
|
||||
|
||||
def on_any(self, *args, **kwargs):
|
||||
pass
|
||||
|
@ -100,3 +98,90 @@ class CallbackBase:
|
|||
def playbook_on_stats(self, stats):
|
||||
pass
|
||||
|
||||
####### V2 METHODS, by default they call v1 counterparts if possible ######
|
||||
def v2_on_any(self, *args, **kwargs):
|
||||
self.on_any(args, kwargs)
|
||||
|
||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||
host = result._host.get_name()
|
||||
self.runner_on_failed(host, result._result, ignore_errors)
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
host = result._host.get_name()
|
||||
self.runner_on_ok(host, result._result)
|
||||
|
||||
def v2_runner_on_skipped(self, result):
|
||||
host = result._host.get_name()
|
||||
#FIXME, get item to pass through
|
||||
item = None
|
||||
self.runner_on_skipped(host, item)
|
||||
|
||||
def v2_runner_on_unreachable(self, result):
|
||||
host = result._host.get_name()
|
||||
self.runner_on_unreachable(host, result._result)
|
||||
|
||||
def v2_runner_on_no_hosts(self, task):
|
||||
self.runner_on_no_hosts()
|
||||
|
||||
def v2_runner_on_async_poll(self, result):
|
||||
host = result._host.get_name()
|
||||
jid = result._result.get('ansible_job_id')
|
||||
#FIXME, get real clock
|
||||
clock = 0
|
||||
self.runner_on_async_poll(host, result._result, jid, clock)
|
||||
|
||||
def v2_runner_on_async_ok(self, result):
|
||||
host = result._host.get_name()
|
||||
jid = result._result.get('ansible_job_id')
|
||||
self.runner_on_async_ok(host, result._result, jid)
|
||||
|
||||
def v2_runner_on_async_failed(self, result):
|
||||
host = result._host.get_name()
|
||||
jid = result._result.get('ansible_job_id')
|
||||
self.runner_on_async_failed(host, result._result, jid)
|
||||
|
||||
def v2_runner_on_file_diff(self, result, diff):
|
||||
pass #no v1 correspondance
|
||||
|
||||
def v2_playbook_on_start(self):
|
||||
self.playbook_on_start()
|
||||
|
||||
def v2_playbook_on_notify(self, result, handler):
|
||||
host = result._host.get_name()
|
||||
self.playbook_on_notify(host, handler)
|
||||
|
||||
def v2_playbook_on_no_hosts_matched(self):
|
||||
self.playbook_on_no_hosts_matched()
|
||||
|
||||
def v2_playbook_on_no_hosts_remaining(self):
|
||||
self.playbook_on_no_hosts_remaining()
|
||||
|
||||
def v2_playbook_on_task_start(self, task, is_conditional):
|
||||
self.playbook_on_task_start(task, is_conditional)
|
||||
|
||||
def v2_playbook_on_cleanup_task_start(self, task):
|
||||
pass #no v1 correspondance
|
||||
|
||||
def v2_playbook_on_handler_task_start(self, task):
|
||||
pass #no v1 correspondance
|
||||
|
||||
def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
||||
self.playbook_on_vars_prompt(varname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
||||
|
||||
def v2_playbook_on_setup(self):
|
||||
self.playbook_on_setup()
|
||||
|
||||
def v2_playbook_on_import_for_host(self, result, imported_file):
|
||||
host = result._host.get_name()
|
||||
self.playbook_on_import_for_host(host, imported_file)
|
||||
|
||||
def v2_playbook_on_not_import_for_host(self, result, missing_file):
|
||||
host = result._host.get_name()
|
||||
self.playbook_on_not_import_for_host(host, missing_file)
|
||||
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
self.playbook_on_play_start(play.name)
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
self.playbook_on_stats(stats)
|
||||
|
||||
|
|
|
@ -15,17 +15,23 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
class CallbackModule(object):
|
||||
class CallbackModule(CallbackBase):
|
||||
"""
|
||||
This is a very trivial example of how any callback function can get at play and task objects.
|
||||
play will be 'None' for runner invocations, and task will be None for 'setup' invocations.
|
||||
"""
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
|
||||
def on_any(self, *args, **kwargs):
|
||||
play = getattr(self, 'play', None)
|
||||
task = getattr(self, 'task', None)
|
||||
print "play = %s, task = %s, args = %s, kwargs = %s" % (play,task,args,kwargs)
|
||||
def v2_on_any(self, *args, **kwargs):
|
||||
i = 0
|
||||
self._display.display(" --- ARGS ")
|
||||
for a in args:
|
||||
self._display.display(' %s: %s' % (i, a))
|
||||
i += 1
|
||||
|
||||
self._display.display(" --- KWARGS ")
|
||||
for k in kwargs:
|
||||
self._display.display(' %s: %s' % (k, kwargs[k]))
|
|
@ -33,9 +33,6 @@ class CallbackModule(CallbackBase):
|
|||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'stdout'
|
||||
|
||||
def v2_on_any(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||
if 'exception' in result._result:
|
||||
if self._display.verbosity < 3:
|
||||
|
@ -67,7 +64,7 @@ class CallbackModule(CallbackBase):
|
|||
msg = "ok: [%s]" % result._host.get_name()
|
||||
color = 'green'
|
||||
|
||||
if (self._display._verbosity > 0 or 'verbose_always' in result._result) and result._task.action not in ('setup', 'include'):
|
||||
if (self._display.verbosity > 0 or 'verbose_always' in result._result) and result._task.action not in ('setup', 'include'):
|
||||
indent = None
|
||||
if 'verbose_always' in result._result:
|
||||
indent = 4
|
||||
|
@ -77,7 +74,7 @@ class CallbackModule(CallbackBase):
|
|||
|
||||
def v2_runner_on_skipped(self, result):
|
||||
msg = "skipping: [%s]" % result._host.get_name()
|
||||
if self._display._verbosity > 0 or 'verbose_always' in result._result:
|
||||
if self._display.verbosity > 0 or 'verbose_always' in result._result:
|
||||
indent = None
|
||||
if 'verbose_always' in result._result:
|
||||
indent = 4
|
||||
|
@ -88,27 +85,6 @@ class CallbackModule(CallbackBase):
|
|||
def v2_runner_on_unreachable(self, result):
|
||||
self._display.display("fatal: [%s]: UNREACHABLE! => %s" % (result._host.get_name(), result._result), color='red')
|
||||
|
||||
def v2_runner_on_no_hosts(self, task):
|
||||
pass
|
||||
|
||||
def v2_runner_on_async_poll(self, result):
|
||||
pass
|
||||
|
||||
def v2_runner_on_async_ok(self, result):
|
||||
pass
|
||||
|
||||
def v2_runner_on_async_failed(self, result):
|
||||
pass
|
||||
|
||||
def v2_runner_on_file_diff(self, result, diff):
|
||||
pass
|
||||
|
||||
def v2_playbook_on_start(self):
|
||||
pass
|
||||
|
||||
def v2_playbook_on_notify(self, result, handler):
|
||||
pass
|
||||
|
||||
def v2_playbook_on_no_hosts_matched(self):
|
||||
self._display.display("skipping: no hosts matched", color='cyan')
|
||||
|
||||
|
@ -124,18 +100,6 @@ class CallbackModule(CallbackBase):
|
|||
def v2_playbook_on_handler_task_start(self, task):
|
||||
self._display.banner("RUNNING HANDLER [%s]" % task.get_name().strip())
|
||||
|
||||
#def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
||||
# pass
|
||||
|
||||
def v2_playbook_on_setup(self):
|
||||
pass
|
||||
|
||||
def v2_playbook_on_import_for_host(self, result, imported_file):
|
||||
pass
|
||||
|
||||
def v2_playbook_on_not_import_for_host(self, result, missing_file):
|
||||
pass
|
||||
|
||||
def v2_playbook_on_play_start(self, play):
|
||||
name = play.get_name().strip()
|
||||
if not name:
|
||||
|
@ -144,7 +108,3 @@ class CallbackModule(CallbackBase):
|
|||
msg = "PLAY [%s]" % name
|
||||
|
||||
self._display.banner(name)
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
pass
|
||||
|
||||
|
|
|
@ -19,16 +19,15 @@ import os
|
|||
import urllib
|
||||
import urllib2
|
||||
|
||||
from ansible import utils
|
||||
|
||||
try:
|
||||
import prettytable
|
||||
HAS_PRETTYTABLE = True
|
||||
except ImportError:
|
||||
HAS_PRETTYTABLE = False
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
class CallbackModule(object):
|
||||
class CallbackModule(CallbackBase):
|
||||
"""This is an example ansible callback plugin that sends status
|
||||
updates to a HipChat channel during playbook execution.
|
||||
|
||||
|
@ -42,11 +41,16 @@ class CallbackModule(object):
|
|||
prettytable
|
||||
|
||||
"""
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'notification'
|
||||
|
||||
def __init__(self, display):
|
||||
|
||||
super(CallbackModule, self).__init__(display)
|
||||
|
||||
def __init__(self):
|
||||
if not HAS_PRETTYTABLE:
|
||||
self.disabled = True
|
||||
utils.warning('The `prettytable` python module is not installed. '
|
||||
self.display.warning('The `prettytable` python module is not installed. '
|
||||
'Disabling the HipChat callback plugin.')
|
||||
|
||||
self.msg_uri = 'https://api.hipchat.com/v1/rooms/message'
|
||||
|
@ -57,7 +61,7 @@ class CallbackModule(object):
|
|||
|
||||
if self.token is None:
|
||||
self.disabled = True
|
||||
utils.warning('HipChat token could not be loaded. The HipChat '
|
||||
self.display.warning('HipChat token could not be loaded. The HipChat '
|
||||
'token can be provided using the `HIPCHAT_TOKEN` '
|
||||
'environment variable.')
|
||||
|
||||
|
@ -80,63 +84,8 @@ class CallbackModule(object):
|
|||
response = urllib2.urlopen(url, urllib.urlencode(params))
|
||||
return response.read()
|
||||
except:
|
||||
utils.warning('Could not submit message to hipchat')
|
||||
self.display.warning('Could not submit message to hipchat')
|
||||
|
||||
def on_any(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def runner_on_failed(self, host, res, ignore_errors=False):
|
||||
pass
|
||||
|
||||
def runner_on_ok(self, host, res):
|
||||
pass
|
||||
|
||||
def runner_on_skipped(self, host, item=None):
|
||||
pass
|
||||
|
||||
def runner_on_unreachable(self, host, res):
|
||||
pass
|
||||
|
||||
def runner_on_no_hosts(self):
|
||||
pass
|
||||
|
||||
def runner_on_async_poll(self, host, res, jid, clock):
|
||||
pass
|
||||
|
||||
def runner_on_async_ok(self, host, res, jid):
|
||||
pass
|
||||
|
||||
def runner_on_async_failed(self, host, res, jid):
|
||||
pass
|
||||
|
||||
def playbook_on_start(self):
|
||||
pass
|
||||
|
||||
def playbook_on_notify(self, host, handler):
|
||||
pass
|
||||
|
||||
def playbook_on_no_hosts_matched(self):
|
||||
pass
|
||||
|
||||
def playbook_on_no_hosts_remaining(self):
|
||||
pass
|
||||
|
||||
def playbook_on_task_start(self, name, is_conditional):
|
||||
pass
|
||||
|
||||
def playbook_on_vars_prompt(self, varname, private=True, prompt=None,
|
||||
encrypt=None, confirm=False, salt_size=None,
|
||||
salt=None, default=None):
|
||||
pass
|
||||
|
||||
def playbook_on_setup(self):
|
||||
pass
|
||||
|
||||
def playbook_on_import_for_host(self, host, imported_file):
|
||||
pass
|
||||
|
||||
def playbook_on_not_import_for_host(self, host, missing_file):
|
||||
pass
|
||||
|
||||
def playbook_on_play_start(self, name):
|
||||
"""Display Playbook and play start messages"""
|
85
lib/ansible/plugins/callback/log_plays.py
Normal file
85
lib/ansible/plugins/callback/log_plays.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
||||
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
# NOTE: in Ansible 1.2 or later general logging is available without
|
||||
# this plugin, just set ANSIBLE_LOG_PATH as an environment variable
|
||||
# or log_path in the DEFAULTS section of your ansible configuration
|
||||
# file. This callback is an example of per hosts logging for those
|
||||
# that want it.
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
"""
|
||||
logs playbook results, per host, in /var/log/ansible/hosts
|
||||
"""
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'notification'
|
||||
|
||||
TIME_FORMAT="%b %d %Y %H:%M:%S"
|
||||
MSG_FORMAT="%(now)s - %(category)s - %(data)s\n\n"
|
||||
|
||||
def __init__(self, display):
|
||||
|
||||
super(CallbackModule, self).__init__(display)
|
||||
|
||||
if not os.path.exists("/var/log/ansible/hosts"):
|
||||
os.makedirs("/var/log/ansible/hosts")
|
||||
|
||||
def log(self, host, category, data):
|
||||
if type(data) == dict:
|
||||
if 'verbose_override' in data:
|
||||
# avoid logging extraneous data from facts
|
||||
data = 'omitted'
|
||||
else:
|
||||
data = data.copy()
|
||||
invocation = data.pop('invocation', None)
|
||||
data = json.dumps(data)
|
||||
if invocation is not None:
|
||||
data = json.dumps(invocation) + " => %s " % data
|
||||
|
||||
path = os.path.join("/var/log/ansible/hosts", host)
|
||||
now = time.strftime(self.TIME_FORMAT, time.localtime())
|
||||
fd = open(path, "a")
|
||||
fd.write(self.MSG_FORMAT % dict(now=now, category=category, data=data))
|
||||
fd.close()
|
||||
|
||||
def runner_on_failed(self, host, res, ignore_errors=False):
|
||||
self.log(host, 'FAILED', res)
|
||||
|
||||
def runner_on_ok(self, host, res):
|
||||
self.log(host, 'OK', res)
|
||||
|
||||
def runner_on_skipped(self, host, item=None):
|
||||
self.log(host, 'SKIPPED', '...')
|
||||
|
||||
def runner_on_unreachable(self, host, res):
|
||||
self.log(host, 'UNREACHABLE', res)
|
||||
|
||||
def runner_on_async_failed(self, host, res, jid):
|
||||
self.log(host, 'ASYNC_FAILED', res)
|
||||
|
||||
def playbook_on_import_for_host(self, host, imported_file):
|
||||
self.log(host, 'IMPORTED', imported_file)
|
||||
|
||||
def playbook_on_not_import_for_host(self, host, missing_file):
|
||||
self.log(host, 'NOTIMPORTED', missing_file)
|
|
@ -19,87 +19,69 @@
|
|||
import subprocess
|
||||
import os
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
FAILED_VOICE="Zarvox"
|
||||
REGULAR_VOICE="Trinoids"
|
||||
HAPPY_VOICE="Cellos"
|
||||
LASER_VOICE="Princess"
|
||||
SAY_CMD="/usr/bin/say"
|
||||
|
||||
def say(msg, voice):
|
||||
subprocess.call([SAY_CMD, msg, "--voice=%s" % (voice)])
|
||||
|
||||
class CallbackModule(object):
|
||||
class CallbackModule(CallbackBase):
|
||||
"""
|
||||
makes Ansible much more exciting on OS X.
|
||||
"""
|
||||
def __init__(self):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'notification'
|
||||
|
||||
def __init__(self, display):
|
||||
|
||||
super(CallbackModule, self).__init__(display)
|
||||
|
||||
# plugin disable itself if say is not present
|
||||
# ansible will not call any callback if disabled is set to True
|
||||
if not os.path.exists(SAY_CMD):
|
||||
self.disabled = True
|
||||
print "%s does not exist, plugin %s disabled" % \
|
||||
(SAY_CMD, os.path.basename(__file__))
|
||||
self._display.warning("%s does not exist, plugin %s disabled" % (SAY_CMD, os.path.basename(__file__)) )
|
||||
|
||||
def on_any(self, *args, **kwargs):
|
||||
pass
|
||||
def say(self, msg, voice):
|
||||
subprocess.call([SAY_CMD, msg, "--voice=%s" % (voice)])
|
||||
|
||||
def runner_on_failed(self, host, res, ignore_errors=False):
|
||||
say("Failure on host %s" % host, FAILED_VOICE)
|
||||
self.say("Failure on host %s" % host, FAILED_VOICE)
|
||||
|
||||
def runner_on_ok(self, host, res):
|
||||
say("pew", LASER_VOICE)
|
||||
self.say("pew", LASER_VOICE)
|
||||
|
||||
def runner_on_skipped(self, host, item=None):
|
||||
say("pew", LASER_VOICE)
|
||||
self.say("pew", LASER_VOICE)
|
||||
|
||||
def runner_on_unreachable(self, host, res):
|
||||
say("Failure on host %s" % host, FAILED_VOICE)
|
||||
|
||||
def runner_on_no_hosts(self):
|
||||
pass
|
||||
|
||||
def runner_on_async_poll(self, host, res, jid, clock):
|
||||
pass
|
||||
self.say("Failure on host %s" % host, FAILED_VOICE)
|
||||
|
||||
def runner_on_async_ok(self, host, res, jid):
|
||||
say("pew", LASER_VOICE)
|
||||
self.say("pew", LASER_VOICE)
|
||||
|
||||
def runner_on_async_failed(self, host, res, jid):
|
||||
say("Failure on host %s" % host, FAILED_VOICE)
|
||||
self.say("Failure on host %s" % host, FAILED_VOICE)
|
||||
|
||||
def playbook_on_start(self):
|
||||
say("Running Playbook", REGULAR_VOICE)
|
||||
self.say("Running Playbook", REGULAR_VOICE)
|
||||
|
||||
def playbook_on_notify(self, host, handler):
|
||||
say("pew", LASER_VOICE)
|
||||
|
||||
def playbook_on_no_hosts_matched(self):
|
||||
pass
|
||||
|
||||
def playbook_on_no_hosts_remaining(self):
|
||||
pass
|
||||
self.say("pew", LASER_VOICE)
|
||||
|
||||
def playbook_on_task_start(self, name, is_conditional):
|
||||
if not is_conditional:
|
||||
say("Starting task: %s" % name, REGULAR_VOICE)
|
||||
self.say("Starting task: %s" % name, REGULAR_VOICE)
|
||||
else:
|
||||
say("Notifying task: %s" % name, REGULAR_VOICE)
|
||||
|
||||
def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
||||
pass
|
||||
self.say("Notifying task: %s" % name, REGULAR_VOICE)
|
||||
|
||||
def playbook_on_setup(self):
|
||||
say("Gathering facts", REGULAR_VOICE)
|
||||
|
||||
def playbook_on_import_for_host(self, host, imported_file):
|
||||
pass
|
||||
|
||||
def playbook_on_not_import_for_host(self, host, missing_file):
|
||||
pass
|
||||
self.say("Gathering facts", REGULAR_VOICE)
|
||||
|
||||
def playbook_on_play_start(self, name):
|
||||
say("Starting play: %s" % name, HAPPY_VOICE)
|
||||
self.say("Starting play: %s" % name, HAPPY_VOICE)
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
say("Play complete", HAPPY_VOICE)
|
||||
|
||||
self.say("Play complete", HAPPY_VOICE)
|
|
@ -6,7 +6,9 @@ import logging.handlers
|
|||
|
||||
import socket
|
||||
|
||||
class CallbackModule(object):
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
"""
|
||||
logs ansible-playbook and ansible runs to a syslog server in json format
|
||||
make sure you have in ansible.cfg:
|
||||
|
@ -17,8 +19,13 @@ class CallbackModule(object):
|
|||
SYSLOG_SERVER (optional): defaults to localhost
|
||||
SYSLOG_PORT (optional): defaults to 514
|
||||
"""
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'aggregate'
|
||||
|
||||
def __init__(self, display):
|
||||
|
||||
super(CallbackModule, self).__init__(display)
|
||||
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger('ansible logger')
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
@ -30,8 +37,6 @@ class CallbackModule(object):
|
|||
self.logger.addHandler(self.handler)
|
||||
self.hostname = socket.gethostname()
|
||||
|
||||
def on_any(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def runner_on_failed(self, host, res, ignore_errors=False):
|
||||
self.logger.error('%s ansible-command: task execution FAILED; host: %s; message: %s' % (self.hostname,host,json.dumps(res, sort_keys=True)))
|
||||
|
@ -40,52 +45,16 @@ class CallbackModule(object):
|
|||
self.logger.info('%s ansible-command: task execution OK; host: %s; message: %s' % (self.hostname,host,json.dumps(res, sort_keys=True)))
|
||||
|
||||
def runner_on_skipped(self, host, item=None):
|
||||
self.logger.info('%s ansible-command: task execution SKIPPED; host: %s; message: %s' % (self.hostname,host,json.dumps(res, sort_keys=True)))
|
||||
self.logger.info('%s ansible-command: task execution SKIPPED; host: %s; message: %s' % (self.hostname,host, 'skipped'))
|
||||
|
||||
def runner_on_unreachable(self, host, res):
|
||||
self.logger.error('%s ansible-command: task execution UNREACHABLE; host: %s; message: %s' % (self.hostname,host,json.dumps(res, sort_keys=True)))
|
||||
|
||||
def runner_on_no_hosts(self):
|
||||
pass
|
||||
|
||||
def runner_on_async_poll(self, host, res):
|
||||
pass
|
||||
|
||||
def runner_on_async_ok(self, host, res):
|
||||
pass
|
||||
|
||||
def runner_on_async_failed(self, host, res):
|
||||
self.logger.error('%s ansible-command: task execution FAILED; host: %s; message: %s' % (self.hostname,host,json.dumps(res, sort_keys=True)))
|
||||
|
||||
def playbook_on_start(self):
|
||||
pass
|
||||
|
||||
def playbook_on_notify(self, host, handler):
|
||||
pass
|
||||
|
||||
def playbook_on_no_hosts_matched(self):
|
||||
pass
|
||||
|
||||
def playbook_on_no_hosts_remaining(self):
|
||||
pass
|
||||
|
||||
def playbook_on_task_start(self, name, is_conditional):
|
||||
pass
|
||||
|
||||
def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
||||
pass
|
||||
|
||||
def playbook_on_setup(self):
|
||||
pass
|
||||
|
||||
def playbook_on_import_for_host(self, host, imported_file):
|
||||
self.logger.info('%s ansible-command: playbook IMPORTED; host: %s; message: %s' % (self.hostname,host,json.dumps(res, sort_keys=True)))
|
||||
|
||||
def playbook_on_not_import_for_host(self, host, missing_file):
|
||||
self.logger.info('%s ansible-command: playbook NOT IMPORTED; host: %s; message: %s' % (self.hostname,host,json.dumps(res, sort_keys=True)))
|
||||
|
||||
def playbook_on_play_start(self, name):
|
||||
pass
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
pass
|
|
@ -12,13 +12,12 @@ class CallbackModule(CallbackBase):
|
|||
CALLBACK_TYPE = 'aggregate'
|
||||
|
||||
start_time = datetime.now()
|
||||
|
||||
|
||||
def __init__(self, display):
|
||||
|
||||
super(CallbackModule, self).__init__(display)
|
||||
super(CallbackModule, self).__init__(display)
|
||||
|
||||
start_time = datetime.now()
|
||||
self._display.warning("Timerv2 plugin is active from included callbacks.")
|
||||
|
||||
def days_hours_minutes_seconds(self, timedelta):
|
||||
minutes = (timedelta.seconds//60)%60
|
||||
|
@ -27,7 +26,7 @@ class CallbackModule(CallbackBase):
|
|||
|
||||
def playbook_on_stats(self, stats):
|
||||
self.v2_playbook_on_stats(stats)
|
||||
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
end_time = datetime.now()
|
||||
timedelta = end_time - self.start_time
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
ansible-plugins
|
||||
===============
|
||||
|
||||
You can extend ansible with optional callback and connection plugins.
|
||||
|
||||
callbacks
|
||||
=========
|
||||
|
||||
Callbacks can be used to add logging or monitoring capability, or just make
|
||||
interesting sound effects.
|
||||
|
||||
Drop callback plugins in your ansible/lib/callback_plugins/ directory.
|
||||
|
||||
connections
|
||||
===========
|
||||
|
||||
Connection plugins allow ansible to talk over different protocols.
|
||||
|
||||
Drop connection plugins in your ansible/lib/runner/connection_plugins/ directory.
|
||||
|
||||
inventory
|
||||
=========
|
||||
|
||||
Inventory plugins allow you to store your hosts, groups, and variables in any way
|
||||
you like. Examples include discovering inventory from EC2 or pulling it from
|
||||
Cobbler. These could also be used to interface with LDAP or database.
|
||||
|
||||
chmod +x an inventory plugin and either name it /etc/ansible/hosts or use ansible
|
||||
with -i to designate the path to the plugin.
|
||||
|
||||
contributions welcome
|
||||
=====================
|
||||
|
||||
Send in pull requests to add plugins of your own. The sky is the limit!
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
|
||||
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
# NOTE: in Ansible 1.2 or later general logging is available without
|
||||
# this plugin, just set ANSIBLE_LOG_PATH as an environment variable
|
||||
# or log_path in the DEFAULTS section of your ansible configuration
|
||||
# file. This callback is an example of per hosts logging for those
|
||||
# that want it.
|
||||
|
||||
TIME_FORMAT="%b %d %Y %H:%M:%S"
|
||||
MSG_FORMAT="%(now)s - %(category)s - %(data)s\n\n"
|
||||
|
||||
if not os.path.exists("/var/log/ansible/hosts"):
|
||||
os.makedirs("/var/log/ansible/hosts")
|
||||
|
||||
def log(host, category, data):
|
||||
if type(data) == dict:
|
||||
if 'verbose_override' in data:
|
||||
# avoid logging extraneous data from facts
|
||||
data = 'omitted'
|
||||
else:
|
||||
data = data.copy()
|
||||
invocation = data.pop('invocation', None)
|
||||
data = json.dumps(data)
|
||||
if invocation is not None:
|
||||
data = json.dumps(invocation) + " => %s " % data
|
||||
|
||||
path = os.path.join("/var/log/ansible/hosts", host)
|
||||
now = time.strftime(TIME_FORMAT, time.localtime())
|
||||
fd = open(path, "a")
|
||||
fd.write(MSG_FORMAT % dict(now=now, category=category, data=data))
|
||||
fd.close()
|
||||
|
||||
class CallbackModule(object):
|
||||
"""
|
||||
logs playbook results, per host, in /var/log/ansible/hosts
|
||||
"""
|
||||
|
||||
def on_any(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def runner_on_failed(self, host, res, ignore_errors=False):
|
||||
log(host, 'FAILED', res)
|
||||
|
||||
def runner_on_ok(self, host, res):
|
||||
log(host, 'OK', res)
|
||||
|
||||
def runner_on_skipped(self, host, item=None):
|
||||
log(host, 'SKIPPED', '...')
|
||||
|
||||
def runner_on_unreachable(self, host, res):
|
||||
log(host, 'UNREACHABLE', res)
|
||||
|
||||
def runner_on_no_hosts(self):
|
||||
pass
|
||||
|
||||
def runner_on_async_poll(self, host, res, jid, clock):
|
||||
pass
|
||||
|
||||
def runner_on_async_ok(self, host, res, jid):
|
||||
pass
|
||||
|
||||
def runner_on_async_failed(self, host, res, jid):
|
||||
log(host, 'ASYNC_FAILED', res)
|
||||
|
||||
def playbook_on_start(self):
|
||||
pass
|
||||
|
||||
def playbook_on_notify(self, host, handler):
|
||||
pass
|
||||
|
||||
def playbook_on_no_hosts_matched(self):
|
||||
pass
|
||||
|
||||
def playbook_on_no_hosts_remaining(self):
|
||||
pass
|
||||
|
||||
def playbook_on_task_start(self, name, is_conditional):
|
||||
pass
|
||||
|
||||
def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
|
||||
pass
|
||||
|
||||
def playbook_on_setup(self):
|
||||
pass
|
||||
|
||||
def playbook_on_import_for_host(self, host, imported_file):
|
||||
log(host, 'IMPORTED', imported_file)
|
||||
|
||||
def playbook_on_not_import_for_host(self, host, missing_file):
|
||||
log(host, 'NOTIMPORTED', missing_file)
|
||||
|
||||
def playbook_on_play_start(self, name):
|
||||
pass
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
pass
|
||||
|
Loading…
Reference in a new issue