ansible

Ansible prompt selection not setting variable for all hosts


I've been searching for an answer to this and can't seem to find the exact answer. I am running a task which prompts a y or n selection for each elements of an installer_type list.
The issues seems to be that when I run this it is only registering the variable in the first host that it is run it.
How can I have this user input registered for all of the hosts that the playbook is being run against?

- name: AppLauncher Installation
  gather_facts: false
  hosts: all

  tasks:
    - pause:
        prompt: "Select Installer {{ item|basename }} [y/n]"
      register: selected_installers
      loop: "{{ installer_types }}"
      loop_control:
        label: "{{ item|basename }}"

    - name: Run Install roles
      include_role:
        name: "{{ item.item|lower }}"
      loop: "{{ selected_installers.results }}"
      loop_control:
        label: "{{ item.item|basename }}"
      when: item.user_input == 'y' and
            item.item == ( item.item|basename)

When the Run Install roles task is run it throws an error for all hosts except the first host, saying that the selected_installers variable is not defined for those other hosts.


Solution

  • Indeed, I can reproduce this behaviour outside of a role context:

    - pause:
        prompt: "`pause_var` definition"
      register: pause_var
    
    - command: "echo {{ pause_var.user_input }}"
    

    Would fail on two out of my three hosts. So, the fact is not propagated on all hosts.

    This said, there is one playbook keyword designed to propagate results and fact on all hosts, it is run_once.

    run_once
    Boolean that will bypass the host loop, forcing the task to attempt to execute on the first host available and afterwards apply any results and facts to all active hosts in the same batch.

    Source: https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#task

    So, your fix would be to add that run_once: true in your pause task:

    - pause:
        prompt: "Select Installer {{ item|basename }} [y/n]"
      register: selected_installers
      run_once: true
      loop: "{{ installer_types }}"
      loop_control:
        label: "{{ item|basename }}"
    

    Given the two tasks:

    - pause:
        prompt: "`pause_var` definition"
      register: pause_var
      run_once: true
    
    - command: "echo {{ pause_var.user_input }}"
      no_log: true # added to make the fatal error less verbose
    

    A run would yield:

    TASK [pause] ******************************************************
    [pause]
    `pause_var` definition:
    foo^Mok: [ansible-node-1]
    
    TASK [command] ****************************************************
    changed: [ansible-node-3]
    changed: [ansible-node-2]
    changed: [ansible-node-1]
    

    Demonstration of the failing behaviour:

    - pause:
        prompt: "`pause_var` definition"
      register: pause_var
    
    - command: "echo {{ pause_var.user_input }}"
      no_log: true # added to make the fatal error less verbose
    

    Running those two tasks:

    TASK [pause] ******************************************************
    [pause]
    `pause_var` definition:
    foo^Mok: [ansible-node-1]
    
    TASK [command] ****************************************************
    fatal: [ansible-node-2]: FAILED! => 
      censored: 'the output has been hidden due to 
        the fact that ''no_log: true'' was specified for this result'
    fatal: [ansible-node-3]: FAILED! => 
      censored: 'the output has been hidden due to 
        the fact that ''no_log: true'' was specified for this result'
    changed: [ansible-node-1]