@@ -120,8 +120,35 @@ defmodule Hemdal.Host do
120120 """
121121 @ spec exec ( host_id ( ) , Hemdal.Config.Alert.Command . t ( ) , command_args ( ) ) ::
122122 { :ok , map ( ) } | { :error , map ( ) }
123- def exec ( host_id , cmd , args ) do
124- GenServer . call ( via ( host_id ) , { :exec , cmd , args } , @ timeout_exec )
123+ @ spec exec ( host_id ( ) , Hemdal.Config.Alert.Command . t ( ) , command_args ( ) , timeout ( ) ) ::
124+ { :ok , map ( ) } | { :error , map ( ) }
125+ def exec ( host_id , cmd , args \\ [ ] , timeout \\ @ timeout_exec )
126+
127+ def exec ( host_id , % Command { type: "line" } = cmd , _args , timeout ) do
128+ GenServer . call ( via ( host_id ) , { :exec , cmd , [ ] } , timeout )
129+ end
130+
131+ def exec ( host_id , % Command { type: "script" } = cmd , args , timeout ) do
132+ GenServer . call ( via ( host_id ) , { :exec , cmd , args } , timeout )
133+ end
134+
135+ def exec ( host_id , % Command { type: "interactive" } = cmd , [ pid ] , timeout ) do
136+ GenServer . call ( via ( host_id ) , { :exec , cmd , [ pid ] } , timeout )
137+ end
138+
139+ @ doc """
140+ Run or execute the command passed as parameter. It's needed to pass the host ID
141+ to find the process where to send the request, and the the command and the
142+ arguments to run the command.
143+
144+ It's returning a tuple for `:ok` or `:error`. The `:ok` tuple have a PID to know
145+ which process is in charge of running the background process and to know if it's
146+ still running or not.
147+ """
148+ @ spec exec_background ( host_id ( ) , Hemdal.Config.Alert.Command . t ( ) , command_args ( ) ) ::
149+ { :ok , pid ( ) } | { :error , any ( ) }
150+ def exec_background ( host_id , cmd , args \\ [ ] ) do
151+ GenServer . call ( via ( host_id ) , { :exec_background , self ( ) , cmd , args } , @ timeout_exec )
125152 end
126153
127154 @ doc """
@@ -221,12 +248,49 @@ defmodule Hemdal.Host do
221248
222249 @ impl GenServer
223250 @ doc false
251+ def handle_call ( { :exec_background , pid , cmd , args } , _from , % __MODULE__ { max_workers: :infinity } = state ) do
252+ Logger . debug (
253+ "host => workers: #{ state . workers } /infinity ; queue length: #{ Queue . len ( state . queue ) } "
254+ )
255+
256+ send_result = & send ( pid , & 1 )
257+ ref = spawn_monitor ( fn -> run_in_background ( cmd , args , send_result , state ) end )
258+ { :reply , { :ok , ref } , % __MODULE__ { state | workers: state . workers + 1 } }
259+ end
260+
261+ def handle_call (
262+ { :exec_background , pid , cmd , args } ,
263+ from ,
264+ % __MODULE__ { max_workers: max_workers , workers: workers , queue: queue } = state
265+ )
266+ when workers >= max_workers do
267+ Logger . debug (
268+ "host => workers: #{ workers } /#{ max_workers } ; queue length: #{ Queue . len ( queue ) + 1 } "
269+ )
270+
271+ queue = Queue . in ( { { :exec_background , pid , cmd , args } , from } , queue )
272+ { :noreply , % __MODULE__ { state | queue: queue } }
273+ end
274+
275+ def handle_call ( { :exec_background , pid , cmd , args } , _from , state ) do
276+ send_result = & send ( pid , & 1 )
277+ ref = spawn_monitor ( fn -> run_in_background ( cmd , args , send_result , state ) end )
278+ workers = state . workers + 1
279+
280+ Logger . debug (
281+ "host => workers: #{ workers } /#{ state . max_workers } ; queue length: #{ Queue . len ( state . queue ) } "
282+ )
283+
284+ { :reply , { :ok , ref } , % __MODULE__ { state | workers: workers } }
285+ end
286+
224287 def handle_call ( { :exec , cmd , args } , from , % __MODULE__ { max_workers: :infinity } = state ) do
225288 Logger . debug (
226289 "host => workers: #{ state . workers } /infinity ; queue length: #{ Queue . len ( state . queue ) } "
227290 )
228291
229- spawn_monitor ( fn -> run_in_background ( cmd , args , from , state ) end )
292+ send_result = & GenServer . reply ( from , & 1 )
293+ spawn_monitor ( fn -> run_in_background ( cmd , args , send_result , state ) end )
230294 { :noreply , % __MODULE__ { state | workers: state . workers + 1 } }
231295 end
232296
@@ -240,11 +304,13 @@ defmodule Hemdal.Host do
240304 "host => workers: #{ workers } /#{ max_workers } ; queue length: #{ Queue . len ( queue ) + 1 } "
241305 )
242306
243- { :noreply , % __MODULE__ { state | queue: Queue . in ( { from , cmd , args } , queue ) } }
307+ queue = Queue . in ( { { :exec , cmd , args } , from } , queue )
308+ { :noreply , % __MODULE__ { state | queue: queue } }
244309 end
245310
246311 def handle_call ( { :exec , cmd , args } , from , state ) do
247- spawn_monitor ( fn -> run_in_background ( cmd , args , from , state ) end )
312+ send_result = & GenServer . reply ( from , & 1 )
313+ spawn_monitor ( fn -> run_in_background ( cmd , args , send_result , state ) end )
248314 workers = state . workers + 1
249315
250316 Logger . debug (
@@ -259,13 +325,13 @@ defmodule Hemdal.Host do
259325 def handle_cast ( { :update , host } , state ) do
260326 case { host . max_workers , state . host . max_workers } do
261327 { max_workers , max_workers } ->
262- { :noreply , % __MODULE__ { host: host } }
328+ { :noreply , % __MODULE__ { state | host: host } }
263329
264330 { :infinity , _ } ->
265- { :noreply , % __MODULE__ { host: host , max_workers: :infinity } }
331+ { :noreply , % __MODULE__ { state | host: host , max_workers: :infinity } }
266332
267333 { new_max_workers , old_max_workers } when new_max_workers < old_max_workers ->
268- { :noreply , % __MODULE__ { host: host , max_workers: new_max_workers } }
334+ { :noreply , % __MODULE__ { state | host: host , max_workers: new_max_workers } }
269335
270336 { new_max_workers , _old_max_workers } ->
271337 state =
@@ -284,8 +350,8 @@ defmodule Hemdal.Host do
284350 do: state
285351
286352 defp launch_extra ( state , false ) do
287- { { :value , { from , cmd , args } } , queue } = Queue . out ( state . queue )
288- { :noreply , state } = handle_call ( { :exec , cmd , args } , from , % __MODULE__ { state | queue: queue } )
353+ { { :value , { info , from } } , queue } = Queue . out ( state . queue )
354+ { :noreply , state } = handle_call ( info , from , % __MODULE__ { state | queue: queue } )
289355 launch_extra ( state , Queue . is_empty ( state . queue ) )
290356 end
291357
@@ -298,9 +364,10 @@ defmodule Hemdal.Host do
298364 Logger . debug ( "host => workers: #{ workers } /#{ state . max_workers } ; queue length: 0" )
299365 { :noreply , % __MODULE__ { state | workers: workers } }
300366
301- { { :value , { from , cmd , args } } , queue } ->
367+ { { :value , { { :exec , cmd , args } , from } } , queue } ->
302368 state = % __MODULE__ { state | queue: queue }
303- spawn_monitor ( fn -> run_in_background ( cmd , args , from , state ) end )
369+ send_result = & GenServer . reply ( from , & 1 )
370+ spawn_monitor ( fn -> run_in_background ( cmd , args , send_result , state ) end )
304371
305372 Logger . debug (
306373 "host => workers: #{ state . workers } /#{ state . max_workers } ; queue length: #{ Queue . len ( queue ) } "
@@ -338,19 +405,20 @@ defmodule Hemdal.Host do
338405 { :error , % { "message" => other , "status" => "FAIL" } }
339406 end
340407
341- defp run_in_background ( cmd , args , from , % __MODULE__ { host: % _ { module: mod } = host } ) do
342- result =
343- mod . transaction ( host , fn handler ->
344- with { :ok , errorlevel , output } <- exec_cmd ( handler , mod , cmd , args ) ,
345- { :ok , % { "status" => status } = data } <- decode ( output ) do
346- Logger . debug ( "command exit(#{ errorlevel } ) output: #{ inspect ( data ) } " )
347- run_result ( data , errorlevel , status )
348- else
349- other -> other
350- end
351- end )
408+ defp run_in_background ( cmd , args , send_result , % __MODULE__ { host: % _ { module: mod } = host } ) do
409+ mod . transaction ( host , fn handler ->
410+ with { :ok , errorlevel , output } <- exec_cmd ( handler , mod , cmd , args ) ,
411+ { :ok , % { "status" => status } = data } <- decode ( output ) do
412+ Logger . debug ( "command exit(#{ errorlevel } ) output: #{ inspect ( data ) } " )
413+ run_result ( data , errorlevel , status )
414+ else
415+ other -> other
416+ end
417+ end )
418+ |> final_run_result ( )
419+ |> send_result . ( )
352420
353- :ok = GenServer . reply ( from , final_run_result ( result ) )
421+ :ok
354422 end
355423
356424 defp decode ( output ) do
0 commit comments