Owl.System (Owl v0.13.0)
View SourceAn alternative to some System functions.
Summary
Functions
A wrapper around System.cmd/3 which additionally logs executed command, args and env.
Runs command as a daemon, executes operation and kills the daemon afterwards.
A wrapper around System.shell/2 which additionally logs executed command.
Functions
@spec cmd( binary(), [binary() | {:secret, binary()} | [binary() | {:secret, binary()}]], keyword() ) :: {Collectable.t(), exit_status :: non_neg_integer()}
A wrapper around System.cmd/3 which additionally logs executed command, args and env.
If URL is found in logged message, then password in it is masked with asterisks. Additionally, it is possible to explicitly mark env values and arguments as secret for safe logging. See examples for details.
Examples
> Owl.System.cmd("echo", ["test"])
# 10:25:34.252 [debug] $ echo test
{"test\n", 0}
# marking an argument as secret
> Owl.System.cmd("echo", ["hello", secret: "world"])
# 10:25:40.516 [debug] $ echo hello ********
{"hello world\n", 0}
# marking a part of an argument as secret
> Owl.System.cmd("echo", ["hello", ["--password=", {:secret, "world"}]])
# 10:25:40.516 [debug] $ echo hello --password=********
{"hello --password=world\n", 0}
# marking a env as secret
> Owl.System.cmd("echo", ["hello", "world"], env: [{"PASSWORD", {:secret, "mypassword"}}])
# 10:25:40.516 [debug] $ PASSWORD=******** sh -c "echo hello world"
{"hello world\n", 0}
> Owl.System.cmd("psql", ["postgresql://postgres:postgres@127.0.0.1:5432", "-tAc", "SELECT 1;"])
# 10:25:50.947 [debug] $ psql postgresql://postgres:********@127.0.0.1:5432 -tAc 'SELECT 1;'
{"1\n", 0}
@spec daemon_cmd( binary(), [binary() | {:secret, binary()} | [binary() | {:secret, binary()}]], (-> result), prefix: Owl.Data.t(), device: IO.device(), ready_check: (String.t() -> boolean()), env: [{binary(), binary() | {:secret, binary()} | nil}] ) :: result when result: any()
Runs command as a daemon, executes operation and kills the daemon afterwards.
Automatically puts messages from stderr and stdout to device prepending them with prefix.
Returns result of invoking operation.
Options
:prefix- a prefix forstderrandstdoutmessages from daemon. Defaults tocommandfollowed by colon.:device- device to which messages fromstderrandstdoutare put. Defaults to:stdio.:ready_check- a function which checks the content of the messages produced bycommandbefore writing todevice. If the function is set, then the execution of theoperationwill be blocked untilready_checkreturnstrue. By default this check is absent andoperationis invoked immediately without awaiting any message.:env- a list of tuples containing environment key-value. The behaviour is similar to the option described incmd/3
Example
ex> Owl.System.daemon_cmd("ping", ["8.8.8.8"], fn ->
..> Process.sleep(3_000)
..> 2 + 2
..> end)
# 00:36:33.963 [debug] $ ping 8.8.8.8
#
# 00:36:33.964 [debug] Started daemon ping with OS pid 576077
# ping: PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
# ping: 64 bytes from 8.8.8.8: icmp_seq=1 ttl=118 time=28.3 ms
# ping: 64 bytes from 8.8.8.8: icmp_seq=2 ttl=118 time=26.9 ms
# ping: 64 bytes from 8.8.8.8: icmp_seq=3 ttl=118 time=28.6 ms
# 00:36:36.965 [debug] $ kill 576077
4
ex> Owl.System.daemon_cmd(
..> "kubectl",
..> [
..> "port-forward",
..> "--namespace=my-app",
..> "--kubeconfig",
..> "~/.kube/myapp",
..> "my-pod",
..> "5432:5432"
..> ],
..> fn ->
..> Logger.debug("Dump DB")
..> end,
..> prefix: "kubectl(my-pod): ",
..> ready_check: &String.contains?(&1, "Forwarding from")
..> )
# 12:08:01.382 [debug] $ kubectl port-forward --namespace=my-app --kubeconfig ~/.kube/myapp my-pod 5432:5432
# 12:08:01.384 [debug] Started daemon kubectl with OS pid 166378
# kubectl(my-pod): Forwarding from 127.0.0.1:5432 -> 5432
# kubectl(my-pod): Forwarding from [::1]:5432 -> 5432
# 12:08:02.484 [debug] Dump DB
# 12:08:02.584 [debug] $ kill 166378
:ok
@spec shell( binary(), keyword() ) :: {Collectable.t(), exit_status :: non_neg_integer()}
A wrapper around System.shell/2 which additionally logs executed command.
Similarly to cmd/3, it automatically hides password in found URLs and allows manual hiding of env values.
Examples
> Owl.System.shell("echo hello world")
# 22:36:01.440 [debug] $ sh -c "echo hello world"
{"hello world\n", 0}
> Owl.System.shell("echo postgresql://postgres:postgres@127.0.0.1:5432")
# 22:36:51.797 [debug] $ sh -c "echo postgresql://postgres:********@127.0.0.1:5432"
{"postgresql://postgres:postgres@127.0.0.1:5432\n", 0}
> Owl.System.shell("echo $PASSWORD $USERNAME", env: [{"USERNAME", "john"}, {"PASSWORD", {:secret, "qwerty"}}])
# 12:38:27.704 [debug] $ USERNAME=john PASSWORD=******** sh -c "echo \$PASSWORD \$USERNAME"
{"qwerty john\n", 0}