Return values from Ansible roles
Ansible roles aren’t functions, so they don’t actually return values. But what if they could?
I recently wrote a role to update a software package, which involved asking some questions:
- What’s the latest version?
- Which version, if any, is currently installed?
I wanted my role to be modular(ish), so it made sense to outsource those questions to other roles. But how would they return their results? I tried adding register: latest_version
to the role invocation, but that didn’t work.
But you can set facts inside a role:
# ... Figure out installed version of Foo package... - name: Return a value set_fact: installed_version: "1.2.3"
and if you know that this role sets installed_version
, you can treat that as a return value, just as if it were a task with register: installed_version
. Also, the fact that it sets, installed_version
, is local to the client, so each host will have a copy in hostvars[ansible_host]
. This makes sense: after all, you might want to know which of your machines are out of date.
The problem, though, is that installed_version
is “global” to each client. So if you’re checking the installed version of multiple packages
- name: Upgrade if necessary roles: - role: check_version package: Foo - role: check_version package: Bar - role: check_version package: Baz tasks: - debug: var=installed_version
how do you know which package’s installed_version
you’re dealing with?
The way to fix this is to realize that you can use string interpolation on the left side of the colon. When we invoke the role, let’s also give it the name of a fact to put the return value in:
- name: Upgrade if necessary roles: - role: check_version package: Foo return: foo_version - role: check_version package: Bar return: bar_version - role: check_version package: Baz return: baz_version
The check_version
role then sees return
as a role variable, and can use that in a play:
# ... Look up installed version of the given package... - name: Return version number set_fact: "{{ return }}": "1.2.3"
And then just check the appropriate fact for each role invocation.
- debug: var=foo_version - debug: var=bar_version - debug: var=baz_version
Bear in mind that these variables have the same scope as other facts, so if two roles set installed_version
, you’re back to the earlier problem of them stepping on each other’s feet. And yes, the whole thing feels like a hack. But it does mean you can return values from roles.