What I’m really looking for is advice/experience in dealing with this. Making it so it is scalable and simple. Also, I’m aware that different scenarios require different techniques. I want to give my guys “We do it this way, unless circumstances require something else”, in order to try to maintain consistency.
I would love it if someone knew of something with the variable templating times. i.e. some technique by which the templating happens and then it doesn’t reevaluate after that. (Would var set at block level handle that? Something inside of a role?). Ideally, I would like to avoid having to have a separate task for this.
The scenario:
Assuming that the secret is identical for whichever host this runs on, say an api endpoint. I would like to pull the secret once per play, no matter how many hosts need it.
Methods I’ve considered:
I considered doing a set_fact to localhost with run_once. However, that limits us to not running host_pinned or free strategies.
Alternatively, I could use that technique with a when condition that checks for the definition of the variable. My past experiences have been that that does work, but will generally run more than one, but not many.
You’re almost there! Use ansible.builtin.set_fact with run_once: true in the first play in your playbook. Either explicitly set strategy: linear with a comment that this is important and why, or let it default to linear and hope nobody changes it later. Delegate the task, or not, as you see fit; it doesn’t change the efficacy of this technique. The extremely useful but not at all obvious result of set_fact with run_once: true is that it sets that fact and value for all hosts in your play batch. This could be the only task in this first play.
Follow the first play with another play, using the same expression for hosts: that you used in your first play. Set your strategy: to whatever your needs require. All (reachable) hosts should have the fact and value set.
You may be able to save time by not duplicating gather_facts: in both plays (unless you’re setting gather_facts: false in both). Facts gathered or set in the one play will be available throughout all subsequent plays in the same playbook.
Finally, if you don’t need a strategy: other than linear, then you don’t need separate plays. But you figured that part out already.
Let us know how you end up addressing the problem. Good luck!
I guess I never really created a run_once on set_fact and look at it on all the hosts, but I do recall some bit of trouble I had a long time ago with something, and this would explain it.
Sometimes it amazes me the things I’m still finding out after 3 years of working with Ansible. Still running into little nuggets here and there.
I am now actually considering another possibility entirely, incorporating your strategy. If I was to make a playbook in a collection using “all” as the hosts pattern, I could then just have the guys do an include on it with the full namespace. This would keep the credential definition abstracted, so that we could change it, if needed, and have it propagate.
This would solve another problem we’ve been wrestling with, and that is that the infrastructure team is considering changing password managers, but has no idea which they are considering. I’ve been trying to come up with a way to abstract this, and that would definitely work.
I’m going to go try this, and I will definitely let you know how it works. It’s brilliant.