pyinfra
pyinfra copied to clipboard
Add attribute to ssh.command, that tells that return code of the command means 'no change'
In the "ssh.command", there may be situations when I can check, whether the system is already in the desired state or not.
- If the system is in the desired state, I won't perform any action, only inform the caller (i.e. pyload in this case) that I did nothing.
- In the other case, I can apply desired changes and return normal status code (zero for the success, non-zero for an error).
In case of 1., I can return special return code and simultaneously I can inform pyload, that this code means "no change".
Let we have (for example) such SSH command:
snap list helm || ( snap install helm && exit 0 ) && exit 200
This command returns status 200 if there is no change (i.e. helm is already installed) and normal status - i.e. 0 if helm was installed or non - zero except 200 (I must guarantee that there is no other 200 than my check) in case of error.
It would be perfect to be able to instruct pyload, that the status 200 means "no change". It could be done by additional attribute of the "ssh.command" command , it can be named for example "no_change_status", so in such case the "ssh.command" can look like this:
ssh.command( name="Install heml via snap", command="snap list helm || ( snap install helm && exit 0 ) && exit 200", no_change_status=200 )
For your particular example, you can write a custom Fact that checks whether a snap package is installed and only run snap install
if needed.
Thank you to pointing out, but - according to my knowledge - the result will not be the same. By my proposed solution, in the result list will be seen that there is some desired state but the opertion made no change (i.e. the system is already in the required state), in your proposal there will not to be a trace about the operation in such case. Am I correct? Btw for my particular examle, the best solution would be to implement "snap" operation :) I looked how the operations are programmed, but my Python knowledge are too few and I don't feel like to be able to do i well. So I will fill new request, so I will make new feature request.
You are right, if the control flow is a part of the top-level file, the skipped operations won't show up. You can however wrap it in a simple operation just calling other operations.
the general idea is
import pyinfra
class SnapPackageInstalled(pyinfra.api.FactBase):
pass # TODO check whether a package is installed
@pyinfra.api.operation
def install_snap_package(name):
exists = pyinfra.host.get_fact(SnapPackageInstalled, name)
if not exists:
yield from pyinfra.operations.server.shell(f"snap install {name}") #TODO escape better
install_snap_package("helm")