From 46890b13b9e565b7b61d2c75ca92441cb7490f7f Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Sat, 22 Nov 2025 21:05:36 -0600 Subject: T8032: add protobuf messaage for config_unsaved request --- data/vyconf.proto | 5 +++++ src/vyconf_pbt.ml | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vyconf_pbt.mli | 20 +++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/data/vyconf.proto b/data/vyconf.proto index fbc7f2d..f45792a 100644 --- a/data/vyconf.proto +++ b/data/vyconf.proto @@ -185,6 +185,10 @@ message Request { optional int32 dummy = 1; } + message ConfigUnsaved { + optional string file = 1; + } + oneof msg { Prompt prompt = 1; @@ -224,6 +228,7 @@ message Request { ResetEditLevel reset_edit_level = 35; GetEditLevel get_edit_level = 36; EditLevelRoot edit_level_root = 37; + ConfigUnsaved config_unsaved = 38; } } diff --git a/src/vyconf_pbt.ml b/src/vyconf_pbt.ml index fe19a44..85eb4e3 100644 --- a/src/vyconf_pbt.ml +++ b/src/vyconf_pbt.ml @@ -179,6 +179,10 @@ type request_edit_level_root = { dummy : int32 option; } +type request_config_unsaved = { + file : string option; +} + type request = | Prompt | Setup_session of request_setup_session @@ -217,6 +221,7 @@ type request = | Reset_edit_level of request_reset_edit_level | Get_edit_level of request_get_edit_level | Edit_level_root of request_edit_level_root + | Config_unsaved of request_config_unsaved type request_envelope = { token : string option; @@ -514,6 +519,12 @@ let rec default_request_edit_level_root dummy; } +let rec default_request_config_unsaved + ?file:((file:string option) = None) + () : request_config_unsaved = { + file; +} + let rec default_request (): request = Prompt let rec default_request_envelope @@ -868,6 +879,14 @@ let default_request_edit_level_root_mutable () : request_edit_level_root_mutable dummy = None; } +type request_config_unsaved_mutable = { + mutable file : string option; +} + +let default_request_config_unsaved_mutable () : request_config_unsaved_mutable = { + file = None; +} + type request_envelope_mutable = { mutable token : string option; mutable request : request; @@ -1157,6 +1176,12 @@ let rec pp_request_edit_level_root fmt (v:request_edit_level_root) = in Pbrt.Pp.pp_brk pp_i fmt () +let rec pp_request_config_unsaved fmt (v:request_config_unsaved) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "file" (Pbrt.Pp.pp_option Pbrt.Pp.pp_string) fmt v.file; + in + Pbrt.Pp.pp_brk pp_i fmt () + let rec pp_request fmt (v:request) = match v with | Prompt -> Format.fprintf fmt "Prompt" @@ -1196,6 +1221,7 @@ let rec pp_request fmt (v:request) = | Reset_edit_level x -> Format.fprintf fmt "@[Reset_edit_level(@,%a)@]" pp_request_reset_edit_level x | Get_edit_level x -> Format.fprintf fmt "@[Get_edit_level(@,%a)@]" pp_request_get_edit_level x | Edit_level_root x -> Format.fprintf fmt "@[Edit_level_root(@,%a)@]" pp_request_edit_level_root x + | Config_unsaved x -> Format.fprintf fmt "@[Config_unsaved(@,%a)@]" pp_request_config_unsaved x let rec pp_request_envelope fmt (v:request_envelope) = let pp_i fmt () = @@ -1623,6 +1649,15 @@ let rec encode_pb_request_edit_level_root (v:request_edit_level_root) encoder = end; () +let rec encode_pb_request_config_unsaved (v:request_config_unsaved) encoder = + begin match v.file with + | Some x -> + Pbrt.Encoder.string x encoder; + Pbrt.Encoder.key 1 Pbrt.Bytes encoder; + | None -> (); + end; + () + let rec encode_pb_request (v:request) encoder = begin match v with | Prompt -> @@ -1736,6 +1771,9 @@ let rec encode_pb_request (v:request) encoder = | Edit_level_root x -> Pbrt.Encoder.nested encode_pb_request_edit_level_root x encoder; Pbrt.Encoder.key 37 Pbrt.Bytes encoder; + | Config_unsaved x -> + Pbrt.Encoder.nested encode_pb_request_config_unsaved x encoder; + Pbrt.Encoder.key 38 Pbrt.Bytes encoder; end let rec encode_pb_request_envelope (v:request_envelope) encoder = @@ -2658,6 +2696,24 @@ let rec decode_pb_request_edit_level_root d = dummy = v.dummy; } : request_edit_level_root) +let rec decode_pb_request_config_unsaved d = + let v = default_request_config_unsaved_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.file <- Some (Pbrt.Decoder.string d); + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_config_unsaved), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + file = v.file; + } : request_config_unsaved) + let rec decode_pb_request d = let rec loop () = let ret:request = match Pbrt.Decoder.key d with @@ -2708,6 +2764,7 @@ let rec decode_pb_request d = | Some (35, _) -> (Reset_edit_level (decode_pb_request_reset_edit_level (Pbrt.Decoder.nested d)) : request) | Some (36, _) -> (Get_edit_level (decode_pb_request_get_edit_level (Pbrt.Decoder.nested d)) : request) | Some (37, _) -> (Edit_level_root (decode_pb_request_edit_level_root (Pbrt.Decoder.nested d)) : request) + | Some (38, _) -> (Config_unsaved (decode_pb_request_config_unsaved (Pbrt.Decoder.nested d)) : request) | Some (n, payload_kind) -> ( Pbrt.Decoder.skip d payload_kind; loop () diff --git a/src/vyconf_pbt.mli b/src/vyconf_pbt.mli index 75dea62..285abfb 100644 --- a/src/vyconf_pbt.mli +++ b/src/vyconf_pbt.mli @@ -186,6 +186,10 @@ type request_edit_level_root = { dummy : int32 option; } +type request_config_unsaved = { + file : string option; +} + type request = | Prompt | Setup_session of request_setup_session @@ -224,6 +228,7 @@ type request = | Reset_edit_level of request_reset_edit_level | Get_edit_level of request_get_edit_level | Edit_level_root of request_edit_level_root + | Config_unsaved of request_config_unsaved type request_envelope = { token : string option; @@ -500,6 +505,12 @@ val default_request_edit_level_root : request_edit_level_root (** [default_request_edit_level_root ()] is the default value for type [request_edit_level_root] *) +val default_request_config_unsaved : + ?file:string option -> + unit -> + request_config_unsaved +(** [default_request_config_unsaved ()] is the default value for type [request_config_unsaved] *) + val default_request : unit -> request (** [default_request ()] is the default value for type [request] *) @@ -642,6 +653,9 @@ val pp_request_get_edit_level : Format.formatter -> request_get_edit_level -> un val pp_request_edit_level_root : Format.formatter -> request_edit_level_root -> unit (** [pp_request_edit_level_root v] formats v *) +val pp_request_config_unsaved : Format.formatter -> request_config_unsaved -> unit +(** [pp_request_config_unsaved v] formats v *) + val pp_request : Format.formatter -> request -> unit (** [pp_request v] formats v *) @@ -774,6 +788,9 @@ val encode_pb_request_get_edit_level : request_get_edit_level -> Pbrt.Encoder.t val encode_pb_request_edit_level_root : request_edit_level_root -> Pbrt.Encoder.t -> unit (** [encode_pb_request_edit_level_root v encoder] encodes [v] with the given [encoder] *) +val encode_pb_request_config_unsaved : request_config_unsaved -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_config_unsaved v encoder] encodes [v] with the given [encoder] *) + val encode_pb_request : request -> Pbrt.Encoder.t -> unit (** [encode_pb_request v encoder] encodes [v] with the given [encoder] *) @@ -906,6 +923,9 @@ val decode_pb_request_get_edit_level : Pbrt.Decoder.t -> request_get_edit_level val decode_pb_request_edit_level_root : Pbrt.Decoder.t -> request_edit_level_root (** [decode_pb_request_edit_level_root decoder] decodes a [request_edit_level_root] binary value from [decoder] *) +val decode_pb_request_config_unsaved : Pbrt.Decoder.t -> request_config_unsaved +(** [decode_pb_request_config_unsaved decoder] decodes a [request_config_unsaved] binary value from [decoder] *) + val decode_pb_request : Pbrt.Decoder.t -> request (** [decode_pb_request decoder] decodes a [request] binary value from [decoder] *) -- cgit v1.2.3 From f28bad075bc46c95dd2e52037d6e52d1621d2a49 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Sun, 23 Nov 2025 15:10:01 -0600 Subject: T8032: add vyconfd handlers for config_unsaved --- src/session.ml | 16 ++++++++++++---- src/session.mli | 2 ++ src/vyconfd.ml | 11 +++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/session.ml b/src/session.ml index 248121d..478c423 100644 --- a/src/session.ml +++ b/src/session.ml @@ -379,6 +379,18 @@ let save w s file = | Error e -> raise (Session_error (Printf.sprintf "Error saving config: %s" e)) | Ok () -> s +let remove_file file = + if Sys.file_exists file then Sys.remove file + +let config_unsaved w s file id = + let tmp_save = Printf.sprintf "/tmp/config.running_%s" id in + let res = + try + let _ = save w s tmp_save in + not (Vyos1x.Util.file_compare ~ignore_line_prefix:"//" tmp_save file) + with Session_error _ -> true (* false positive on unlikely error *) + in remove_file tmp_save; res + let write_running_cache w = (* alert exn Internal.write_internal: [Internal.Write_error] caught @@ -480,10 +492,6 @@ let get_config w s id = in id let cleanup_config w id = - let remove_file file = - if Sys.file_exists file then - Sys.remove file - in let vc = w.vyconf_config in let running_cache = Printf.sprintf "%s_%s" vc.running_cache id in let session_cache = Printf.sprintf "%s_%s" vc.session_cache id in diff --git a/src/session.mli b/src/session.mli index 757bc18..cb49bf6 100644 --- a/src/session.mli +++ b/src/session.mli @@ -69,6 +69,8 @@ val merge : world -> session_data -> string -> bool -> session_data val save : world -> session_data -> string -> session_data +val config_unsaved : world -> session_data -> string -> string -> bool + val get_value : world -> session_data -> string list -> string val get_values : world -> session_data -> string list -> string list diff --git a/src/vyconfd.ml b/src/vyconfd.ml index ed84978..dc302e5 100644 --- a/src/vyconfd.ml +++ b/src/vyconfd.ml @@ -407,6 +407,16 @@ let edit_level_root world token (_req: request_edit_level_root) = if Session.edit_level_root world (find_session token) then response_tmpl else {response_tmpl with status=Fail} +let config_unsaved world token (req: request_config_unsaved) = + let saved_file = + match req.file with + | None -> defaults.legacy_config_path + | Some file -> file + in + if Session.config_unsaved world (find_session token) saved_file token + then response_tmpl + else {response_tmpl with status=Fail} + let send_response oc resp = let enc = Pbrt.Encoder.create () in let%lwt () = encode_pb_response resp enc |> return in @@ -463,6 +473,7 @@ let rec handle_connection world ic oc () = | Some t, Reset_edit_level r -> reset_edit_level world t r | Some t, Get_edit_level r -> get_edit_level world t r | Some t, Edit_level_root r -> edit_level_root world t r + | Some t, Config_unsaved r -> config_unsaved world t r | _ -> failwith "Unimplemented" ) |> Lwt.return end -- cgit v1.2.3 From 44397fa19950a6d729080051835c079cbf811435 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Sun, 23 Nov 2025 20:38:54 -0600 Subject: T8032: add config_unsaved request to client module --- src/vyconf_client.ml | 8 ++++++++ src/vyconf_client.mli | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/vyconf_client.ml b/src/vyconf_client.ml index 9250851..76b6680 100644 --- a/src/vyconf_client.ml +++ b/src/vyconf_client.ml @@ -221,3 +221,11 @@ let edit_level_root client = | Success -> Lwt.return (Ok "") | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let config_unsaved client file = + let req = Config_unsaved {file=file;} in + let%lwt resp = do_request client req in + match resp.status with + | Success -> Lwt.return (Ok "") + | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return + | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return diff --git a/src/vyconf_client.mli b/src/vyconf_client.mli index 200f960..a3744d7 100644 --- a/src/vyconf_client.mli +++ b/src/vyconf_client.mli @@ -47,3 +47,5 @@ val reset_edit_level : t -> (string, string) result Lwt.t val get_edit_level : t -> (string, string) result Lwt.t val edit_level_root : t -> (string, string) result Lwt.t + +val config_unsaved : t -> string option -> (string, string) result Lwt.t -- cgit v1.2.3 From 9def9bcde17e0720283dae6822bece98983bf7ee Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Sun, 23 Nov 2025 20:42:57 -0600 Subject: T8032: add translation of sessionUnsaved --- src/vyconf_cli_compat.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vyconf_cli_compat.ml b/src/vyconf_cli_compat.ml index eaa3501..6ebd1f1 100644 --- a/src/vyconf_cli_compat.ml +++ b/src/vyconf_cli_compat.ml @@ -9,6 +9,7 @@ type op_t = | OpEditLevelRoot | OpShowConfig | OpSessionChanged + | OpConfigUnsaved let op_of_arg s = match s with @@ -19,6 +20,7 @@ let op_of_arg s = | "editLevelAtRoot" -> OpEditLevelRoot | "showCfg" -> OpShowConfig | "sessionChanged" -> OpSessionChanged + | "sessionUnsaved" -> OpConfigUnsaved | _ -> failwith (Printf.sprintf "Unknown operation %s" s) let in_cli_config_session () = @@ -88,6 +90,7 @@ let main op path = | OpEditLevelRoot -> edit_level_root c | OpShowConfig -> show_config c path | OpSessionChanged -> session_changed c + | OpConfigUnsaved -> config_unsaved c None end | Error e -> Error e |> Lwt.return in -- cgit v1.2.3