AnneTheAgile
AnneTheAgile

Reputation: 10260

Ansible to Conditionally Prompt for a Variable?

I would like to be able to prompt for my super secure password variable if it is not already in the environment variables. (I'm thinking that I might not want to put the definition into .bash_profile or one of the other spots.)

This is not working. It always prompts me.

vars:
  THISUSER: "{{ lookup('env','LOGNAME') }}"
  SSHPWD:   "{{ lookup('env','MY_PWD') }}"

vars_prompt:
  - name: "release_version"
    prompt: "Product release version"
    default: "1.0"
    when: SSHPWD == null

NOTE: I'm on a Mac, but I'd like for any solutions to be platform-independent.

Upvotes: 44

Views: 53834

Answers (8)

erwin
erwin

Reputation: 738

You can conditionally skip execution of the vars_prompt: prompt by defining the variable on the command line.

Let's say you have:

  vars_prompt:
    - name: server
      prompt: New Server Name? (skip with -e "server=foo")
      private: false

If you run this playbook with `ansible-playbook your_playbook.yml -e "server=foo", then the prompt will be skipped. And if you run the playbook without the extra_vars definition, you'll be prompted for the undefined variable.

The actual ansible code in question is here. extra_vars is the long form of -e.

if vname not in self._variable_manager.extra_vars

If your goal is more of a programmatic usage of extra_vars with an actual when: clause, this is not possible. Instead the official recommendation from the Ansible team is to use the pause module:

when is not a supported keyword on vars (even in vars_prompt), if you want to use conditional input look at the pause module

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/pause_module.html

Upvotes: 0

huyz
huyz

Reputation: 2371

Based on @tehmoon's answer, this is what worked for me with ansible-core 2.14:

  tasks:
    - name: Prompt SSH password if necessary
      when: ansible_password is undefined
      block:
        - name: Conditionally prompt for ssh/sudo password
          ansible.builtin.pause:
            prompt: "Password for {{ ansible_user_id }}@{{ ansible_host }}"
            echo: false
          register: password_prompt
          no_log: true

        - name: Set ansible_password
          ansible.builtin.set_fact:
            ansible_password: "{{ password_prompt.user_input }}"
          no_log: true

    - name: Set ansible_become_password
      ansible.builtin.set_fact:
        ansible_become_password: "{{ ansible_password }}"
      no_log: true
      when: ansible_become_password is undefined

Upvotes: 0

keypress
keypress

Reputation: 799

Based on tehmoon's answer with some modifications I did it that way:

- hosts:
    - hostA
  become: yes
  pre_tasks:
    - pause:
        prompt: "Give your username"
      register: prompt
      no_log: yes
      run_once: yes
    - set_fact:
        username: "{{prompt.user_input}}"
      no_log: yes
      run_once: yes
    - pause:
        prompt: "Give your password"
        echo: no
      register: prompt
      no_log: yes
      run_once: yes
    - set_fact:
        password: "{{prompt.user_input}}"
      no_log: yes
      run_once: yes
  tags: [my_role_using_user_pass]
  roles:
    - role: my_role_using_user_pass

Upvotes: 10

Alex Pretty
Alex Pretty

Reputation: 41

This works for me (2.3) .. do two bits in the one file. This allows me to consruct a tmp vars file when running the playbook via jenkins.. but also allow prompting on the command line

And you get to do it with only the one var used

---
- name: first bit                                    
  hosts:                            all
  connection:                       local            
  tasks: 
  - set_fact:                                  
      favColour:                   "{{ favColour }}" 
    when: favColour is defined

- name: second bit                                    
  hosts:                            all
  connection:                       local            
  vars_prompt:
    favColour: 
      prompt:                       "Whats ya favorite colour: "
    when: favColour is not defined

  tasks:
    - debug:                        msg="{{favColour}}"

Upvotes: 2

Silveri
Silveri

Reputation: 5261

As can be seen in the source code, the when keyword isn't implemented for vars_prompt (and in fact never was). The same was mentioned in this Github comment.

The only way in which vars_prompt is currently conditional is that it only prompts when the variable (defined in name) is already defined (using the command-line extra_vars argument).

Upvotes: 4

tehmoon
tehmoon

Reputation: 597

I might be late to the party but a quick way to avoid vars_prompt is to disable the interactive mode by doing that simple trick:

echo -n | ansible-playbook -e MyVar=blih site.yaml

This add no control over which vars_prompt to avoid but coupled with default: "my_default" it can be used in a script.

Full example here:

---
- hosts: localhost
  vars_prompt:
    - prompt: Enter blah value
    - default: "{{ my_blah }}"
    - name: blah

echo -n | ansible-playbook -e my_blah=blih site.yaml

EDIT:

I've found that using the pause module and the prompt argument was doing what I wanted:

---
- pause:
      prompt: "Sudo password for localhost "
  when: ( env == 'local' ) and
      ( inventory_hostname == "localhost" ) and
      ( hostvars["localhost"]["ansible_become_password"] is not defined )
  register: sudo_password
  no_log: true
  tags:
       - always

Upvotes: 38

Confiks
Confiks

Reputation: 41

This is indeed not possible by default in Ansible. I understand the reasoning behind not allowing it, yet I think it can be appropriate in some contexts. I've been writing an AWS EC2 deploy script, using the blue/green deploy system, and at some point in the role I need to ask the user if a rollback needs to be done if something has gone awry. As said, there is no way to do this (conditionally and/or non-fugly).

So I wrote a very simple Ansible (2.x) action plugin, based on the pause action from the standard library. It a bit spartan in that it only accepts a single key press, but it might be of use. You can find it in a Github gist here. You need to copy the whole Gist file to the action_plugins directory of your playbook directory. See the documentation in the file.

Upvotes: 4

adm_
adm_

Reputation: 662

According to the replies from the devs and a quick test I've done with the latest version, the vars_prompt is run before "GATHERING FACTS". This means that the env var SSHPWD is always null at the time of your check with when.

Unfortunately it seems there is no way of allowing the vars_prompt statement at task level.

Michael DeHaan's reasoning for this is that allowing prompts at the task-level would open up the doors to roles asking a lot of questions. This would make using Ansible Galaxy roles which do this difficult:

There's been a decided emphasis in automation in Ansible and asking questions at task level is not something we really want to do.

However, you can still ask vars_prompt questions at play level and use those variables throughout tasks. You just can't ask questions in roles.

And really, that's what I would like to enforce -- if a lot of Galaxy roles start asking questions, I can see that being annoying :)

Upvotes: 51

Related Questions