AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible expect Module: Handle Interactive Prompts & Input (Guide)

By Luca Berton · Published 2024-01-01 · Category: installation

How to handle interactive command prompts with Ansible expect module (ansible.builtin.expect). Automate password prompts, respond to questions.

The ansible.builtin.expect module runs commands that require interactive input — responding to password prompts, confirmations, license agreements, and multi-step installers. It uses Python's pexpect library to match prompts and send responses.

Prerequisites

The pexpect library must be installed on the remote host:

- name: Install pexpect
  ansible.builtin.pip:
    name: pexpect
    state: present
  become: true

Or via system packages:

- name: Install pexpect (Debian/Ubuntu)
  ansible.builtin.apt:
    name: python3-pexpect
    state: present
  become: true

- name: Install pexpect (RHEL/CentOS) ansible.builtin.dnf: name: python3-pexpect state: present become: true

See also: Ansible expect Module: Automate Interactive Commands (Examples)

Basic Usage

- name: Change user password
  ansible.builtin.expect:
    command: passwd johndoe
    responses:
      "New password:": "SecureP@ss123"
      "Retype new password:": "SecureP@ss123"
  become: true
  no_log: true

Key Parameters

| Parameter | Description | Default | |-----------|-------------|---------| | command | Command to run | (required) | | responses | Dict of prompt→response pairs | (required) | | timeout | Seconds to wait for each prompt | 30 | | echo | Show command output | false | | chdir | Working directory | — | | creates | Skip if file exists | — | | removes | Skip if file doesn't exist | — |

See also: Ansible Set File Permissions 755: chmod with file Module Guide

Pattern Matching with Regex

The responses keys are Python regular expressions:

- name: Accept license agreement
  ansible.builtin.expect:
    command: /opt/installer/setup.sh
    responses:
      # Regex patterns for flexible matching
      "(?i)do you accept.*license": "yes"
      "(?i)enter.*installation.*directory": "/opt/myapp"
      "(?i)continue.*\\?": "y"
      "(?i)password": "{{ vault_app_password }}"
    timeout: 120
  no_log: true

Real-World Examples

MySQL Secure Installation

- name: Secure MySQL installation
  ansible.builtin.expect:
    command: mysql_secure_installation
    responses:
      "Enter password for user root:": "{{ mysql_root_pass }}"
      "VALIDATE PASSWORD": "y"
      "Please enter.*strength.*password": "2"
      "Change the password for root": "n"
      "Remove anonymous users": "y"
      "Disallow root login remotely": "y"
      "Remove test database": "y"
      "Reload privilege tables now": "y"
    timeout: 30
  become: true
  no_log: true

SSH Key Generation

- name: Generate SSH key non-interactively
  ansible.builtin.expect:
    command: ssh-keygen -t ed25519 -C "deploy@example.com"
    responses:
      "Enter file in which to save": "/home/deploy/.ssh/id_ed25519"
      "Enter passphrase": ""
      "Enter same passphrase": ""
    creates: /home/deploy/.ssh/id_ed25519
  become: true
  become_user: deploy

Software Installation

- name: Install application interactively
  ansible.builtin.expect:
    command: /tmp/installer.bin
    responses:
      "Press ENTER to continue": ""
      "(?i)accept.*license.*\\(yes/no\\)": "yes"
      "Installation directory": "/opt/app"
      "(?i)create.*directory": "y"
      "Admin username": "admin"
      "Admin password": "{{ vault_admin_pass }}"
      "Confirm password": "{{ vault_admin_pass }}"
      "Start service now": "yes"
    timeout: 300
    creates: /opt/app/bin/server
  become: true
  no_log: true

Handling Repeated Prompts

When a prompt appears multiple times, provide a list of responses:

- name: Interactive setup with repeated prompts
  ansible.builtin.expect:
    command: /opt/app/setup.sh
    responses:
      "Enter value:":
        - "first_value"
        - "second_value"
        - "third_value"
      "Confirm.*\\?": "yes"
    timeout: 60

See also: Add Windows Registry on Windows-like systems - Ansible module win_regedit

Timeout Handling

- name: Long-running interactive command
  ansible.builtin.expect:
    command: /opt/backup/full-backup.sh
    responses:
      "(?i)password": "{{ vault_backup_pass }}"
      "(?i)continue": "yes"
    timeout: 3600  # 1 hour
  async: 7200     # Ansible-level timeout: 2 hours
  poll: 30

Idempotent expect

- name: Initialize database (only if not done)
  ansible.builtin.expect:
    command: /opt/app/bin/init-db
    responses:
      "Admin email:": "admin@example.com"
      "Admin password:": "{{ vault_db_admin_pass }}"
    creates: /opt/app/data/.initialized
  no_log: true

Security: Always Use no_log

⚠️ Always set no_log: true when responses contain passwords or secrets:

# BAD — passwords appear in Ansible output and logs
- ansible.builtin.expect:
    command: passwd user1
    responses:
      "New password:": "secret123"

# GOOD — output is suppressed - ansible.builtin.expect: command: passwd user1 responses: "New password:": "{{ vault_user_password }}" no_log: true

When NOT to Use expect

Many interactive commands have non-interactive alternatives:

| Interactive Command | Non-Interactive Alternative | |---|---| | passwd | ansible.builtin.user module with password | | mysql_secure_installation | Direct SQL commands | | ssh-keygen (with passphrase) | community.crypto.openssh_keypair | | apt install (prompts) | ansible.builtin.apt (handles it) | | fdisk | community.general.parted |

Use expect as a last resort — native modules are more reliable and idempotent.

FAQ

Why do I get "No module named 'pexpect'"?

Install pexpect on the remote host (not the control node). Use pip install pexpect or install the system package python3-pexpect.

How do I handle a prompt that appears multiple times?

Use a list of responses instead of a single string. Ansible sends each response in order for successive matches of the same prompt pattern.

Why doesn't my pattern match?

Response keys are Python regex patterns. Special characters (?, (, ), [, ]) need escaping with \\. Use (?i) for case-insensitive matching. Test patterns with python3 -c "import re; print(re.search(r'your_pattern', 'test_string'))".

Conclusion

Use ansible.builtin.expect for interactive commands that have no non-interactive alternative. Always use no_log: true for security, regex patterns for flexible matching, and creates/removes for idempotency. Prefer native Ansible modules when available.

Related Articles

Ansible command ModuleAnsible shell vs commandAnsible Vault Deep Dive

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home