action_plugin/ vs library/ module

So, what’s the deal with action_plugins? There is very little documentation on their purpose.

Observations:

  1. If action_plugin/foo.py and library/foo.py both exist, then only action_plugin/foo.py gets called (the plugin may call the module if it wants, but that is not by default).
  2. If library/foo.py exists, but there is no corresponding action_plugin, the library is called.
  3. If action_plugin/foo.py exists, but there is no corresponding module, then Ansible throws a syntax error.
  4. If action_plugin/foo.py exists, and the library is empty (literally created with ‘touch library/foo.py’), then the action_plugin is called and everything works.
  5. sometimes, but no always, the action_plugin does some preliminary work with data that is not available to the library or the option plugin modifies the results.

For #5, I can understand a solid use case. If a vendor supplies a module and you want to use it, but would prefer to have the data returned differently (or strip out data or whatever) but don’t want to modify the vendor’s module, then this makes a lot of sense as a module wrapper.

I need to write a module and can’t decide if I should write a standard library module or if I should write an action_plugin with a blank library module (I suppose just to use for documentation, though that seems odd).

any clarification would help.

99% of the time you want a module, action plugins normally are created
when you need to do work on the 'master' machine.

Taking a step back, what problem are you trying to solve?

Depending on what you are trying to do, you might be able to solve the problem using the existing modules working together in a (re-usable) role.

Jon

I’m trying to get Ansible to open a ticket in our internal config management system.

I’m not new to modules, just thought that the action plugin looked more 2.0-ish.

I also notice that there seem to be a lot of action_plugins for core modules.

It doesn’t look like modules have access to ansible main data (e.g. if --diff was passed on the cmdline). If I need that data, might I need an action_plugin?

So, it looks like, in my case, I’ll want an action plugin since I don’t really need anything run on a remote machine and I’ll need access to the results of the playbook.

From the sounds of it, developing a callback might be more appropriate.

http://docs.ansible.com/ansible/developing_plugins.html#callbacks

I actually started out to create a callback that triggered on change, but after some internal discussion, decided that I didn’t want it to fire after each task, but rather, wanted to run it one time in the beginning and once at the end, so I figured that calling it as a task would be more appropriate.

That said, one future enhancement will be to open the ticket at the beginning, then update it after each changed task, in which case, I plan to use module tasks to create and close the ticket and then use a callback_plugin to update the ticket with results as they come in. Of course, if I’ve already written a module, I could set the updates to run as a handler task on change.

It still sounds like you want a callback, you can just implement the
on_start and on_stat methods and ignore all the intermediate actions

Perhaps. I’ll probably build both and see which feels better. I need to be able to set vars for the plugin/module to use that might be different for each playbook. The callback_plugins have access to vars through the ‘invocation’ in res, right? I’ll also need access to all of the diffs, so I’ll need to capture and then reference them in on_stat.

All other things being equal, this may come down to style and which playbook is easiest for people to understand and work with. Of course, most likely, in either case, my playbook would probably look something like this, no matter which option I choose:

`

Ok, so the problem I’m having in making this a callback is that I want to open a ticket on playbook start and close it on stats.

In order to open the ticket, I need certain information that will be specific to the playbook being run. The only way I can find to pass vars is through play_vars, which are only available in v2_playbook_on_play_start through play.get_vars().
These vars are only those that are set in the play itself, which excludes vars defined in vars_files (play.get_vars_files() returns a list of files which I would then need to read).

I feel like I’m missing something. Is there a better way that I can pass variables to a callback_plugin?

The best I can find so far is to grab them from TaskResult[‘invocation’] after the first task is run (then keep track of the fact that I’ve already opened a ticket and not open a new one for every task).

IYI, my eventual solution involves creating a blank change-mgmt ticket with a callback_plugin in init(). I then store the ticket number that is created in main.cli.ticket_number.
Then, the first pre-task of my playbook calls my action_plugin to read the ticket_number from main.cli and update the ticket with the actual data specific to the playbook that is being run.

I’m not sure I’m completely satisfied with this solution, but it does seem to work.