Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

SSH connection has_tty does not check use_tty option, breaks machinectl #86298

@LichP

Description

@LichP

Summary

Since 2.19, tasks using the community.general.machinectl become method now fail with the following error:

[ERROR]: Task failed: The 'ssh' connection does not provide a TTY which is required for the selected become plugin: community.general.machinectl.

The same tasks work as expected with 2.18. This appears to be due to changes to the has_tty property in the ssh connection plugin introduced in 2.19: see 7290959 . This change implements has_tty using the new _is_tty_requested method, which does not seem to check the TTY requirement in a way that is consistent with the behaviour in exec_command.

Adding a check for the use_tty option at the top of _is_tty_requested in ansible/lib/ansible/plugins/connection/ssh.py resolves the problem and allows tasks to run normally as per 2.18:

     def _is_tty_requested(self):

+        # check use_tty option
+        if self.get_option('use_tty'):
+            return True
+
         # check if we require tty (only from our args, cannot see options in configuration files)
         opts = []

I'm unsure if this is the correct approach or if a deeper change is needed, however it is successfully acting as a workaround for me at present.

Issue Type

Bug Report

Component Name

ssh

Ansible Version

$ ansible --version
ansible [core 2.20.0]
  config file = /path/redacted/ansible.cfg
  configured module search path = ['/home/pstewart/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/pstewart/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible
  ansible collection location = /home/pstewart/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/pstewart/.local/bin/ansible
  python version = 3.13.5 (main, Jun 25 2025, 18:55:22) [GCC 14.2.0] (/home/pstewart/.local/pipx/venvs/ansible/bin/python)
  jinja version = 3.1.6
  pyyaml version = 6.0.3 (with libyaml v0.2.5)

Configuration

# if using a version older than ansible-core 2.12 you should omit the '-t all'
$ ansible-config dump --only-changed -t all
CONFIG_FILE() = /path/redacted/ansible.cfg
DEFAULT_HOST_LIST(/path/redacted/ansible.cfg) = ['/path/redacted/inventories/dev.yml']
DEFAULT_STDOUT_CALLBACK(/path/redacted/ansible.cfg) = default
DEFAULT_VAULT_IDENTITY_LIST(/path/redacted/ansible.cfg) = [REDACTED]
HOST_KEY_CHECKING(/path/redacted/ansible.cfg) = False

GALAXY_SERVERS:


CONNECTION:
==========

paramiko_ssh:
____________
host_key_checking(/path/redacted/ansible.cfg) = False

ssh:
___
host_key_checking(/path/redacted/ansible.cfg) = False

OS / Environment

Host OS: Debian Trixie
Target OS: RHEL 9.7

Steps to Reproduce

- name: Debug ssh connection TTY-related settings
  hosts: all
  gather_facts: false

  tasks:
    - name: Show ssh connection config as Ansible sees it
      ansible.builtin.debug:
        msg:
          ansible_connection: "{{ ansible_connection | default('ssh (implicit)') }}"
          ansible_ssh_use_tty: "{{ ansible_ssh_use_tty | default('UNSET') }}"
          ansible_ssh_common_args: "{{ ansible_ssh_common_args | default('UNSET') }}"
          ansible_ssh_args: "{{ ansible_ssh_args | default('UNSET') }}"
          ansible_ssh_extra_args: "{{ ansible_ssh_extra_args | default('UNSET') }}"
          ansible_pipelining: "{{ ansible_pipelining | default('UNSET') }}"

    - name: Simple echo under machinectl
      become: true
      become_user: appuser
      become_method: community.general.machinectl
      ansible.builtin.command:
        cmd: '/bin/echo "hello from machinectl"'

Expected Results


PLAY [Debug ssh connection TTY-related settings] ***********************************************************************************************************

TASK [Show ssh connection config as Ansible sees it] *******************************************************************************************************
ok: [target.example.com] => {
    "msg": {
        "ansible_connection": "ssh",
        "ansible_pipelining": false,
        "ansible_ssh_args": "-C -o ControlMaster=auto -o ControlPersist=60s",
        "ansible_ssh_common_args": "UNSET",
        "ansible_ssh_extra_args": "UNSET",
        "ansible_ssh_use_tty": true
    }
}

TASK [Simple echo under machinectl] ************************************************************************************************************************
changed: [target.example.com]

PLAY RECAP *************************************************************************************************************************************************
target.example.com       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Actual Results

PLAY [Debug ssh connection TTY-related settings] ***********************************************************************************************************

TASK [Show ssh connection config as Ansible sees it] *******************************************************************************************************
ok: [target.example.com] => {
    "msg": {
        "ansible_connection": "ssh",
        "ansible_pipelining": false,
        "ansible_ssh_args": "-C -o ControlMaster=auto -o ControlPersist=60s",
        "ansible_ssh_common_args": "UNSET",
        "ansible_ssh_extra_args": "UNSET",
        "ansible_ssh_use_tty": true
    }
}

TASK [Simple echo under machinectl] ************************************************************************************************************************
[ERROR]: Task failed: The 'ssh' connection does not provide a TTY which is required for the selected become plugin: community.general.machinectl.
Origin: /path/to/playbook.yml:16:7

14           ansible_pipelining: "{{ ansible_pipelining | default('UNSET') }}"
15
16     - name: Simple echo under machinectl
         ^ column 7

fatal: [target.example.com]: FAILED! => {"changed": false, "msg": "Task failed: The 'ssh' connection does not provide a TTY which is required for the selected become plugin: community.general.machinectl."}

PLAY RECAP *************************************************************************************************************************************************
target.example.com       : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Code of Conduct

  • I agree to follow the Ansible Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    affects_2.20bugThis issue/PR relates to a bug.has_prThis issue has an associated PR.needs_triageNeeds a first human triage before being processed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions