accessing vars for hosts that are not in the play?

91 views
Skip to first unread message

Dick Visser

unread,
Sep 16, 2022, 5:34:37 AM9/16/22
to ansible...@googlegroups.com
Hi

I have a playbook that contains several plays. One play is performing API related tasks in AWS, so it's using the local connection and localhost. The plays after that targets real hosts.
Pseudo code:

- name: do API related work
  hosts: localhost
  connection: local
  become: false
  gather_facts: false
  tags: api
  tasks:
    - name: populate secret for use elsewhere
      community.aws.aws_secret:
        name: foopass
        secret: "{{ hostvars[groups['web'][0]].foopass }}"

- name: deploy web servers
  hosts: web
  tasks:
    - name: save secret
      copy:
        dest: foopass.txt
        content: "{{ foopass }}"


This play works, but I don't know how to selectively run the API play if there are no web servers in the play (as they might not exist yet).
If I try '-i localhost, --connection local', then the API task doesn't find any hostvars for a 'web' host:

TASK [populate secret for use elsewhere] ***************************************************************************************************************
fatal: [localhost]: FAILED! =>
  msg: '{{ hostvars[groups[''web''][0]].foopass }}: ''dict object'' has no attribute ''web'''

This seems to make sense. But how would I go about accessing those vars?
Is it possible at all to access variables for hosts that are NOT in the current play?

FYI the variable is not gathered (again, because the web host is not yet there), it is defined in group_vars/web/main.yml - so it is there on disk.

Thanks!

Dick Visser


Todd Lewis

unread,
Sep 16, 2022, 6:50:22 AM9/16/22
to Ansible Project
Can you add
    when: groups['web'] | length
onto the "populate secret for use elsewhere" task?

Todd Lewis

unread,
Sep 16, 2022, 7:19:01 AM9/16/22
to Ansible Project
Better:
    groups['web'] | default([]) | length

Dick Visser

unread,
Sep 16, 2022, 7:39:45 AM9/16/22
to ansible...@googlegroups.com
Hi

Thanks, but that seems to be making the play conditional on whether there are any 'web' hosts in the play.
What I am looking for is a way to access those group_vars regardless of whether there are any such hosts in the play.



--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/c75c3488-9e4b-4c71-97a1-8ff249585605n%40googlegroups.com.

Todd Lewis

unread,
Sep 16, 2022, 9:07:19 AM9/16/22
to Ansible Project
In that case, in the first play, do a "debug" and see what variables are available.
    - name: groupvars anybody
      debug:
        msg: "{{ vars }}"
From that you should be able to work out what the expression would be, if there is a way to do it.

Evan Hisey

unread,
Sep 16, 2022, 9:17:11 AM9/16/22
to ansible...@googlegroups.com
Honestly this sounds more like a need to revisit how you are handling variables. You are creating a scoping issue with the current approach. The all group is were things should live that might need to be accessed by multiple groups. Specific subgroups are for scope specific variables, so really should not be reaching across scopes for variables.

Todd Lewis

unread,
Sep 16, 2022, 9:50:04 AM9/16/22
to Ansible Project
This works in my little test. Worth a try, but this feels shaky.
In your first play, at the same indent level as "tasks:",  add
  vars_files:
    - group_vars/web/main.yml
Then "{{ foopass }}" will be available to your task(s) in that first play.

Brian Coca

unread,
Sep 16, 2022, 10:25:10 AM9/16/22
to ansible...@googlegroups.com
> vars_files:
> - group_vars/web/main.yml
Do not load group_vars/host_vars directly, this is the job of the vars plugin,
you create duplicate entries and mask the actual expected values from
normal precedence resolution.

> msg: '{{ hostvars[groups[''web''][0]].foopass }}: ''dict object''
has no attribute ''web'''
This is not because host is not in current play, it is because the
host is not in inventory, which is a very different issue.

If you want to skip the tasks conditionally, check that the group is
present and has at least one host:

when: "'web' in groups and groups['web'][0]"


----------
Brian Coca

Dick Visser

unread,
Sep 16, 2022, 2:41:34 PM9/16/22
to ansible...@googlegroups.com
Ok thanks for clearing this up.
Just to be sure: it is not possible to access variables for hosts that are not in the inventory?



--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
--
Sent from Gmail Mobile

Evan Hisey

unread,
Sep 16, 2022, 2:55:07 PM9/16/22
to ansible...@googlegroups.com
If hosts are not in the inventory then they dont exist for Ansible. Group variables are different than host variables, by the way. 

Kevin Shumaker

unread,
Sep 16, 2022, 2:57:49 PM9/16/22
to Ansible Project
Is it possible to have multiple 'inventories'? Like a touch list and do not touch list?

Evan Hisey

unread,
Sep 16, 2022, 3:39:57 PM9/16/22
to ansible...@googlegroups.com
Sure. That is the purpose of groups. You can but the entire network in a single inventory, solit it up by groups and groups of groups, then run play books only against the groups you want.  You can also build them on the fly. 

You can also mix that with logic loops in the playbooks to skip certain host with a switch varible.

Todd Lewis

unread,
Sep 16, 2022, 8:59:22 PM9/16/22
to ansible...@googlegroups.com, uto...@gmail.com


On 9/16/22 10:23 AM, Brian Coca wrote:
vars_files:
   - group_vars/web/main.yml
Do not load group_vars/host_vars directly, this is the job of the vars plugin,
you create duplicate entries and mask the actual expected values from
normal precedence resolution.
The vars_files thing was my suggestion, and I heartily endorse Brian's stance on this — i.e. to not to. "This works in my little test" and "this feels shaky" were too subtle. Just don't.

Reflecting further on the nature of the problem as you re-stated it:

Thanks, but that seems to be making the play conditional on whether there are any 'web' hosts in the play.
What I am looking for is a way to access those group_vars regardless of whether there are any such hosts in the play.
If you have a need to access these group variables' values even when there are no host members in the relevant group(s) in your inventory, then I assert that these values are improperly scoped. By that I mean their "true root" should not be that group, but rather some other source that's available to all the places that need it. For example

---
# group_vars/all/web_centric_vars.yml
web_foopass: sEcrEtSauCE
...


---
# group_vars/web/main.yml
foopass: "{{ web_foopass }}"
...

With those two files in place, your initial play becomes
---

- name: do API related work
  hosts: localhost
  connection: local
  become: false
  gather_facts: false
  tags: api
  tasks:
    - name: populate secret for use elsewhere
      community.aws.aws_secret:
        name: foopass
        secret: "{{ web_foopass }}"
...


The later web-scoped play can use 'foopass' from the 'group_vars/web/main.yml' file. This should always work regardless of how many hosts – including zero – are in the 'web' group.

One could reasonably argue that, given 'web_foopass' in an 'all/*' file, there's no need for 'foopass' in a 'group_vars/web' file. However, a 'host_vars/web' file or some other higher precedence source my override the group_vars 'foopass' in certain circumstances. We don't know how much complexity you've left out, so do it the way that will make the most sense to the maintainers.
-- 
Todd

Evan Hisey

unread,
Sep 16, 2022, 9:08:31 PM9/16/22
to ansible...@googlegroups.com, uto...@gmail.com
In a follow up to you line of thought, this really looks a variable (in the example) better handle by usin ansible vault than a variable file. It was designed for things like passwords.

--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.

Todd Lewis

unread,
Sep 16, 2022, 9:23:46 PM9/16/22
to Evan Hisey, ansible...@googlegroups.com, uto...@gmail.com


On 9/16/22 9:08 PM, Evan Hisey wrote:
In a follow up to you line of thought, this really looks a variable (in the example) better handle by usin ansible vault than a variable file. It was designed for things like passwords.
Oh, for sure:
---
# group_vars/all/web_centric_vars.yml
web_foopass: !vault |
  $ANSIBLE_VAULT;1.2;AES256;xyz
  36323135366637613635323035653831393030323833396134653837646335626430346162336634
  3233363235653030333932323762316137346564656664320a303164373831383362383935346638
  37653039646163613537646565376633383866326361323063303162326232303532623835623331
  6439393135396463630a353237636238363963663366616536333536326234636262633865363533
  3530
...


-- 
Todd
Reply all
Reply to author
Forward
0 new messages