Source file push_manifest.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
open Lwt.Infix
open Auth
type t = auth option
let ( >>!= ) = Lwt_result.bind
let id = "docker-push-manifest"
let push_mutex = Lwt_mutex.create ()
module Key = Current.String
module Value = struct
type t = {
manifests : S.repo_id list;
}
let digest { manifests } =
Yojson.Safe.to_string @@ `Assoc [
"manifests", `List (List.map (fun id -> `String id) manifests);
]
end
module Outcome = struct
include Current.String
let unmarshal = function
| "()" -> failwith "Result from old version. Need rebuild"
| repo_id -> repo_id
end
let create_cmd ~config ~tag {Value.manifests} =
Cmd.docker ~config ~docker_context:None (["manifest"; "create"; tag] @ manifests)
let push_cmd ~config tag =
Cmd.docker ~config ~docker_context:None ["manifest"; "push"; tag]
let or_fail = function
| Ok x -> x
| Error (`Msg x) -> failwith x
let publish auth job tag value =
Current.Job.start job ~level:Current.Level.Dangerous >>= fun () ->
Current.Process.with_tmpdir ~prefix:"push-manifest" @@ fun config ->
Bos.OS.File.write Fpath.(config / "config.json") {|{"experimental": "enabled"}|} |> or_fail;
Auth.login ~config ~docker_context:None ~job auth >>!= fun () ->
Prometheus.Gauge.inc_one Metrics.docker_push_manifest_events;
Current.Process.exec ~cancellable:true ~job (create_cmd ~config ~tag value) >>= (function
| Error _ as e -> Lwt.return e
| Ok () ->
Lwt_mutex.with_lock push_mutex @@ fun () ->
Current.Process.check_output ~cancellable:true ~job (push_cmd ~config tag) >>!= fun output ->
Current.Job.write job output;
let output = String.trim output in
let hash =
match Astring.String.cut ~rev:true ~sep:"\n" output with
| None -> output
| Some (_, id) -> id
in
let repo_id = Printf.sprintf "%s@%s" tag hash in
Current.Job.log job "--> %S" repo_id;
Lwt_result.return repo_id)
>|= (fun res -> Prometheus.Gauge.dec_one Metrics.docker_push_manifest_events; res)
let pp f (tag, value) =
Fmt.pf f "push %s = %s" tag (Value.digest value)
let auto_cancel = true