diff --git a/tezt/lib_cloud/agent.ml b/tezt/lib_cloud/agent.ml index 83af4122bf62a104d20e0866cb7e9e1b57c38cfe..c0d6c893781457ec5592b8030052972ce3fced1d 100644 --- a/tezt/lib_cloud/agent.ml +++ b/tezt/lib_cloud/agent.ml @@ -134,10 +134,33 @@ let host_run_command agent cmd args = | Some cmd_wrapper -> Process.spawn cmd_wrapper.Gcloud.cmd (cmd_wrapper.args @ [cmd] @ args) -let docker_run_command agent cmd args = +let docker_run_command agent ?(detach = false) cmd args = + (* This function allows to run a command and detach it from the terminal + session and parent process. This allows to run a command in background + without the session (and processes group) being killed by ssh on + disconnection. It uses the [setsid -f] to detach the session. + Automatically log stdout and stderr of the command in tezt temporary dir *) + let run_detached ?runner cmd args = + let whole_cmd = String.concat " " (cmd :: args) in + let cmd = "sh" in + let args = + "-c" + :: [ + "setsid -f " ^ whole_cmd ^ " > " + ^ Temp.file ?runner (cmd ^ ".log") + ^ " 2>&1"; + ] + in + (cmd, args) + in match agent.runner with - | None -> Process.spawn cmd args + | None -> + let cmd, args = if detach then run_detached cmd args else (cmd, args) in + Process.spawn cmd args | Some runner -> + let cmd, args = + if detach then run_detached ~runner cmd args else (cmd, args) + in let cmd, args = Runner.wrap_with_ssh runner (Runner.Shell.cmd [] cmd args) in diff --git a/tezt/lib_cloud/agent.mli b/tezt/lib_cloud/agent.mli index 48a917c3d4190e41b403fd1c10c39c007f2ba7e6..e4ab61ddd33518f9c066cab65e5c5cedcc406743 100644 --- a/tezt/lib_cloud/agent.mli +++ b/tezt/lib_cloud/agent.mli @@ -12,7 +12,7 @@ type t (** [make ?zone ?ssh_id ?point ~configuration ~next_available_port ~name ()] creates an [agent] from the given parameters. [~next_available_port] should - always provide an available port or raise [Not_found] otherwise. + always provide an available port or raise [Not_found] otherwise. [~name] is the name of the agent. [?ssh_id] and [?point] are used to potentially create a [runner] for the [agent]. *) val make : @@ -60,10 +60,15 @@ val host_run_command : t -> string -> string list -> Process.t The library uses it to ensure there won't be any check of the host when issuing for the first time an ssh connection. + + [detach] Allows the command to be run in background and detaching from the + owning terminal and parent process. In this case, a temporary file is + automatically created in /tmp/tezt-$n with the name of the command as + prefix (warning: it can causes duplicates). *) -val docker_run_command : t -> string -> string list -> Process.t +val docker_run_command : t -> ?detach:bool -> string -> string list -> Process.t -(** [copy ?refresh ?is_directory ?destination agent ~source] copies the file +(** [copy ?refresh ?is_directory ?destination agent ~source] copies the file into the [agent] directory and returns the directory where the file can be found if [?refresh] is set to [true]. It is assumed the [~source] file does not exist on the agent machine. If the parent directory does diff --git a/tezt/tests/cloud/basic.ml b/tezt/tests/cloud/basic.ml index 9b8325df3eb401b28b3f611b31f0936c6b1bfb0c..e9ef1d7c96f0c2c7151d12f18551af7c62ef255b 100644 --- a/tezt/tests/cloud/basic.ml +++ b/tezt/tests/cloud/basic.ml @@ -59,6 +59,26 @@ let run_vm () = (String.concat " " cmd) ; unit +let run_detached () = + Cloud.register + ~vms:[Configuration.make ()] + ~__FILE__ + ~tags:["run"; "detach"; Tag.cloud] + ~title:"Run a command and detach in a vm" + @@ fun t -> + let agents = Cloud.agents t in + let agent = List.nth agents 0 in + Log.info "Run a command and detach. You should not wait" ; + let* _ = + Agent.docker_run_command ~detach:true agent "sleep" ["10"] |> Process.wait + in + Log.info "OK" ; + Log.info "Run a command without detaching. You should wait 10sec" ; + let* _ = Agent.docker_run_command agent "sleep" ["10"] |> Process.wait in + Log.info "OK" ; + unit + let register () = simple () ; - run_vm () + run_vm () ; + run_detached ()