diff options
author | John Estabrook <jestabro@vyos.io> | 2025-03-16 22:59:46 -0500 |
---|---|---|
committer | John Estabrook <jestabro@vyos.io> | 2025-03-16 23:13:39 -0500 |
commit | 57f788f4dc1468807a2d78f7effbbaddcae6f36c (patch) | |
tree | 5ffb797cf40f6a5ccbc16560d8b9d17ebab20e3b | |
parent | d246228cfb94261a4b71cd8ed066d6c651f0a550 (diff) | |
download | vyconf-57f788f4dc1468807a2d78f7effbbaddcae6f36c.tar.gz vyconf-57f788f4dc1468807a2d78f7effbbaddcae6f36c.zip |
T7121: add commitd client operation and test function
-rw-r--r-- | src/dune | 13 | ||||
-rw-r--r-- | src/vycall_client.ml | 124 | ||||
-rw-r--r-- | src/vycall_client.mli | 1 |
3 files changed, 138 insertions, 0 deletions
@@ -22,6 +22,19 @@ yojson ppx_deriving.show ppx_deriving_yojson) (preprocess (pps lwt_ppx ppx_deriving.show ppx_deriving_yojson))) +(library + (name vycall_message) + (public_name vyconf.vycall-message) + (modules vycall_pbt) + (libraries ocaml-protoc)) + +(library + (name commitd_client) + (public_name vyconf.vycall-client) + (modules vycall_client) + (libraries vyos1x-config vyconfd_config vycall_message lwt lwt.unix lwt_log lwt_ppx ocplib-endian) + (preprocess (pps lwt_ppx))) + (executable (name vyconfd) (public_name vyconfd) diff --git a/src/vycall_client.ml b/src/vycall_client.ml new file mode 100644 index 0000000..c7fc811 --- /dev/null +++ b/src/vycall_client.ml @@ -0,0 +1,124 @@ +(* send commit data to Python commit daemon *) + +open Vycall_message.Vycall_pbt +open Vyconfd_config.Commit + +module CT = Vyos1x.Config_tree +module IC = Vyos1x.Internal.Make(CT) +module ST = Vyconfd_config.Startup +module DF = Vyconfd_config.Defaults +module FP = FilePath + +type t = { + ic: Lwt_io.input Lwt_io.channel; + oc: Lwt_io.output Lwt_io.channel; +} + +(* explicit translation between commit data and commit protobuf + * to keep the commit data opaque to protobuf message definition. + * The commit daemon updates the (subset of) commit data with + * results of script execution in init/reply fields. + *) +let node_data_to_call nd = + { script_name = nd.script_name; + tag_value = nd.tag_value; + arg_value = nd.arg_value; + reply = None + } + +let call_to_node_data ((c: call), (nd: node_data)) = + match c.reply with + | None -> nd + | Some r -> { nd with reply = Some { success = r.success; out = r.out }} + +let commit_data_to_commit_proto cd = + { session_id = cd.session_id; + named_active = cd.named_active; + named_proposed = cd.named_proposed; + dry_run = cd.dry_run; + atomic = cd.atomic; + background = cd.background; + init = None; + calls = List.map node_data_to_call cd.node_list; + } + +let commit_proto_to_commit_data (c: commit) (cd: commit_data) = + match c.init with + | None -> cd + | Some i -> + { cd with init = Some { success = i.success; out = i.out }; + node_list = + List.map call_to_node_data (List.combine c.calls cd.node_list); + } + +(* read/write message from/to socket *) +let call_write oc msg = + let length = Bytes.length msg in + let length' = Int32.of_int length in + if length' < 0l then failwith (Printf.sprintf "Bad message length: %d" length) else + let header = Bytes.create 4 in + let () = EndianBytes.BigEndian.set_int32 header 0 length' in + let%lwt () = Lwt_io.write_from_exactly oc header 0 4 in + Lwt_io.write_from_exactly oc msg 0 length + +let call_read ic = + let header = Bytes.create 4 in + let%lwt () = Lwt_io.read_into_exactly ic header 0 4 in + let length = EndianBytes.BigEndian.get_int32 header 0 |> Int32.to_int in + if length < 0 then failwith (Printf.sprintf "Bad message length: %d" length) else + let buffer = Bytes.create length in + let%lwt () = Lwt_io.read_into_exactly ic buffer 0 length in + Lwt.return buffer + +(* encode/decode commit data *) +let do_call client request = + let enc = Pbrt.Encoder.create () in + let () = encode_pb_commit request enc in + let msg = Pbrt.Encoder.to_bytes enc in + let%lwt () = call_write client.oc msg in + let%lwt resp = call_read client.ic in + decode_pb_commit (Pbrt.Decoder.of_bytes resp) |> Lwt.return + +(* socket management and commit callback *) +let create sockfile = + let open Lwt_unix in + let sock = socket PF_UNIX SOCK_STREAM 0 in + let%lwt () = connect sock (ADDR_UNIX sockfile) in + let ic = Lwt_io.of_fd ~mode:Lwt_io.Input sock in + let oc = Lwt_io.of_fd ~mode:Lwt_io.Output sock in + Lwt.return { ic=ic; oc=oc; } + +let update session_data = + Lwt.return (commit_store session_data) + +let do_commit session_data = + let session = commit_data_to_commit_proto session_data in + let run () = + let sockfile = "/run/vyos-commitd.sock" in + let%lwt client = create sockfile in + let%lwt resp = do_call client session in + let%lwt () = Lwt_io.close client.oc in + update (commit_proto_to_commit_data resp session_data) + in Lwt_main.run @@ run () + +(* test function *) +let test_commit at wt = + let vc = + ST.load_daemon_config DF.defaults.config_file in + let () = + IC.write_internal at (FP.concat vc.session_dir vc.running_cache) in + let () = + IC.write_internal wt (FP.concat vc.session_dir vc.session_cache) in + let rt_opt = + ST.read_reference_tree (FP.concat vc.reftree_dir vc.reference_tree) + in + match rt_opt with + | Error msg -> print_endline msg + | Ok rt -> + let del_list, add_list = + calculate_priority_lists rt at wt + in + let commit_session = + { default_commit_data with node_list = del_list @ add_list } + in + do_commit commit_session diff --git a/src/vycall_client.mli b/src/vycall_client.mli new file mode 100644 index 0000000..8836f73 --- /dev/null +++ b/src/vycall_client.mli @@ -0,0 +1 @@ +val test_commit : Vyos1x.Config_tree.t -> Vyos1x.Config_tree.t -> unit |