-
Notifications
You must be signed in to change notification settings - Fork 24.2k
Description
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) = FalseOS / 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=0Code of Conduct
- I agree to follow the Ansible Code of Conduct