How to prompt user for a target host in Ansible?
Asked Answered
P

5

13

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?

Pierre answered 14/10, 2015 at 7:23 Comment(0)
C
30

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"
Caesium answered 13/4, 2016 at 17:2 Comment(1)
What happens if you keep running the same playbook with exactly the same IP as input? Does it keep adding IPs to a file somewhere, or the dynamically_created_hosts get's cleared at the end of the execution? In other words, is dynamically_created_hosts persisted?Autocrat
S
8

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"
Spiderwort answered 14/10, 2015 at 7:32 Comment(4)
The inventory/environment part is just an example (as with playbook.yml). If you don't provide an inventory file with -i then Ansible will simply pick up the default inventory file /etc/ansible/hosts which is not normally what you want even when you are specifying the hosts using extra-varsSpiderwort
It's an example about how to pass extra-vars, not a "here's the exact line you need to type". And an inventory is a necessary argument, it just defaults to /etc/ansible/hosts and if that file doesn't exist then it will fail.Spiderwort
@techraf: Your suggested edits were rejected in the review queue. ydaetskcoR has nothing to do with that. Edits like that are simply not accepted on SO. Since this answer does currently provide the answer for you, you really should accept it, for future visitors' sake.Ailsun
Your answer was deleted because it was a copy-paste of this one. Plagiarism like that is not allowed on SO. The OP of this answer now added your specific case to the answer, so I really see no reason not to accept this one.Ailsun
D
6

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"
Draggle answered 25/9, 2017 at 15:57 Comment(0)
P
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"

Pierre answered 26/10, 2015 at 14:20 Comment(1)
I don't like this approach because if someone runs the playbook without parameters by mistake the hell breaks loose.Discontent
S
0

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
Schwejda answered 21/4, 2022 at 18:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.