Instantiate callback plugins only once so we can set play/task objects on them and they'll stick.

This commit is contained in:
Michael DeHaan 2013-04-20 09:09:35 -04:00
parent df93d7dd97
commit 53ac0bbec2
4 changed files with 113 additions and 16 deletions

View file

@ -45,10 +45,25 @@ if cowsay and noncow == 'random':
cows = out.split()
cows.append(False)
noncow = random.choice(cows)
callback_plugins = [x for x in utils.plugins.callback_loader.all()]
def set_play(callback, play):
''' used to notify callback plugins of context '''
callback.play = play
for callback_plugin in callback_plugins:
callback_plugin.play = play
def set_task(callback, task):
''' used to notify callback plugins of context '''
callback.task = task
for callback_plugin in callback_plugins:
callback_plugin.task = task
def call_callback_module(method_name, *args, **kwargs):
for callback_plugin in utils.plugins.callback_loader.all():
for callback_plugin in callback_plugins:
methods = [
getattr(callback_plugin, method_name, None),
getattr(callback_plugin, 'on_any', None)

View file

@ -16,8 +16,8 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import ansible.inventory
import ansible.runner
import ansible.constants as C
import ansible.runner
from ansible.utils import template
from ansible import utils
from ansible import errors
@ -214,8 +214,9 @@ class PlayBook(object):
for (play_ds, play_basedir) in zip(self.playbook, self.play_basedirs):
play = Play(self, play_ds, play_basedir)
self.callbacks.play = play
self.runner_callbacks.play = play
assert play is not None
ansible.callbacks.set_play(self.callbacks, play)
ansible.callbacks.set_play(self.runner_callbacks, play)
matched_tags, unmatched_tags = play.compare_tags(self.only_tags)
matched_tags_all = matched_tags_all | matched_tags
@ -317,8 +318,8 @@ class PlayBook(object):
def _run_task(self, play, task, is_handler):
''' run a single task in the playbook and recursively run any subtasks. '''
self.callbacks.task = task
self.runner_callbacks.task = task
ansible.callbacks.set_task(self.callbacks, task)
ansible.callbacks.set_task(self.runner_callbacks, task)
self.callbacks.on_task_start(template.template(play.basedir, task.name, task.module_vars, lookup_fatal=False), is_handler)
if hasattr(self.callbacks, 'skip_task') and self.callbacks.skip_task:
@ -402,8 +403,8 @@ class PlayBook(object):
self.callbacks.on_setup()
self.inventory.restrict_to(host_list)
self.callbacks.task = None
self.runner_callbacks.task = None
ansible.callbacks.set_task(self.callbacks, None)
ansible.callbacks.set_task(self.runner_callbacks, None)
# push any variables down to the system
setup_results = ansible.runner.Runner(

View file

@ -22,6 +22,7 @@ import imp
import ansible.constants as C
from ansible import errors
MODULE_CACHE = {}
_basedirs = []
def push_basedir(basedir):
@ -41,7 +42,11 @@ class PluginLoader(object):
self.config = config
self.subdir = subdir
self.aliases = aliases
self._module_cache = {}
if not class_name in MODULE_CACHE:
MODULE_CACHE[class_name] = {}
self._module_cache = MODULE_CACHE[class_name]
self._extra_dirs = []
def _get_package_path(self):
@ -111,6 +116,7 @@ class PluginLoader(object):
return getattr(self._module_cache[path], self.class_name)(*args, **kwargs)
def all(self, *args, **kwargs):
for i in self._get_paths():
for path in glob.glob(os.path.join(i, "*.py")):
name, ext = os.path.splitext(os.path.basename(path))
@ -120,10 +126,54 @@ class PluginLoader(object):
self._module_cache[path] = imp.load_source('.'.join([self.package, name]), path)
yield getattr(self._module_cache[path], self.class_name)(*args, **kwargs)
action_loader = PluginLoader('ActionModule', 'ansible.runner.action_plugins', C.DEFAULT_ACTION_PLUGIN_PATH, 'action_plugins')
callback_loader = PluginLoader('CallbackModule', 'ansible.callback_plugins', C.DEFAULT_CALLBACK_PLUGIN_PATH, 'callback_plugins')
connection_loader = PluginLoader('Connection', 'ansible.runner.connection_plugins', C.DEFAULT_CONNECTION_PLUGIN_PATH, 'connection_plugins', aliases={'paramiko': 'paramiko_ssh'})
module_finder = PluginLoader('', '', C.DEFAULT_MODULE_PATH, 'library')
lookup_loader = PluginLoader('LookupModule', 'ansible.runner.lookup_plugins', C.DEFAULT_LOOKUP_PLUGIN_PATH, 'lookup_plugins')
vars_loader = PluginLoader('VarsModule', 'ansible.inventory.vars_plugins', C.DEFAULT_VARS_PLUGIN_PATH, 'vars_plugins')
filter_loader = PluginLoader('FilterModule', 'ansible.runner.filter_plugins', C.DEFAULT_FILTER_PLUGIN_PATH, 'filter_plugins')
action_loader = PluginLoader(
'ActionModule',
'ansible.runner.action_plugins',
C.DEFAULT_ACTION_PLUGIN_PATH,
'action_plugins'
)
callback_loader = PluginLoader(
'CallbackModule',
'ansible.callback_plugins',
C.DEFAULT_CALLBACK_PLUGIN_PATH,
'callback_plugins'
)
connection_loader = PluginLoader(
'Connection',
'ansible.runner.connection_plugins',
C.DEFAULT_CONNECTION_PLUGIN_PATH,
'connection_plugins',
aliases={'paramiko': 'paramiko_ssh'}
)
module_finder = PluginLoader(
'',
'',
C.DEFAULT_MODULE_PATH,
'library'
)
lookup_loader = PluginLoader(
'LookupModule',
'ansible.runner.lookup_plugins',
C.DEFAULT_LOOKUP_PLUGIN_PATH,
'lookup_plugins'
)
vars_loader = PluginLoader(
'VarsModule',
'ansible.inventory.vars_plugins',
C.DEFAULT_VARS_PLUGIN_PATH,
'vars_plugins'
)
filter_loader = PluginLoader(
'FilterModule',
'ansible.runner.filter_plugins',
C.DEFAULT_FILTER_PLUGIN_PATH,
'filter_plugins'
)

View file

@ -0,0 +1,31 @@
# (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
class CallbackModule(object):
"""
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.
"""
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)