hard to remove file-or-link
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)
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
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.
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=Trueto move theand create the (<include call location here)