package rpc_parallel

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file remote_executable.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
open Core
open Poly
open Async

type 'a t =
  { host : string
  ; path : string
  ; host_key_checking : string list
  }
[@@deriving fields ~getters]

let hostkey_checking_options opt =
  match opt with
  | None -> []
  (* Use ssh default *)
  | Some `Ask -> [ "-o"; "StrictHostKeyChecking=ask" ]
  | Some `No -> [ "-o"; "StrictHostKeyChecking=no" ]
  | Some `Yes -> [ "-o"; "StrictHostKeyChecking=yes" ]
;;

let existing_on_host ~executable_path ?strict_host_key_checking host =
  { host
  ; path = executable_path
  ; host_key_checking = hostkey_checking_options strict_host_key_checking
  }
;;

let copy_to_host ~executable_dir ?strict_host_key_checking host =
  let our_basename = Filename.basename Sys.executable_name in
  Process.run ~prog:"mktemp" ~args:[ "-u"; sprintf "%s.XXXXXXXX" our_basename ] ()
  >>=? fun new_basename ->
  let options = hostkey_checking_options strict_host_key_checking in
  let path = String.strip (executable_dir ^/ new_basename) in
  Process.run
    ~prog:"scp"
    ~args:(options @ [ Utils.our_binary (); sprintf "%s:%s" host path ])
    ()
  >>|? Fn.const { host; path; host_key_checking = options }
;;

let delete executable =
  Process.run
    ~prog:"ssh"
    ~args:(executable.host_key_checking @ [ executable.host; "rm"; executable.path ])
    ()
  >>|? Fn.const ()
;;

let env_for_ssh env =
  let env =
    (* If we are running a test, we should propagate the relevant environment variable
       through ssh so the spawned workers know they are running a test. *)
    if am_running_test then ("TESTING_FRAMEWORK", "") :: env else env
  in
  let cheesy_escape str = Sexp.to_string (String.sexp_of_t str) in
  List.map env ~f:(fun (key, data) -> key ^ "=" ^ cheesy_escape data)
;;

let run ?(assert_binary_hash = true) exec ~env ~args ~wrap =
  let%bind.Deferred.Or_error () =
    match assert_binary_hash with
    | false -> Deferred.Or_error.ok_unit
    | true ->
      Utils.our_md5 ()
      >>=? fun md5 ->
      Process.run
        ~prog:"ssh"
        ~args:(exec.host_key_checking @ [ exec.host; "md5sum"; exec.path ])
        ()
      >>=? fun remote_md5 ->
      let remote_md5, _ = String.lsplit2_exn ~on:' ' remote_md5 in
      if md5 <> remote_md5
      then
        Deferred.Or_error.errorf
          "The remote executable %s:%s does not match the local executable"
          exec.host
          exec.path
      else Deferred.Or_error.ok_unit
  in
  let { Prog_and_args.prog; args } = wrap { Prog_and_args.prog = exec.path; args } in
  Process.create
    ~prog:"ssh"
    ~args:(exec.host_key_checking @ [ exec.host ] @ env_for_ssh env @ [ prog ] @ args)
    ()
;;