Lack of orthogonality: cmd vs require_cmd
tmalaher-telus opened this issue · 2 comments
The cmd
configuration value is parsed using strings.Fields()
, and executed with: exec.Command(p.command[0], p.command[1:]...)
The require_cmd
configuration value is not parsed and is executed with exec.Command(shell, "-c", cfg.RequireCmd).Run()
This means that you cannot use a command in cmd
that does any sort of globbing, pipes, quoting, escaping or uses environment variables, and you cannot pass an argument to the command that contains whitespace.
I suppose the issue is that using "sh -c" creates an extra (shell) child process layer, which maybe you want to avoid.
So, for example, I could not run this:
cmd: curl -S -H"X-Custom:Value with spaces" http://example.com/RestService
In other similar tools I've done something like this:
cmd_exec: /bin/curl
cmd_args:
- -S
- -HX-Custom:Value with spaces
- http://example.com/RestService
This still does not allow for globbing, env var expansion or pipes.
Perhaps there should be an alternate way to specify a full "command line" where quoting, interpolation and globbing can work:
cmd_line: echo "Searching for new foo files";date;ls -l $HOME/subdir/*/foo*
Hey, fancy title 😎
cmd
is the app/binary/command you would like to demonize, but you still can use /bin/sh
for example:
immortal -l /tmp/sleep.log /bin/sh -c "sleep 5 && date"
Output of immortalctl
:
$ immortalctl
PID Up Down Name CMD
61721 3.2s 61717 /bin/sh -c sleep 5 && date
What is the error you get from your example? try:
cmd: curl -S -H"X-Custom:Value with spaces" http://example.com/RestService
log:
file: /tmp/test.log
or create a script:
#!/bin/sh
exec 2>&1
curl -S -H"X-Custom:Value with spaces" http://example.com/RestService
Then try:
cmd: /path/to/script
log:
file: /tmp/test.log
try testing running it like this: immortal -c /path/to/test.yml
require_cmd
is used as a condition to start or not your app based on the exit
status code, therefore here the use of sh -c
so that you could pipe, etc. (https://immortal.run/post/run.yml/)
now if you would not like to "daemonize" but to retry a command X number to times you could try something like:
cmd: rsync -aHAXxv --numeric-ids --delete -P <src> user@host:/<dest>
log:
file: /tmp/rsync.log
wait: 60
retries: 3
more info here: https://immortal.run/post/retries/
I don't know your use case, but if just need to trigger a command (not an application like a web server) maybe this work better:
nohup command arguments &
A supervisor is something that you usually is not used for triggering things only once
You've pointed out another non-orthogonality:
immortal ...options... command line
behaves differently from:
immortal -c command.yml
So your example: immortal -l /tmp/sleep.log /bin/sh -c "sleep 5 && date"
works fine.
But immortal -c command.yml
containing: cmd: sleep 5 && date
fails with:
sleep: invalid time interval ‘&&’
sleep: invalid time interval ‘date’
Try 'sleep --help' for more information.
Whereas cmd: sh -c "sleep 5 && date"
fails with:
5: -c: line 0: unexpected EOF while looking for matching `"'
5: -c: line 1: syntax error: unexpected end of file
This is because what is being passed to exec.Command is:
["sleep", "5" ,"&&", "date"]
or ["sh", "-c", "\"sleep", "5", "&&", "date\""]
And since no shell characters are being interpreted, the "sleep" or "sh" commands rightfully complain about the invalid arguments.
So what this comes down to is that with the YAML file option, you can only pass in simple command lines, or better yet, just write a script and call that.
And yes, I'm aware that using "immortal" for a one-shot is weird. I was just trying to create an example.