Ansible can't find /bin/sh in chroot directory

Hi

I am trying to create a directory in a block device (mounted on /media/ajaved/PIROOT) using Ansible chroot connection and it fails with the following message:

redirecting (type: connection) ansible.builtin.chroot to community.general.chroot
The full traceback is:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/ansible/executor/task_executor.py", line 165, in run
    res = self._execute()
  File "/usr/lib/python3/dist-packages/ansible/executor/task_executor.py", line 574, in _execute
    self._connection = self._get_connection(cvars, templar, current_connection)
  File "/usr/lib/python3/dist-packages/ansible/executor/task_executor.py", line 953, in _get_connection
    connection, plugin_load_context = self._shared_loader_obj.connection_loader.get_with_context(
  File "/usr/lib/python3/dist-packages/ansible/plugins/loader.py", line 936, in get_with_context
    obj.__init__(instance, *args, **kwargs)  # pylint: disable=unnecessary-dunder-call
  File "/usr/lib/python3/dist-packages/ansible_collections/community/general/plugins/connection/chroot.py", line 127, in __init__
    if not (is_executable(chrootsh) or (os.path.lexists(chrootsh) and os.path.islink(chrootsh))):
  File "/usr/lib/python3/dist-packages/ansible/module_utils/common/file.py", line 74, in is_executable
    return ((stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) & os.stat(path)[stat.ST_MODE])
FileNotFoundError: [Errno 2] No such file or directory: '/media/ajaved/PIROOT/bin/sh'
  pikvm3 failed: {
    "msg": "Unexpected failure during module execution: [Errno 2] No such file or directory: '/media/ajaved/PIROOT/bin/sh'",
    "stdout": ""
}

Ansible is somehow failing to find the default executable /bin/sh inside chroot directory /media/ajaved/PIROOT but I checked, and the file is there already. My host OS is Ubuntu Jammy (22.04) and Ansible version is 2.10.8. I also tried with newest Ansible version 2.16.5 and the problem is still there.

On Ubuntu Focal (20.04), I don’t have this error and everything is fine. Any help is much appreciated.

Thanks

Could you provide some more details, like the key parts of the inventory, playbook and role you are using? And the ownership and permissions of the chroot directory and the permissions of the user you are running Ansible as?

This is the inventory file:

all:
  children:
    kvms:
      hosts:
        pikvm3:
          image: v3-hdmi-rpi4-box-20240417.img.xz
          image_checksum: sha1:272e54cd3bfc1078c43e36fb72cddfe5200ff96c

We have an Ansible role called flash and the tasks main.yml file is:

- name: Image is fetched
  get_url:
    url: 'https://files.pikvm.org/images/{{ image }}'
    dest: '{{ role_path }}/files/{{ image }}'
    checksum: '{{ image_checksum }}'

- name: Rewriting SD card
  shell: |
    set -euf
    xzcat {{ role_path }}/files/{{ image }} > /dev/sdb
    sync
    eject /dev/sdb
  tags: slow

- name: Waiting for SD card unmount
  wait_for:
    path: '/media/ajaved/PIROOT'
    state: absent

- name: Mounting SD card
  shell: eject --trayclose /dev/sdb

- name: Waiting for SD card mount
  wait_for:
    path: '/media/ajaved/PIROOT'

- block:

  - name: Ansible facts directory
    file:
      path: /etc/ansible/facts.d
      state: directory

  - name: Gathering facts
    setup:

  vars:
    ansible_connection: chroot
    ansible_host: '/media/ajaved/PIROOT'

And the flash.yml playbook is:

- name: Flash OS
  hosts: kvms
  gather_facts: no
  roles:
  - role: flash

And we run the playbook with sudo.

I thought the chroot connection required a directory, for example:

all:
  children:
    chroots:
      hosts:
        /media/ajaved/PIROOT:

Here is the chroot directory:

ls -lah /media/ajaved/PIROOT
total 80K
drwxr-xr-x  17 root root 4.0K Apr 17 18:38 .
drwxr-x---+  6 root root 4.0K Apr 29 18:16 ..
lrwxrwxrwx   1 root root    7 Apr 17 18:38 bin -> usr/bin
drwxr-xr-x   2 root root 4.0K Apr 17 18:38 boot
drwxr-xr-x   2 root root 4.0K Mar  1  2023 dev
drwxr-xr-x  54 root root 4.0K Apr 17 18:38 etc
drwxr-xr-x   3 root root 4.0K Apr 17 18:36 home
lrwxrwxrwx   1 root root    7 Apr 17 18:38 lib -> usr/lib
drwx------   2 root root  16K Apr 17 18:38 lost+found
drwxr-xr-x   2 root root 4.0K Feb  5  2023 mnt
drwxr-xr-x   2 root root 4.0K Apr 17 18:25 opt
dr-xr-xr-x   2 root root 4.0K Mar  1  2023 proc
drwxr-x---   5 root root 4.0K Apr 17 18:36 root
drwxr-xr-x   2 root root 4.0K Mar  1  2023 run
lrwxrwxrwx   1 root root    7 Apr 17 18:38 sbin -> usr/bin
drwxr-xr-x   4 root root 4.0K Mar  1  2023 srv
dr-xr-xr-x   2 root root 4.0K Mar  1  2023 sys
drwxrwxrwt   2 root root 4.0K Apr 17 18:36 tmp
drwxr-xr-x   8 root root 4.0K Apr 17 18:36 usr
drwxr-xr-x  12 root root 4.0K Apr 17 18:25 var

And the user ajaved has administrator privileges.

My understanding of the chroot connection is that the inventory entry for the chroot is a directory path, your example doesn’t appear to provide this?

The chroot directory is mentioned as ansible_host in the Ansible role main.yml file above (see vars in the end of .yml file). We are first flashing with local connection and then chroot into the directory. It works fine with Ubuntu Focal.

1 Like

Sorry I don’t know the answer for this problem.

The most likely explanation would be some sort of race condition that you’re losing under Jammy, where the mount point /media/ajaved/PIROOT exists but is not yet usable. What happens if you change your wait_for task to check that the filesystem is actually available?

- name: Waiting for SD card mount
  wait_for:
    path: /media/ajaved/PIROOT/bin/sh
3 Likes

The error might be a bit misleading, sh itself might be saying ‘file not found’ as your shellism is not really translating as you think it is. Try:

shell:  xzcat {{ role_path }}/files/{{ image }} > /dev/sdb &&  sync &&  eject /dev/sdb
1 Like

Thanks for your reply @flowerysong

Changing path to /media/ajaved/PIROOT/bin/sh in wait_for tasks works fine and I don’t get the error anymore.

1 Like

Thanks @bcoca for your message.

What is the difference between my shell task and what you shared? You mean using && in between the commands?