pyinfra icon indicating copy to clipboard operation
pyinfra copied to clipboard

hard to remove file-or-link

Open drewp opened this issue 3 years ago • 3 comments

1  files.file(path='/etc/resolv.conf', present=False)
2  files.link(path='/etc/resolv.conf', present=False)
3  files.template(src='templates/resolv.conf.j2', dest='/etc/resolv.conf', ns='10.2.0.1')

If I run 1,2,3 I get --> pyinfra error: /etc/resolv.conf exists and is not a file

If I run just 2,3 I get (on another host) --> pyinfra error: /etc/resolv.conf exists and is not a link

If I run just 3 I get no errors, but I'm left with some hosts having a symlink and some having a file.

I expected just 3 to work and replace symlinks with the templated file.

May be related to #791

Meta

System: Linux
  Platform: Linux-5.13.0-40-generic-x86_64-with-glibc2.34
  Release: 5.13.0-40-generic
  Machine: x86_64
pyinfra: v2.1
Executable: env/bin/pyinfra
Python: 3.9.9 (CPython, GCC 10.3.0)

drewp avatar May 07 '22 06:05 drewp

I thought this would be a workaround: server.shell(["[[ -L /etc/resolv.conf ]] && rm /etc/resolv.conf"])

--> Starting operation: Server/Shell (['[[ -L /etc/passwd ]] && rm /etc/resolv.conf'])
    [dash] sh: 1: [[: not found
    [dash] Error

drewp avatar May 07 '22 07:05 drewp

I think you want the force option. You should be able to only have one operation when using force. So you should be able to get away with doing:

from pyinfra.operations import files
files.file(path='/tmp/resolv.conf', present=False, force=True)

And this should work for both symlink and regular files.

The downside of doing this is the file is renamed, instead of fully being deleted.

sysadmin75 avatar May 07 '22 14:05 sysadmin75

I think this is correct - by default the files.[link|directory|file] operations will raise these errors if the path exists and doesn't match the desired type. The force=True argument can be used to rename before creating the expected path. There is also a force_backup (default True) that can be set to False to remove the path without backup.

The files.template operation does not check anything about the target path which is why it'll work whether the path is a link or a file. I think this makes sense so a template could be written to a link directly?

So I'm not sure there's a bug to fix except maybe the error messages need improvement, something like:

--> pyinfra error: path /etc/resolv.conf already exists as a , use force=True to move the and create the (<include call location here)

Fizzadar avatar May 28 '22 17:05 Fizzadar