community.general icon indicating copy to clipboard operation
community.general copied to clipboard

filetree lookup plugin resolves relative paths relative to cwd

Open btmc opened this issue 8 months ago • 4 comments

Summary

When there is a file or directory, matching lookup search criteria, in files subdir of current working directory, it is returned by the lookup.

This means playbook execution results depend on cwd. Although not described in the docs explicitely, I believe that is not an expected behaviour.

The reason seems to be in the path_dwim_relative function of ansible dataloader. One of search options added there is mentioned as being "absolute" in the comment line, but in fact is defined this way:

# try to create absolute path for loader basedir + templates/files/vars + filename
 search.append(unfrackpath(os.path.join(dirname, source), follow=False))

dirname here being 'files', from filetree invocation.

And unfrackpath, when it does not receive a basedir parameter, renders relative path relative to cwd.

I'm not sure whether this should be reported directly to ansible repo, because the function path_dwim_relative, although used in several places, does not have regressions there (and reproducible use-cases).

There also exists its counterpart with multi-path search: path_dwim_relative_stack, which resolves such paths correctly, and that one is used in find_file_in_search_path function in lookup plugins init code, so maybe it should also be used here instead?

Issue Type

Bug Report

Component Name

community.general.filetree

Ansible Version

ansible [core 2.18.3]
  python version = 3.13.2 (main, Feb 14 2025, 19:28:41) [GCC 14.2.0] (/usr/local/bin/python3.13)
  jinja version = 3.1.5
  libyaml = True

Community.general Version

10.4.0

Configuration

No response

OS / Environment

cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.21.3
PRETTY_NAME="Alpine Linux v3.21"

Steps to Reproduce

cd /tmp

mkdir -p /tmp/dir1
mkdir -p /tmp/files/dir2

touch /tmp/files/dir2/file

<<\Q cat > /tmp/dir1/test.yml
- hosts: localhost
  gather_facts: no
  tasks:
  - debug:
      msg:
        src: "{{ item.src }}"
        root: "{{ item.root }}"
    with_community.general.filetree: [ dir2 ]
Q

# file from files dir, relative to cwd, is returned
#
ansible-playbook /tmp/dir1/test.yml

TASK [debug] **********
...
        root: /tmp/files/dir2
        src: /tmp/files/dir2/file


cd /tmp/dir1

# no file returned
#
ansible-playbook /tmp/dir1/test.yml

skipping: [localhost]


mkdir -p /tmp/dir1/dir2
touch /tmp/dir1/dir2/file

# file relative to playbook is returned
#
ansible-playbook /tmp/dir1/test.yml

        root: /tmp/dir1/dir2
        src: /tmp/dir1/dir2/file


cd /tmp

# file from files dir, relative to cwd, is returned again and overshadows the one,
# that is relative to the playbook, as it goes first in path_dwim_relative search order
#
ansible-playbook /tmp/dir1/test.yml

        root: /tmp/files/dir2
        src: /tmp/files/dir2/file

Expected Results

Only files and directories relative to playbook (or roles) are searched, the result is stable and does not depend on cwd.

Actual Results

No response

Code of Conduct

  • [x] I agree to follow the Ansible Code of Conduct

btmc avatar Mar 18 '25 12:03 btmc

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot avatar Mar 18 '25 12:03 ansibullbot

cc @dagwieers click here for bot help

ansibullbot avatar Mar 18 '25 12:03 ansibullbot

Hi @btmc

I have not used this before, but I would argue exactly the contrary: the execution of the code should not be tied to the placement of the code. Let's, generically, call the files you are searching for your actual playbook "data", and your playbook "code". In your proposition, we MUST always save data under the directory structure for code. That is not a good practice, IMHO. Code and data should not be tightly coupled like that.

russoz avatar May 25 '25 09:05 russoz

Also note that the plugin has been behaving this way for a long time (since Ansible 2.2, in 2016: https://github.com/ansible/ansible/pull/14332#issuecomment-218633723), so even if this has been a bug back then, it's standard behavior now and no longer a bug. Making it configurable is OK, but "fixing" it will simply break potentially many users who adjusted to the behavior.

felixfontein avatar May 28 '25 18:05 felixfontein