struct
open Ketrew_host.Ssh
let do_ssh ssh command =
["ssh"; ssh_batch_option ssh]
@ ssh.add_ssh_options
@ (match ssh.port with
| Some p -> ["-p"; Int.to_string p]
| None -> [])
@ (match ssh.user with
| None -> [ssh.address]
| Some u -> [fmt "%s@%s" u ssh.address])
@ [command]
let generic_ssh_exec ssh command =
let unique_tag = Unique_id.create () in
let spicied_command =
fmt "echo -n %s >&2 ; (exec %s) ;
echo -n %s$? >&2 ;
exit 0"
unique_tag
(List.map command ~f:(Filename.quote) |> String.concat ~sep:" ")
unique_tag
in
let ssh_exec = do_ssh ssh spicied_command in
let parse_error_log out err =
let fail_parsing msg = fail (`Ssh_failure (`Wrong_log msg, err)) in
let pieces = String.split ~on:(`String unique_tag) err in
match pieces with
| "" :: actual_stderr :: return_value :: [] ->
begin match Int.of_string (String.strip return_value) with
| Some r -> return (out, actual_stderr, r)
| None ->
fail_parsing (fmt "Return value not an integer: %S" return_value)
end
| somehting_else -> fail_parsing "Cannot parse error log"
in
begin Ketrew_unix_process.exec ssh_exec
>>< function
| `Ok (out, err, `Exited 0) -> parse_error_log out err
| `Ok (out, err, other) ->
fail (`Ssh_failure (`Wrong_status other, err))
| `Error (`Process _ as process_error) ->
let msg = Ketrew_unix_process.error_to_string process_error in
Log.(s "Ssh-cmd " % OCaml.list (sf "%S") ssh_exec
% s " failed: " %s msg @ verbose);
fail (`Unix_exec msg)
end
let scp_push ssh ~src ~dest =
["scp"; ssh_batch_option ssh]
@ ssh.add_ssh_options
@ (match ssh.port with
| Some p -> ["-P"; "port"]
| None -> [])
@ src
@ (match ssh.user with
| None -> [fmt "%s:%s" ssh.address dest]
| Some u -> [fmt "%s@%s:%s" u ssh.address dest])
let scp_pull ssh ~src ~dest =
["scp"; ssh_batch_option ssh]
@ ssh.add_ssh_options
@ (match ssh.port with
| Some p -> ["-P"; "port"]
| None -> [])
@ (List.map src ~f:(fun src_item ->
match ssh.user with
| None -> fmt "%s:%s" ssh.address src_item
| Some u -> fmt "%s@%s:%s" u ssh.address src_item))
@ [dest]
end