There will be no LSP highlights as “global task” is not a task from ansible point of view
Anchor just copies the content from one place to another.
I did not want to make a huge jump right to this final solution on the first post as it might confuse people.
Well yes and no… Anchors work just inside a single yaml file, as they are yaml objects. When ansible reads tihs file it is as if you would copy and paste the same code at multiple places.
Having this code at multiple places means it would be execuded MULTIPLE TIMES. This might not be desired, especially when running on an inventory with thousands of hosts - you do not want (not need) to re-execute this task for each play!
My suggested approach eecutes this lookup just a single time for entire playbook file regardless of number of hosts. It assigns a set_fact level variable to all hosts and it is visible in ALL following plays without the need to re-execute it.
I know that anchors might get handy in some places, but for me this is a quick and dirty hack to avoid copy/paste same code within same file. I however do not like the idea to have same code in one file at multiple places in the first place…
Hi Bartowl, I’m having a bit of trouble envisioning what’s different from your suggestion and my original post (and what I’ve done wrong in that context). Ideally, I’m not installing Bitwarden and syncing that everywhere, I want to do the lookup from the place I’m running the playbook. The sync is a manual process from the CLI tool, and I have to grab a session key once I log in. Originally, I was running this I think as you described, except I was delegating it and having trouble.
I definitely didn’t really like that this was running more than once.
You can use run_once in the play targeting your ansible_test_vm group. It will run once and you can access the fact directly instead of through hostvars:
Originally, I was running this I think as you described, except I was delegating it and having trouble.
Your error was unrelated to delegation, it was caused by how you defined vars:. In this example I used | default(omit), but see my comment above for other options to avoid that issue (regardless of delegation).
Hi Shertel, I don’t want to run the play to get the password against the same host as I do other things. I either have to delegate it or have a play to grab it. It’s always worked just fine if I do everything on the same host as I grab the password.
I swear I did that before (before I tried the variable thing in the original post) but maybe I had a typo or something.
So now I have this (what you recommended) and it works.
- name: Test using Bitwarden varaible
hosts: ansible_test_vm
gather_facts: false
tasks:
- name: Get Bitwarden password for badmin lab user
ansible.builtin.set_fact:
bw_data: >-
{{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}
cacheable: true
delegate_to: localhost
- name: Check if `/etc/profile.d/ps1.sh` exists
ansible.builtin.stat:
path: /etc/profile.d/ps1.sh
become: true
register: stat_ps1_sh
vars:
ansible_become_pass: "{{ bw_data | default(omit) }}"
If I have some other play further down that targets some other group of VMs for some reason, would I then have to run it again on that new group of hosts? I assumed something like the below would be cleaner since I’d only do it a single time but the variable isn’t persistent for the second play.
set_fact runs on the controller FOR the inventory_hostname, not on the hosts, this is true for many actions like ‘debug’, see the ‘attributes’ section, anything not using the connection should behave this way
run_once has several side effects, one of them is to apply results to all hosts
the result of set_fact is to set a variable on a host .. so it kind of does run set_fact for every host, you just skip the parts that show in the callback
when using this strategy you are making N copies of the variables (N == number of hosts), when using the localhost/hostvars[‘localhost’] you only have 1 copy of the variable
That is not what I suggested, and I don’t know why it would work unless localhost is the only host in that group. You asked how run_once was different from your original post, so my example was just a demonstration of how to use it, not a recommendation per se.
If you want one copy of the variable or want that variable accessible for other plays, I’d write it as:
- name: Use Bitwarden pass from task
hosts: ansible_test_vm
tasks:
# You could move this to its own play targeting localhost and remove delegate_to and delegate_facts if you want.
- name: 'Get password for "badmin - Lab User" from Bitwarden'
set_fact:
bw_data: >-
{{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}
cacheable: True
delegate_to: localhost
delegate_facts: True
- name: Check if `/etc/profile.d/ps1.sh` exists
ansible.builtin.stat:
path: /etc/profile.d/ps1.sh
become: true
register: stat_ps1_sh
vars:
ansible_become_pass: "{{ hostvars['localhost']['bw_data'] | default(omit) }}" # You were missing "| default(omit)" in the original example (although IMO this is a bug in ansible-core)
- hosts: ansible
vars:
ansible_become_pass: "{{ hostvars['localhost']['bw_data'] }}" # Note that "| default(omit)" is no longer necessary since the fact was defined in an earlier play that always runs
Yes, you are right. To be honest I forgot that inside one playbook set_fact is visible in different plays. Scope of what is available where is not good documented for ansible.
There are still use case where one would want to have lookup to be executed for each host, for instance when each host has different credentials.