'Is there a way to re-set the "hosts" variable within a playbook?

I am tasked with creating a playbook, where I perform the following operations:

  • Fetch information from a YAML file (the file contains details on VLANs)
  • Cycle through the YAML objects and verify which subnet contains the IP, then return the object
  • The object contains also a definition of the inventory_hostname where to run the Ansible playbook

At the moment, I have the following (snippet):

Playbook:

- name: "Playbook"
  gather_facts: false
  hosts: "localhost"
  tasks: 
    - name: "add host"
      add_host:
        name: "{{ vlan_target }}"
    - name: "debug"
      debug:
        msg: "{{ inventory_hostname }}" 

The defaults file defines the target_host as an empty string "" and then it is evaluated within another role task, like so (snippet):

Role:

- set_fact: 
    vlan_object: "vlan | trim | from_json | first"

- name: "set facts based on IP address"
  set_fact:
    vlan_name: "{{ vlan_object.name }}"
    vlan_target: "{{ vlan_object.target }}"
  delegate_to: localhost

What I am trying to achieve is to change the hosts: variable so that I can use the right target, since the IP/VLAN should reside on a specific device.

I have tried to put the aforementioned task above the add_host, or even putting in the same playbook, like so:

- name: "Set_variables"
  hosts: "localhost"
  tasks:
    - name: "Set target host"
      import_role:
        name: test
        tasks_from: target_selector

- name: "Playbook"
  gather_facts: false
  hosts: "localhost"

Adding a debug clause to the above playbook sets the right target, but it is not re-used below, making me think that the variable is not set globally, but within that run.

I am looking for a way to set the target, based on a variable that I am passing to the playbook.

Does anyone have any experience with this?



Solution 1:[1]

Global facts are not a thing, at best you can assign a fact to all hosts in the play, but since you are looking to use the said fact to add an host, this won't be a solution for your use case.

You can access facts of another hosts via the hostvars special variable, though. It is a dictionary where the keys are the names of the hosts.

The usage of the role is not relevant to your issue at hand, so, in the demonstration below, let's put this aside.

Given the playbook:

- hosts: localhost
  gather_facts: no
  
  tasks: 
    - set_fact:
        ## fake object, since we don't have the structure of your JSON 
        vlan_object:
          name: foo
          target: bar

    - set_fact:
        vlan_name: "{{ vlan_object.name }}"
        vlan_target: "{{ vlan_object.target }}"
      run_once: true

    - add_host:
        name: "{{ vlan_target }}"

- hosts: "{{ hostvars.localhost.vlan_target }}"
  gather_facts: no

  tasks:
    - debug:
        var: ansible_play_hosts

This would yield

PLAY [localhost] *************************************************************

TASK [set_fact] **************************************************************
ok: [localhost]

TASK [set_fact] **************************************************************
ok: [localhost]

TASK [add_host] **************************************************************
changed: [localhost]

PLAY [bar] *******************************************************************

TASK [debug] *****************************************************************
ok: [bar] => 
  ansible_play_hosts:
  - bar  

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 β.εηοιτ.βε