'How to prompt user for a target host in Ansible?

I want to write a bootstrapper playbook for new machines in Ansible which will reconfigure the network settings. At the time of the first execution target machines will have DHCP-assigned address.

The user who is supposed to execute the playbook knows the assigned IP address of a new machine. I would like to prompt the user for is value.

vars_prompt module allows getting input from the user, however it is defined under hosts section effectively preventing host address as the required value.

Is it possible without using a wrapper script modifying inventory file?



Solution 1:[1]

The right way to do this is to create a dynamic host with add_host and place it in a new group, then start a new play that targets that group. That way, if you have other connection vars that need to be set ahead of time (credentials/keys/etc) you could set them on an empty group in inventory, then add the host to it dynamically. For example:

- hosts: localhost
  gather_facts: no
  vars_prompt:
  - name: target_host
    prompt: please enter the target host IP
    private: no
  tasks:
    - add_host:
        name: "{{ target_host }}"
        groups: dynamically_created_hosts

- hosts: dynamically_created_hosts
  tasks:
  - debug: msg="do things on target host here"

Solution 2:[2]

You could pass it with extra-vars instead.

Simply make your hosts section a variable such as {{ hosts_prompt }} and then pass the host on the command line like so:

ansible-playbook -i inventory/environment playbook.yml --extra-vars "hosts_prompt=192.168.1.10"

Or if you are using the default inventory file location of /etc/ansible/hosts you could simply use:

ansible-playbook playbook.yml --extra-vars "hosts_prompt=192.168.1.10"

Solution 3:[3]

Adding to Matt's answer for multiple hosts.

input example would be 192.0.2.10,192.0.2.11

- hosts: localhost
  gather_facts: no
  vars_prompt:
  - name: target_host
    prompt: please enter the target host IP
    private: no
  tasks:
    - add_host:
        name: "{{ item }}"
        groups: dynamically_created_hosts
      with_items: "{{ target_host.split(',') }}"


- hosts: dynamically_created_hosts
  tasks:
  - debug: msg="do things on target host here"

Solution 4:[4]

Disclaimer: The accepted answer offers the best solution to the problem. While this one is working it is based on a hack and I leave it as a reference.

I found out it was possible use a currently undocumented hack (credit to Bruce P for pointing me to the post) that turns the value of -i / --inventory parameter into an ad hoc list of hosts (reference). With just the hostname/ip address and a trailing space (like below) it refers to a single host without the need for the inventory file to exist.

Command:

ansible-playbook -i "192.168.1.21," playbook.yml

And accordingly playbook.yml can be run against all hosts (which in the above example will be equal to a single host 192.168.1.21):

- hosts: all 

The list might contain more than one ip address -i "192.168.1.21,192.168.1.22"

Solution 5:[5]

Adding to Jacob's and Matt's examples, with the inclusion of a username and password prompt:

---

- hosts: localhost
  pre_tasks:
    - name: verify_ansible_version
      assert:
        that: "ansible_version.full is version_compare('2.10.7', '>=')"
        msg: "Error: You must update Ansible to at least version 2.10.7 to run this playbook..."
  vars_prompt:
    - name: target_hosts
      prompt: |
        Enter Target Host IP[s] or Hostname[s] (comma separated)
        (example: 1.1.1.1,myhost.example.com)
      private: false
    - name: username
      prompt: Enter Target Host[s] Login Username
      private: false
    - name: password
      prompt: Enter Target Host[s] Login Password
      private: true
  tasks:
    - add_host:
        name: "{{ item }}"
        groups: host_groups
      with_items:
        - "{{ target_hosts.split(',') }}"
    - add_host:
        name: login
        username: "{{ username }}"
        password: "{{ password }}"
- hosts: host_groups
  remote_user: "{{ hostvars['login']['username'] }}"
  vars:
    ansible_password: "{{ hostvars['login']['password'] }}"
    ansible_become: yes
    ansible_become_method: sudo
    ansible_become_pass: "{{ hostvars['login']['password'] }}"
  roles:
    - my_role

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 nitzmahone
Solution 2
Solution 3 Jacob Evans
Solution 4 Community
Solution 5