Search code examples
ansibleansible-2.xansible-inventory

How add hosts from user's input in a ansible playbook?


I need to add a host from the user's input. Now I'm trying to use the ansible in-memory inventory, add_host module and prompt to add the target host to execute the remaining tasks. This is the content of my playbook:

Deploy.yml

- name: Adding the host server
  hosts: localhost

- vars_prompt:
  - name: "Server IP"
    prompt: "Server"
    private: no

  - name: "Username (default: Ubuntu)"
    prompt: "User"
    default: "Ubuntu"
    private: no

  - name: "Password"
    prompt: "Passwd"
    private: yes
    encrypt: "sha512_crypt"

  - name: "Identity file path"
    prompt: "IdFile"
    private: no
    when: Passwd is undefined

  tasks:
    - name: Add host server
      add_host:
        name: "{{ Server }}"
        ansible_ssh_user: "{{ User }}"
        ansible_ssh_private_key_file: "{{ IdFile }}"
      when: IdFile is defined

    - name: Add host server
      add_host:
        name: "{{ Server }}"
        ansible_ssh_user: "{{ User }}"
        ansible_ssh_pass: "{{ Passwd }}"
      when: Passwd is defined

- hosts: "{{ Server }}"

tasks:
    - name: Copy the script file to the server
      copy:
        src: script.sh
        dest: "{{ ansible_env.HOME }}/folder/"
        mode: 755
        force: yes
        attr:
          - +x

When I run this playbook with this command $ ansible-playbook Deploy.yml, The output is:

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'


PLAY [Adding the host server] ***********************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************
ok: [localhost]
Server: <server-ip>
User [Ubuntu]:
Passwd:
IdFile: <path/to/id/file>
ERROR! the field 'hosts' is required but was not set

I don't know why it throws this error:

ERROR! the field 'hosts' is required but was not set

How can I do what I need to do?

UPDATE:

It still not working. This is the content of my playbook:

Deploy.yml

- name: Adding the host server
  hosts: localhost

  vars_prompt:
  - name: "Server"
    prompt: "Server IP"
    private: no

  - name: "User"
    prompt: "Username"
    default: "Ubuntu"
    private: no

  - name: "Passwd"
    prompt: "Password"
    private: yes
    encrypt: "sha512_crypt"

  - name: "IdFile"
    prompt: "Identity file path"
    private: no
    when: Passwd is undefined

  tasks:
    - name: Add host server
      add_host:
        name: "{{ Server }}"
        ansible_ssh_user: "{{ User }}"
        ansible_ssh_private_key_file: "{{ IdFile }}"
      when: IdFile is defined

    - name: Add host server
      add_host:
        name: "{{ Server }}"
        ansible_ssh_user: "{{ User }}"
        ansible_ssh_pass: "{{ Passwd }}"
      when: IdFile is undefined

- hosts: "{{ Server }}"

  tasks:
    - name: Copy the script file to the server
      copy:
        src: script.sh
        dest: "{{ ansible_env.HOME }}/folder/"
        mode: 755
        force: yes
        attr:
          - +x

When I run this playbook with this command $ ansible-playbook Deploy.yml, The output is:

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'


PLAY [Adding the host server] ***********************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************
ok: [localhost]
Server IP: <server-ip>
Username [Ubuntu]:
Password:
Identity file path: <path/to/id/file>
ERROR! the field 'hosts' is required but was not set

I don't know why it throws this error:

ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'Server' is undefined

Here is a flowchart of how the playbook should works:

+------------------+     +---------------+     +-----------------+
|Use ansible to run|     |Get host IP fom|     |Get ssh User from|
|  this playbook   +---->+ user's input  +---->+  user's input   |
+------------------+     +---------------+     +--------+--------+
                                                        |
                                                        v
                                           +------------+--------+
                                           |Get ssh password from|
                                           |    user's input     |
                                           +------------+--------+
                                                        |
                                                        v
                   +---------------+     *************************
                   |Add a host with| Yes | Did the user inputted |
        v----------+   password    +<---+|      a password?      |
+----------------+ +---------------+     ***************+*********
||Run some tasks||                                      |No
||in recently   ||                                      v
||added host    || +---------------+       +------------+--------+
+----------------+ |Add a host with|       |Get ssh identity file|
        ^----------+ identity file +<------+  from user's input  |
                   +---------------+       +---------------------+

Solution

  • Ok I've updated my answer to suit the changes in your question, with the original answer left for historic reasons.

    To solve the substitution error you are seeing, which results in an empty host list in your second play, I would instead use an inventory group.

    There are also two other syntax errors in the second play

    1. The file mode needs to be octal (i.e. 0700)
    2. The attribute is invalid. My assumption is you are trying to make the file executable, so fix the file mode and remove the attribute.

    Here is an updated playbook:

    - name: Adding the host server
      hosts: localhost
    
      vars_prompt:
        - name: "Server"
          prompt: "Server IP"
          private: no
    
        - name: "User"
          prompt: "Username"
          default: "Ubuntu"
          private: no
    
        - name: "Passwd"
          prompt: "Password"
          private: yes
          encrypt: "sha512_crypt"
    
        - name: "IdFile"
          prompt: "Identity file path"
          private: no
          when: Passwd is undefined
    
      tasks:
        - name: Add host server
          add_host:
            name: "{{ Server }}"
            ansible_ssh_user: "{{ User }}"
            ansible_ssh_private_key_file: "{{ IdFile }}"
            group: added_hosts
          when: IdFile is defined
    
        - name: Add host server
          add_host:
            name: "{{ Server }}"
            ansible_ssh_user: "{{ User }}"
            ansible_ssh_pass: "{{ Passwd }}"
            group: added_hosts
          when: IdFile is undefined
    
    - hosts: added_hosts
    
      tasks:
        - name: Copy the script file to the server
          copy:
            src: script.sh
            dest: "{{ ansible_env.HOME }}/folder/"
            mode: 0755
            force: yes
    

    === OLD ANSWER ===

    User input is stored in the whatever variable you are using for the name attribute in each of the variable prompts.

    You need to switch around your name and prompt values under vars_prompt

    There are also YAML formatting issues

    For example:

    - vars_prompt:
      - name: "Server IP"
        prompt: "Server"
        private: no
    

    should be:

      vars_prompt:
        - name: "server"
          prompt: "Server IP"
          private: no
    

    Then you can refer to the {{ server }} variable in your tasks