accessing vars for hosts that are not in the play?

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

Can you add
when: groups[‘web’] | length
onto the “populate secret for use elsewhere” task?

Better:
groups[‘web’] | default() | length

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.

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.

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.

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.

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]"

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?

If hosts are not in the inventory then they dont exist for Ansible. Group variables are different than host variables, by the way.

Is it possible to have multiple ‘inventories’? Like a touch list and do not touch list?

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.

The 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: 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 With those two files in place, your initial play becomes

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: