diff --git a/tezt/lib_cloud/deployement.ml b/tezt/lib_cloud/deployement.ml index 38484aee89fc6bca531edc22478694104d58d200..393d008758d3e2c0f3ef592552ba84ca83585154 100644 --- a/tezt/lib_cloud/deployement.ml +++ b/tezt/lib_cloud/deployement.ml @@ -296,6 +296,154 @@ module Remote = struct Lwt.return_unit) end +(* Deployment on a SSH reachable host. At this moment, it is expected to be a + debian bookworm, and apt must be executable by the user connecting with sudo. + At this moment, this deployment launches a proxy mode docker. *) +module Ssh_host = struct + type t = {point : string * string * int; agents : Agent.t list} + + let deploy_proxy runner = + let configuration = Proxy.make_config () in + let next_available_port = + let cpt = ref 30_000 in + fun () -> + incr cpt ; + !cpt + in + let name = configuration.name in + let* docker_image = + Agent.Configuration.uri_of_docker_image configuration.vm.docker_image + in + (* Remove any existing proxy first *) + let* () = Docker.rm ~runner ~force:true name |> Process.check in + (* Prepare the arguments for docker run *) + let ssh_listening_port = next_available_port () in + let guest_port = string_of_int ssh_listening_port in + let publish_ports = (guest_port, guest_port, guest_port, guest_port) in + let volumes = + [ + ("/var/run/docker.sock", "/var/run/docker.sock"); + ("/tmp/prometheus", "/tmp/prometheus"); + ("/tmp/website", "/tmp/website"); + ("/tmp/grafana", "/tmp/grafana"); + ("/tmp/alert_manager", "/tmp/alert_manager"); + ("/tmp/otel", "/tmp/otel"); + ] + in + let* () = + Docker.run + ~runner + ~rm:true + ~detach:true + ~network:"host" + ~volumes + ~publish_ports + ~name + docker_image + ["-D"; "-p"; guest_port] + |> Process.check + in + let agent = + Agent.make + ~vm_name:None + ~configuration + ~next_available_port + ~point:(Runner.address (Some runner), ssh_listening_port) + ~ssh_id:(Env.ssh_private_key_filename ()) + ~process_monitor:None + () + in + Lwt.return agent + + let _deploy ~user ~host ~port ~(configurations : Agent.Configuration.t list) + () = + let proxy_runner = + Runner.create ~ssh_user:"root" ~ssh_port:port ~address:host () + in + (* Deploys the proxy *) + let* proxy = deploy_proxy proxy_runner in + (* Deploys all agents *) + let* agents = + Lwt_list.mapi_p + (fun i (configuration : Agent.Configuration.t) -> + let* docker_image = + Agent.Configuration.uri_of_docker_image + configuration.vm.docker_image + in + let ssh_port = Agent.next_available_port proxy in + (* FIXME move this constants elsewhere *) + let base_port = 30_050 in + let range = 50 in + let runner = + Runner.create ~ssh_user:user ~ssh_port:port ~address:host () + in + let publish_ports = + ( string_of_int (base_port + (i * range)), + string_of_int (base_port + ((i + 1) * range) - 1), + string_of_int (base_port + (i * range)), + string_of_int (base_port + ((i + 1) * range) - 1) ) + in + let* () = + Docker.run + ~runner + ~detach:true + ~publish_ports + ~network:"host" + ~name:configuration.name + docker_image + [ + "--entrypoint"; + "/usr/bin/sshd"; + "-D"; + "-p"; + string_of_int ssh_port; + "-e"; + ] + |> Process.check + in + let () = + Log.warn + "Deployed agent: %s on (%s, %d)" + configuration.name + host + ssh_port + in + let agent = + Agent.make + ~vm_name:None + ~configuration + ~next_available_port: + (let cpt = ref (base_port + (i * range)) in + fun () -> + incr cpt ; + !cpt) + ~process_monitor:None + ~point:(host, ssh_port) + ~ssh_id:(Env.ssh_private_key_filename ()) + () + in + Lwt.return agent) + configurations + in + let agents = proxy :: agents in + Lwt.return {point = (user, host, port); agents} + + let _agents t = t.agents + + let _terminate {point; agents} = + let _user, host, port = point in + let* () = + Lwt_list.iter_p + (fun agent -> + let name = Agent.name agent in + let runner = Runner.create ~ssh_port:port ~address:host () in + let* _ = Docker.rm ~runner name |> Process.check in + Lwt.return_unit) + agents + in + Lwt.return_unit +end + (* Infrastructure to deploy locally using Docker *) module Localhost = struct type t = { diff --git a/tezt/lib_cloud/docker.ml b/tezt/lib_cloud/docker.ml index f30fa419fc74676c6c5abcb549d6180aebab3f69..4f18d61f637a346f8234275b7531eca465e31920 100644 --- a/tezt/lib_cloud/docker.ml +++ b/tezt/lib_cloud/docker.ml @@ -55,7 +55,8 @@ let pull ?image_name ?alias ?(tag = "latest") ~registry_uri () = let network ~command ~network_name = Process.spawn ~color "docker" (["network"] @ [command] @ [network_name]) -let run ?(rm = false) ?name ?network ?publish_ports image args = +let run ?runner ?(rm = false) ?name ?(detach = false) ?network ?publish_ports + ?volumes image args = let publish_ports = match publish_ports with | None -> [] @@ -67,18 +68,36 @@ let run ?(rm = false) ?name ?network ?publish_ports image args = in let name = match name with None -> [] | Some name -> ["--name"; name] in let rm = if rm then ["--rm"] else [] in + let detach = if detach then ["-d"] else [] in + let volumes = + match volumes with + | None -> [] + | Some volumes -> + let arg_of_volume (host, container) = + ["-v"; Format.asprintf "%s:%s" host container] + in + List.map arg_of_volume volumes |> List.flatten + in (* [init] can be used to ensure signals are forwarded properly to the entrypoint run by the container. *) Process.spawn + ?runner ~color "docker" - (["run"] @ rm @ name @ macos_platform_arg @ network @ publish_ports + (["run"] @ detach @ rm @ name @ macos_platform_arg @ volumes @ network + @ publish_ports @ [Format.asprintf "%s" image] @ args) let kill container_name = Process.spawn ~color "docker" ["kill"; container_name] -let rm container_name = Process.spawn ~color "docker" ["rm"; container_name] +let rm ?runner ?(force = false) container_name = + Log.info "Docker.rm '%s'" container_name ; + Process.spawn + ?runner + ~color + "docker" + (["rm"] @ (if force then ["--force"] else []) @ [container_name]) let cp container_name ~kind ~source ~destination = match kind with diff --git a/tezt/lib_cloud/docker.mli b/tezt/lib_cloud/docker.mli index 0b5cc4970f726dc8a092bf5573dda1c42ce6a9bd..1c48b3fcc8b0573fda4577f7f31229648e1e5c08 100644 --- a/tezt/lib_cloud/docker.mli +++ b/tezt/lib_cloud/docker.mli @@ -49,10 +49,13 @@ val network : command:string -> network_name:string -> Process.t (** [run] is an alias for [docker run]. *) val run : + ?runner:Runner.t -> ?rm:bool -> ?name:string -> + ?detach:bool -> ?network:string -> ?publish_ports:string * string * string * string -> + ?volumes:(string * string) list -> string -> string list -> Process.t @@ -61,7 +64,7 @@ val run : val kill : string -> Process.t (** [rm] is an alias for [docker rm]. *) -val rm : string -> Process.t +val rm : ?runner:Runner.t -> ?force:bool -> string -> Process.t (** [cp] is an alias for [docker cp]. *) val cp :