Skip to content

Commit a962bed

Browse files
committed
1.0.4 - interactive commands
1 parent 29866d5 commit a962bed

File tree

7 files changed

+102
-9
lines changed

7 files changed

+102
-9
lines changed

config/config.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Config
2+
3+
if config_env() == :dev do
4+
config :hemdal, :config_module, Hemdal.Config.Backend.Env
5+
6+
config :hemdal, Hemdal.Config, []
7+
end

lib/hemdal/config/alert.ex

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ defmodule Hemdal.Config.Alert do
4444
each alert. The data used is:
4545
4646
- `name` the name of the script.
47-
- `type` the type of the script could be `line` or `script`. The first
48-
one let us define a command in a single line and the last one let us
49-
define a script, a multi-line code which will be copied and executed
50-
in the host.
47+
- `type` the type of the script could be `line`, `script` or
48+
`interactive`. The first one let us define a command in a single line,
49+
the last one let us define a script, a multi-line code which will be
50+
copied and executed in the host, and the last one let us run a command
51+
interacting with a process for providing information in runtime.
5152
- `command` as the command line to be executed. It could be only one line
5253
or a multi-line script.
5354
"""

lib/hemdal/event/log.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ defmodule Hemdal.Event.Log do
5757
end
5858

5959
defp get_message(event, :ok, :ok) do
60-
"sucessful run #{event.alert.name} on #{event.alert.host.name}"
60+
"successful run #{event.alert.name} on #{event.alert.host.name}"
6161
end
6262

6363
defp get_message(event, :ok, :warn) do
64-
"sucessful again run #{event.alert.name} on #{event.alert.host.name} after #{event.fail_duration || "unknown"} sec"
64+
"successful again run #{event.alert.name} on #{event.alert.host.name} after #{event.fail_duration || "unknown"} sec"
6565
end
6666

6767
defp get_message(event, :ok, :error) do

lib/hemdal/host.ex

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,10 @@ defmodule Hemdal.Host do
398398
end
399399
end
400400

401+
defp exec_cmd(handler, mod, %Command{type: "interactive", command: command}, [pid]) do
402+
mod.exec_interactive(handler, command, pid)
403+
end
404+
401405
@typedoc """
402406
Handler is used by the backend implementation of the host, it could be
403407
whatever depending on the needs of the backend implementation. For
@@ -452,11 +456,19 @@ defmodule Hemdal.Host do
452456

453457
@doc """
454458
Exec a command using the method implemented by the module where it's
455-
implemented. The `exec/2` command is getting a handler from the transaction
459+
implemented. The `c:exec/2` command is getting a handler from the transaction
456460
and the command to be executed as a string.
457461
"""
458462
@callback exec(handler(), command()) :: {:ok, errorlevel(), output()} | {:error, reason()}
459463

464+
@doc """
465+
Exec an interactive command implemented by the module where it's
466+
implemented. The `c:exec_interactive/3` command is getting a handler from the
467+
transaction and the command to be executed as a string.
468+
"""
469+
@callback exec_interactive(handler(), command(), pid()) ::
470+
{:ok, errorlevel(), output()} | {:error, reason()}
471+
460472
@doc """
461473
Write a file in the remote (or local) host. It's intended to write the
462474
scripts which will be needed to be executed after that with `exec/2`.
@@ -466,7 +478,7 @@ defmodule Hemdal.Host do
466478

467479
@doc """
468480
Remove a file which was created with `write_file/3` when the execution of
469-
the script was finalised.
481+
the script was finalized.
470482
"""
471483
@callback delete(handler(), tpm_file :: charlist()) :: :ok | {:error, reason()}
472484

lib/hemdal/host/local.ex

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,38 @@ defmodule Hemdal.Host.Local do
1717
{:ok, errorlevel, output}
1818
end
1919

20+
@impl Hemdal.Host
21+
def exec_interactive(_opts, command, pid) do
22+
port = Port.open({:spawn, command}, [:binary])
23+
send(pid, {:start, self()})
24+
get_and_send_all(port, pid, "")
25+
end
26+
27+
defp get_and_send_all(port, pid, output) do
28+
receive do
29+
{:data, data} ->
30+
send(port, {self(), {:command, data}})
31+
get_and_send_all(port, pid, output)
32+
33+
:close ->
34+
send(port, {self(), :close})
35+
get_and_send_all(port, pid, output)
36+
37+
{^port, {:data, data}} ->
38+
send(pid, {:continue, data})
39+
get_and_send_all(port, pid, output <> data)
40+
41+
{^port, :closed} ->
42+
send(pid, :closed)
43+
{:ok, 0, output}
44+
after
45+
60_000 ->
46+
Port.close(port)
47+
send(pid, :closed)
48+
{:ok, 127, output}
49+
end
50+
end
51+
2052
@impl Hemdal.Host
2153
@doc """
2254
Write a file locally, the file is intended to be located in a temporal

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Hemdal.MixProject do
22
use Mix.Project
33

4-
@version "1.0.3"
4+
@version "1.0.4"
55

66
def project do
77
[

test/hemdal/host_test.exs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,45 @@ defmodule Hemdal.HostTest do
9595
78eb75f9-2ac7-434c-a1a2-330b23c89982
9696
] == Hemdal.Host.get_all()
9797
end
98+
99+
test "run shell command" do
100+
assert :ok = Hemdal.Host.reload_all()
101+
assert [host_id, _] = Hemdal.Host.get_all()
102+
103+
echo = %Hemdal.Config.Alert.Command{
104+
name: "hello world!",
105+
type: "line",
106+
command: ~s|echo '{"status": "OK", "message": "hello world!"}'|
107+
}
108+
109+
assert {:ok, %{"message" => "hello world!"}} = Hemdal.Host.exec(host_id, echo, [])
110+
end
111+
112+
test "run interactive shell command" do
113+
assert :ok = Hemdal.Host.reload_all()
114+
assert [host_id, _] = Hemdal.Host.get_all()
115+
116+
echo = %Hemdal.Config.Alert.Command{
117+
name: "hello world!",
118+
type: "interactive",
119+
command: "cat"
120+
}
121+
122+
pid =
123+
spawn_link(fn ->
124+
pid =
125+
receive do
126+
{:start, pid} -> pid
127+
end
128+
129+
send(pid, {:data, ~s|{"status": "OK",\n|})
130+
assert_receive {:continue, ~s|{"status": "OK",\n|}
131+
send(pid, {:data, ~s| "message": "hello world!"}\n|})
132+
assert_receive {:continue, ~s| "message": "hello world!"}\n|}
133+
send(pid, :close)
134+
assert_receive :closed
135+
end)
136+
137+
assert {:ok, %{"message" => "hello world!"}} = Hemdal.Host.exec(host_id, echo, [pid])
138+
end
98139
end

0 commit comments

Comments
 (0)