Accessing variables from within a plugin (callback)

Hello list,

is there a way how I can access host/group vars from within a callback plugin? Basically I want to modify the Hipchat callback plugin to use a room ID configured via group_vars (or maybe registered as a var right in a roles tasks), as we have hundred of chat rooms and to which room a message will be sent would depend on the role.

Thanks,
Daniel

Currently the callback instances don’t have a copy of the runner instance variable needed to get at that dictionary.

In playbook code, we do something like this so callbacks can know what play they are currently executing.

https://github.com/ansible/ansible/blob/devel/lib/ansible/playbook/init.py#L325

I can see something like this being set in Runner callbacks, but it may be more appropriate for the “on_stats” method (which is really the final callback when everything is all done) to get passed a reference to the per-host variable structure (internally referred to as the “setup_cache”).

However, the easiest thing you could do, if possible, is just have your callback be responsive to an environment variable like ROOM_ID. However, this would require launching your playbook appropriately.

I’d be interested in hearing more about the use case as having 100 different chatrooms all running playbooks seems like something I’d be interested in :slight_smile:

Daniel,

Since I submitted the hipchat.py calback plugin PR, we have since modified it locally, to do something similar to what you are doing.

In our case, our hipchat API token lives in a vault encrypted vars file for all hosts, so we pull this var out during run time. You can see the results at:

https://gist.github.com/sivel/bf217f2465523fb8d548

Specifically, you will be interested in:

https://gist.github.com/sivel/bf217f2465523fb8d548#file-hipchat-py-L30-L40

and

https://gist.github.com/sivel/bf217f2465523fb8d548#file-hipchat-py-L127-L128

Matt, that’s awesome. Thanks for the great example. (and the Hipchat callback)

So this snippet is what I was looking for to get to global definitions:

hosts = self.playbook.inventory.get_hosts() host_vars = self.playbook.inventory.get_variables(hosts[0].name)

Host specific methods in the callback then have the host parameter which can be used to get vars belonging to that host.

I’d be interested in hearing more about the use case as having 100 different chatrooms all running playbooks seems like something I’d be interested in :slight_smile:

I think that question now is already answered here.

Cheers!
Daniel

Hi,

I am trying to create vars_plugins plugin and I would need variables passed from cmdline.

Is there any way I could access other vars than host_vars? I would like to pass on cmdline for example -e customer_name=demo and use this variable in my custom vars_plugin and obtain variables specific only for this user…

Thanks,
Jakub

Hi Jakub,

I have not yet looked into vars plugins. But in theory, if there is the runner object available, you should be able to access those. Try to access self.runner. If it is available the extra vars should be somewhere in there.

Another approach might be, to just dynamically include a yml file, if that’s possible in your case.

  • include_vars: {{ customer }}.yml

Cheers,
Daniel

Thanks for the tip Daniel.

Seems like I can’t access runner:

AttributeError: ‘VarsModule’ object has no attribute ‘runner’

Am I accessing it on right place though? Can’t find runner in this module: https://github.com/ansible/ansible/tree/devel/lib/ansible/inventory.

I am afraid I will have to go with system envs as mentioned by Michael.
I am currently using dynamic include_vars, but my evil plan counts with having this config in etcd db. I wanna use watcher which will trigger appropriate deploys in case of config change.

Jakub

vars_plugins are mostly just a way to implement inventory (at a point in time, anyway), and were not really meant to be user serviceable.

Not quite following this part: “and I would need variables passed from cmdline.”

It sounds like you are trying to generate variables from an external source like a CMDB or cloud, and might want to read an environment variable.

if you are doing this, an inventory plugin (if this source already contains the list of hosts/groups/etc as well) would be a good place to return variables at the same time and is usually how we do that.

I am not using inventory plugin because it wouldn’t make sense in my case. Please correct me if it does.

I have dynamic ec2 inventory after I provision CoreOS hosts.
I am running apps in docker containers on top of CoreOS cluster so there can be more or less apps than actual hosts and I mostly don’t specify on which host the app is running.
The apps (fleet unit files) are configured and started using action on local host using fleet module to interact with coreos cluster.

I have general configuration which could be in group_vars/all so that this info is accessible from each host.
Variables are different for each environment, thats why I am loading these values dynamically during run and don’t have those in single static file.

Currently my variables are read first from general config and after overwritten (if present) by customer specific config and after by environment specific config.

When I think about it now I could perhaps convert vars script to dynamic inventory and add variables to local host this way. I believe this should be the only host that I am running those commands from.

My problem with passing variables from cmdline is that if I run ansible-paybook with -e “customer_name=demo customer_env=dev” I would like to import variables for demo customer’s dev environmnent but unfortunatelly I can’t access this variable in my vars_plugin custom python script…

Will I have this variable if I try to implement dynamic inventory?

Thanks,
Jakub

If it doesn’t bother you to have an extra task, you could do it with an action plugin. At least I know you have access to the runner there. But actually it wouldn’t matter as you could simply pass it in the task like so:

- load_customer_vars: {{ customer_name }}

In the set_facts or include_vars plugins you could see how to return facts from an action plugin:

https://github.com/ansible/ansible/blob/devel/lib/ansible/runner/action_plugins/include_vars.py
https://github.com/ansible/ansible/blob/devel/lib/ansible/runner/action_plugins/set_fact.py

Cheers,
Daniel

Excelent idea, its not as elegant as having a fancy dynamic inventory, but seems a lot simpler :slight_smile:

Thanks a lot,
Jakub

Hi, I am trying to do something similar and am having issues. Does this work with 2.0?

Specifically this piece:

def playbook_on_play_start(self, pattern): self.playbook = self.play.playbook self.inventory = self.playbook.inventory

where you reference self.play, but I can’t figure out where self.play is ever created. The play object is passed in v2_playbook_on_play_start, but that does not have a playbook attribute.

That code no longer works with Ansible 2.0 as the internal structure is completely different due to changes in the python API.

You will want to look at what you get from the play variable. You have things like play._variable_manager

You may find some help in a recent discussion had here on ansible-devel: https://groups.google.com/forum/#ansible-devel/DQiGednLgU0/lXWDiwuQFQAJ

Looks like link to discussion is not working.
So can anyone help on how to get access to variables from callback plugin in Ansible 2.0?

You already found it, as it seems. But for others who are looking for a solution, this is the correct link to mentioned discussion: https://groups.google.com/forum/#!msg/ansible-devel/DQiGednLgU0/JIvQ2Z-zFQAJ