network-programmingautomationansiblerefreshinventory

ansible meta: refresh_inventory does not include previously absent hosts in task execution


Sometime ago, somebody suggested using dynamic inventories to generate a different hosts file depending on a location and other variables from a template, but I faced a pretty big issue :

After I create the inventory from a template, I need to refresh it (I do it using meta: refresh_inventory) for Ansible to execute tasks on newly added hosts, however, if the host was not initially in hosts file, ansible does not execute tasks on it. On the other hand, if after changing the host file a host is absent from a newly-formed file, then Ansible omits the host like it should, so the refresh_inventory does half of the work. Is there any way to get around this issue?

E.g. I have 1 task to generate hosts file from template, then refresh inventory, then do a simple task on all hosts, like show message:

 tasks:
  - name: Creating inventory template
    local_action:
         module: template
         src: hosts.j2
         dest: "/opt/ansible/inventories/{{location}}/hosts"
         mode: 0777
         force: yes
         backup: yes
    ignore_errors: yes
    run_once: true

  - name: "Refreshing hosts file for {{location}} location"
    meta: refresh_inventory

  - name: Force refresh of host errors
    meta: clear_host_errors

  - name: Show message
    debug: msg="This works for this host"

If initial hosts file has hosts A, B, C, D, and the newly created inventory has B, C, D, then all is good:

ok: [B] => {
    "msg": "This works for this host"
}
ok: [C] => {
    "msg": "This works for this host"
}
ok: [D] => {
    "msg": "This works for this host"
}

However, if newly formed hosts file has hosts B, C, D, E (E not being present at initial hosts file) then again the result is:

ok: [B] => {
    "msg": "This works for this host"
}
ok: [C] => {
    "msg": "This works for this host"
}
ok: [D] => {
    "msg": "This works for this host"
}

With task for E missing. Now if I replay the playbook, only to add another host, say F, then the result looks like:

ok: [B] => {
    "msg": "This works for this host"
}
ok: [C] => {
    "msg": "This works for this host"
}
ok: [D] => {
    "msg": "This works for this host"
}
ok: [E] => {
    "msg": "This works for this host"
}

But no F, which is already added to the inventory file before the refresh.

So, any ideas?


Solution

  • Quoting from Basics

    For each play in a playbook, you get to choose which machines in your infrastructure to target ... The hosts line is a list of one or more groups or host patterns ...

    For example, it is possible to create the inventory in the 1st play and use it in the 2nd play. The playbook below

    - hosts: localhost
      tasks:
        - template:
            src: hosts.j2
            dest: "{{ playbook_dir }}/hosts"
        - meta: refresh_inventory
    
    - hosts: test
      tasks:
        - debug:
            var: inventory_hostname
    

    with the template (fit it to your needs)

    $ cat hosts.j2
    [test]
    test_01
    test_02
    test_03
    
    [test:vars]
    ansible_connection=ssh
    ansible_user=admin
    ansible_become=yes
    ansible_become_user=root
    ansible_become_method=sudo
    ansible_python_interpreter=/usr/local/bin/python3.6
    ansible_perl_interpreter=/usr/local/bin/perl
    

    give

    PLAY [localhost] ****************************************************************************
    
    TASK [Gathering Facts] **********************************************************************
    ok: [localhost]
    
    TASK [template] *****************************************************************************
    changed: [localhost]
    
    PLAY [test] *********************************************************************************
    
    TASK [Gathering Facts] **********************************************************************
    ok: [test_02]
    ok: [test_01]
    ok: [test_03]
    
    TASK [debug] ********************************************************************************
    ok: [test_01] => {
        "inventory_hostname": "test_01"
    }
    ok: [test_02] => {
        "inventory_hostname": "test_02"
    }
    ok: [test_03] => {
        "inventory_hostname": "test_03"
    }
    
    PLAY RECAP **********************************************************************************
    localhost                  : ok=2    changed=1    unreachable=0    failed=0   
    test_01                    : ok=2    changed=0    unreachable=0    failed=0   
    test_02                    : ok=2    changed=0    unreachable=0    failed=0   
    test_03                    : ok=2    changed=0    unreachable=0    failed=0