Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

file module always fails to create relative symlinks if force is not yes. #21401

Closed
simonmikkelsen opened this issue Feb 14, 2017 · 2 comments · Fixed by #39100
Closed

file module always fails to create relative symlinks if force is not yes. #21401

simonmikkelsen opened this issue Feb 14, 2017 · 2 comments · Fixed by #39100
Labels
affects_2.2 This issue/PR affects Ansible v2.2 bug This issue/PR relates to a bug. module This issue/PR relates to a module. support:core This issue/PR relates to code supported by the Ansible Engineering Team.

Comments

@simonmikkelsen
Copy link

ISSUE TYPE
  • Bug Report
COMPONENT NAME

module/file
devel/lib/ansible/modules/files/file.py

ANSIBLE VERSION
ansible --version
ansible 2.2.1.0
  config file = /home/vagrant/ansible/ansible.cfg
  configured module search path = Default w/o overrides
CONFIGURATION

No changes made.

OS / ENVIRONMENT

cat /etc/centos-release
CentOS Linux release 7.3.1611 (Core)

SUMMARY

The file module cannot create symlinks: src and destination paths are concatinated and the result is used to check if the src exists.

STEPS TO REPRODUCE

Run the task below. The src is a directory that exists. In the dest only dias-installer-4.5.0/installer_repository/ exists.

  tasks:
    - name: Create a symlink to the .git folder
      file:
        src: "dias-installer-4.5.0/release_repository.git"
        dest: "dias-installer-4.5.0/installer_repository/.git"
        state: link
EXPECTED RESULTS

A symlink to be created.

ACTUAL RESULTS

The output hints about the issue:

fatal: [sseudia23mgt01]: FAILED! => {"changed": false, "failed": true, "msg": "src file does not exist, use \"force=yes\" if you really want to create the link: dias-installer-4.5.0/installer_repository/dias-installer-4.5.0/release_repository.git", "path": "dias-installer-4.5.0/installer_repository/.git", "src": "dias-installer-4.5.0/release_repository.git", "state": "absent"}

Note that I am asked if I want to create the link dias-installer-4.5.0/installer_repository/dias-installer-4.5.0/release_repository.git which is a path created by concatinating the dest and src path, essentially: dest/src. I would not expect such a file to exist and I can only see the path is not created correctly. Perhaps the dest part was intended to be the first part of an absolute path?

When I look into https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/files/file.py
I find the following code:

absrc = os.path.join(relpath, src)
        b_absrc = to_bytes(absrc, errors='surrogate_or_strict')
        if not force and not os.path.exists(b_absrc):
            module.fail_json(path=path, src=src, msg='src file does not exist, use "force=yes" if you really want to create the link: %s' % absrc)

In the first line, relpath, which originates as the dest or path argument, is joined with the src path. Exactly as I see in the output. In the last part of the code, the code fails if force is not set to yes.

@ansibot ansibot added affects_2.2 This issue/PR affects Ansible v2.2 bug_report module This issue/PR relates to a module. needs_triage Needs a first human triage before being processed. labels Feb 14, 2017
@ryansb ryansb removed the needs_triage Needs a first human triage before being processed. label Feb 14, 2017
grimmjow8 added a commit to grimmjow8/ansible that referenced this issue Feb 19, 2017
    During src path validation before link creation, dest joined with src.
    Nonsense path checked for existence. For absolute paths, os.path.join returned
    second parameter ie abs src path.

    Fix: Replaced os.path.join with os.path.abspath
    Testing: Existing integration testing sufficent, though some tests were successfully
          linking non-existing files without the force flag.
grimmjow8 added a commit to grimmjow8/ansible that referenced this issue Feb 19, 2017
    During src path validation before link creation, dest joined with src.
    Nonsense path checked for existence. For absolute paths, os.path.join returned
    second parameter ie abs src path.

    Fix: Replaced os.path.join with os.path.abspath
    Testing: Existing integration testing sufficent, though some tests were successfully
          linking non-existing files without the force flag.
grimmjow8 added a commit to grimmjow8/ansible that referenced this issue Feb 19, 2017
grimmjow8 added a commit to grimmjow8/ansible that referenced this issue Feb 19, 2017
grimmjow8 added a commit to grimmjow8/ansible that referenced this issue Feb 24, 2017
    During src path validation before link creation, dest joined with src.
    Nonsense path checked for existence. For absolute paths, os.path.join returned
    second parameter ie abs src path.

    Fix: Replaced os.path.join with os.path.abspath
    Testing: Existing integration testing sufficent, though some tests were successfully
          linking non-existing files without the force flag.
grimmjow8 added a commit to grimmjow8/ansible that referenced this issue Feb 24, 2017
    During src path validation before link creation, dest joined with src.
    Nonsense path checked for existence. For absolute paths, os.path.join returned
    second parameter ie abs src path.

    Fix: Replaced os.path.join with os.path.abspath
    Testing: Existing integration testing sufficent, though some tests were successfully
          linking non-existing files without the force flag.
grimmjow8 added a commit to grimmjow8/ansible that referenced this issue Feb 24, 2017
Failed to commit fixes for tests that were linking non-existing dirs without force=yes
@ansibot ansibot added the support:core This issue/PR relates to code supported by the Ansible Engineering Team. label Jun 29, 2017
@ansibot
Copy link
Contributor

ansibot commented Nov 21, 2017

Files identified in the description:

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

click here for bot help

@ansibot ansibot added bug This issue/PR relates to a bug. and removed bug_report labels Mar 1, 2018
@abadger abadger changed the title file module always fails to create symlinks if force is not yes. file module always fails to create relative symlinks if force is not yes. Apr 20, 2018
@abadger
Copy link
Contributor

abadger commented Apr 20, 2018

Apologies for taking a long time to look into this. I have been able to look at it in the past few days, though, and I think this is working as expected. I'll summarize first and then give a longer explanation afterwards:

I believe for your case, you have a directory tree like:

dias-installer-4.5.0
├── installer_repository
├── installer_repository/.git   => release_repository.git
└── release_repository.git

And you want to create a link so that the tree looks like this:

dias-installer-4.5.0
├── installer_repository
├── installer_repository/.git   => release_repository.git
└── release_repository.git

To achieve that you should use a playbook like the following:

      file:
        src: "../release_repository.git"
        dest: "dias-installer-4.5.0/installer_repository/.git"
        state: link

The reason for this is that ansible -m file -a 'src=SRC dest=DEST is supposed to work a lot like the UNIX command ln -s SRC DEST. When you use that with a relative path in SRC, the path is relative to the DEST path, not to the current working directory. You can test that out by doing somethng like:

[pts/40@peru ~]$ cd /home
[pts/40@peru /home]$ ln -s ../home /var/tmp/home
[pts/40@peru /home]$ ls -al /var/tmp/home
lrwxrwxrwx. 1 badger badger 7 Apr 20 12:07 /var/tmp/home -> ../home

If you look at the ls -al output closely, you can see that it is a link to /var/home (since it is relative to the destination) rather than /home (as it would if it was relative to the current working directory).

The documentation for the file module attempts to say this by saying that relative paths are not expanded:

  • src
    path of the file to link to (applies only to state=link' and state=hard'). Will accept absolute, relative and nonexisting paths. Relative paths are not expanded.

but I think that it would be clearer if I mention that it works the same way as ln -s when presented with relative paths. I'll go ahead and submit a PR to add that to the documentation.

abadger added a commit to abadger/ansible that referenced this issue Apr 20, 2018
Fixes ansible#21401

Also sdd some more tests to validate file state=link creates a symlink
which points to the file we intended.
abadger added a commit that referenced this issue Apr 20, 2018
Fixes #21401

Also sdd some more tests to validate file state=link creates a symlink
which points to the file we intended.
oolongbrothers pushed a commit to oolongbrothers/ansible that referenced this issue May 14, 2018
Fixes ansible#21401

Also sdd some more tests to validate file state=link creates a symlink
which points to the file we intended.
oolongbrothers pushed a commit to oolongbrothers/ansible that referenced this issue May 15, 2018
Fixes ansible#21401

Also sdd some more tests to validate file state=link creates a symlink
which points to the file we intended.
ilicmilan pushed a commit to ilicmilan/ansible that referenced this issue Nov 7, 2018
Fixes ansible#21401

Also sdd some more tests to validate file state=link creates a symlink
which points to the file we intended.
@ansible ansible locked and limited conversation to collaborators Apr 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.2 This issue/PR affects Ansible v2.2 bug This issue/PR relates to a bug. module This issue/PR relates to a module. support:core This issue/PR relates to code supported by the Ansible Engineering Team.
Projects
None yet
4 participants