From e00f45edd537180d3b1b78657b001eaf65529538 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Mon, 17 Nov 2025 11:40:32 -0600 Subject: T8009: add messages for edit_level requests --- src/vyconf_pbt.ml | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vyconf_pbt.mli | 100 +++++++++++++++++++ 2 files changed, 384 insertions(+) (limited to 'src') diff --git a/src/vyconf_pbt.ml b/src/vyconf_pbt.ml index d84d94f..fe19a44 100644 --- a/src/vyconf_pbt.ml +++ b/src/vyconf_pbt.ml @@ -159,6 +159,26 @@ type request_show_sessions = { exclude_other : bool; } +type request_set_edit_level = { + path : string list; +} + +type request_set_edit_level_up = { + dummy : int32 option; +} + +type request_reset_edit_level = { + dummy : int32 option; +} + +type request_get_edit_level = { + dummy : int32 option; +} + +type request_edit_level_root = { + dummy : int32 option; +} + type request = | Prompt | Setup_session of request_setup_session @@ -192,6 +212,11 @@ type request = | Aux_set of request_aux_set | Aux_delete of request_aux_delete | Show_sessions of request_show_sessions + | Set_edit_level of request_set_edit_level + | Set_edit_level_up of request_set_edit_level_up + | Reset_edit_level of request_reset_edit_level + | Get_edit_level of request_get_edit_level + | Edit_level_root of request_edit_level_root type request_envelope = { token : string option; @@ -459,6 +484,36 @@ let rec default_request_show_sessions exclude_other; } +let rec default_request_set_edit_level + ?path:((path:string list) = []) + () : request_set_edit_level = { + path; +} + +let rec default_request_set_edit_level_up + ?dummy:((dummy:int32 option) = None) + () : request_set_edit_level_up = { + dummy; +} + +let rec default_request_reset_edit_level + ?dummy:((dummy:int32 option) = None) + () : request_reset_edit_level = { + dummy; +} + +let rec default_request_get_edit_level + ?dummy:((dummy:int32 option) = None) + () : request_get_edit_level = { + dummy; +} + +let rec default_request_edit_level_root + ?dummy:((dummy:int32 option) = None) + () : request_edit_level_root = { + dummy; +} + let rec default_request (): request = Prompt let rec default_request_envelope @@ -773,6 +828,46 @@ let default_request_show_sessions_mutable () : request_show_sessions_mutable = { exclude_other = false; } +type request_set_edit_level_mutable = { + mutable path : string list; +} + +let default_request_set_edit_level_mutable () : request_set_edit_level_mutable = { + path = []; +} + +type request_set_edit_level_up_mutable = { + mutable dummy : int32 option; +} + +let default_request_set_edit_level_up_mutable () : request_set_edit_level_up_mutable = { + dummy = None; +} + +type request_reset_edit_level_mutable = { + mutable dummy : int32 option; +} + +let default_request_reset_edit_level_mutable () : request_reset_edit_level_mutable = { + dummy = None; +} + +type request_get_edit_level_mutable = { + mutable dummy : int32 option; +} + +let default_request_get_edit_level_mutable () : request_get_edit_level_mutable = { + dummy = None; +} + +type request_edit_level_root_mutable = { + mutable dummy : int32 option; +} + +let default_request_edit_level_root_mutable () : request_edit_level_root_mutable = { + dummy = None; +} + type request_envelope_mutable = { mutable token : string option; mutable request : request; @@ -1032,6 +1127,36 @@ let rec pp_request_show_sessions fmt (v:request_show_sessions) = in Pbrt.Pp.pp_brk pp_i fmt () +let rec pp_request_set_edit_level fmt (v:request_set_edit_level) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "path" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.path; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_request_set_edit_level_up fmt (v:request_set_edit_level_up) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "dummy" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.dummy; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_request_reset_edit_level fmt (v:request_reset_edit_level) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "dummy" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.dummy; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_request_get_edit_level fmt (v:request_get_edit_level) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "dummy" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.dummy; + in + Pbrt.Pp.pp_brk pp_i fmt () + +let rec pp_request_edit_level_root fmt (v:request_edit_level_root) = + let pp_i fmt () = + Pbrt.Pp.pp_record_field ~first:true "dummy" (Pbrt.Pp.pp_option Pbrt.Pp.pp_int32) fmt v.dummy; + in + Pbrt.Pp.pp_brk pp_i fmt () + let rec pp_request fmt (v:request) = match v with | Prompt -> Format.fprintf fmt "Prompt" @@ -1066,6 +1191,11 @@ let rec pp_request fmt (v:request) = | Aux_set x -> Format.fprintf fmt "@[Aux_set(@,%a)@]" pp_request_aux_set x | Aux_delete x -> Format.fprintf fmt "@[Aux_delete(@,%a)@]" pp_request_aux_delete x | Show_sessions x -> Format.fprintf fmt "@[Show_sessions(@,%a)@]" pp_request_show_sessions x + | Set_edit_level x -> Format.fprintf fmt "@[Set_edit_level(@,%a)@]" pp_request_set_edit_level x + | Set_edit_level_up x -> Format.fprintf fmt "@[Set_edit_level_up(@,%a)@]" pp_request_set_edit_level_up x + | 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 let rec pp_request_envelope fmt (v:request_envelope) = let pp_i fmt () = @@ -1450,6 +1580,49 @@ let rec encode_pb_request_show_sessions (v:request_show_sessions) encoder = Pbrt.Encoder.key 2 Pbrt.Varint encoder; () +let rec encode_pb_request_set_edit_level (v:request_set_edit_level) encoder = + Pbrt.List_util.rev_iter_with (fun x encoder -> + Pbrt.Encoder.string x encoder; + Pbrt.Encoder.key 1 Pbrt.Bytes encoder; + ) v.path encoder; + () + +let rec encode_pb_request_set_edit_level_up (v:request_set_edit_level_up) encoder = + begin match v.dummy with + | Some x -> + Pbrt.Encoder.int32_as_varint x encoder; + Pbrt.Encoder.key 1 Pbrt.Varint encoder; + | None -> (); + end; + () + +let rec encode_pb_request_reset_edit_level (v:request_reset_edit_level) encoder = + begin match v.dummy with + | Some x -> + Pbrt.Encoder.int32_as_varint x encoder; + Pbrt.Encoder.key 1 Pbrt.Varint encoder; + | None -> (); + end; + () + +let rec encode_pb_request_get_edit_level (v:request_get_edit_level) encoder = + begin match v.dummy with + | Some x -> + Pbrt.Encoder.int32_as_varint x encoder; + Pbrt.Encoder.key 1 Pbrt.Varint encoder; + | None -> (); + end; + () + +let rec encode_pb_request_edit_level_root (v:request_edit_level_root) encoder = + begin match v.dummy with + | Some x -> + Pbrt.Encoder.int32_as_varint x encoder; + Pbrt.Encoder.key 1 Pbrt.Varint encoder; + | None -> (); + end; + () + let rec encode_pb_request (v:request) encoder = begin match v with | Prompt -> @@ -1548,6 +1721,21 @@ let rec encode_pb_request (v:request) encoder = | Show_sessions x -> Pbrt.Encoder.nested encode_pb_request_show_sessions x encoder; Pbrt.Encoder.key 32 Pbrt.Bytes encoder; + | Set_edit_level x -> + Pbrt.Encoder.nested encode_pb_request_set_edit_level x encoder; + Pbrt.Encoder.key 33 Pbrt.Bytes encoder; + | Set_edit_level_up x -> + Pbrt.Encoder.nested encode_pb_request_set_edit_level_up x encoder; + Pbrt.Encoder.key 34 Pbrt.Bytes encoder; + | Reset_edit_level x -> + Pbrt.Encoder.nested encode_pb_request_reset_edit_level x encoder; + Pbrt.Encoder.key 35 Pbrt.Bytes encoder; + | Get_edit_level x -> + Pbrt.Encoder.nested encode_pb_request_get_edit_level x encoder; + Pbrt.Encoder.key 36 Pbrt.Bytes encoder; + | Edit_level_root x -> + Pbrt.Encoder.nested encode_pb_request_edit_level_root x encoder; + Pbrt.Encoder.key 37 Pbrt.Bytes encoder; end let rec encode_pb_request_envelope (v:request_envelope) encoder = @@ -2379,6 +2567,97 @@ let rec decode_pb_request_show_sessions d = exclude_other = v.exclude_other; } : request_show_sessions) +let rec decode_pb_request_set_edit_level d = + let v = default_request_set_edit_level_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + v.path <- List.rev v.path; + ); continue__ := false + | Some (1, Pbrt.Bytes) -> begin + v.path <- (Pbrt.Decoder.string d) :: v.path; + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_set_edit_level), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + path = v.path; + } : request_set_edit_level) + +let rec decode_pb_request_set_edit_level_up d = + let v = default_request_set_edit_level_up_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Varint) -> begin + v.dummy <- Some (Pbrt.Decoder.int32_as_varint d); + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_set_edit_level_up), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + dummy = v.dummy; + } : request_set_edit_level_up) + +let rec decode_pb_request_reset_edit_level d = + let v = default_request_reset_edit_level_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Varint) -> begin + v.dummy <- Some (Pbrt.Decoder.int32_as_varint d); + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_reset_edit_level), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + dummy = v.dummy; + } : request_reset_edit_level) + +let rec decode_pb_request_get_edit_level d = + let v = default_request_get_edit_level_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Varint) -> begin + v.dummy <- Some (Pbrt.Decoder.int32_as_varint d); + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_get_edit_level), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + dummy = v.dummy; + } : request_get_edit_level) + +let rec decode_pb_request_edit_level_root d = + let v = default_request_edit_level_root_mutable () in + let continue__= ref true in + while !continue__ do + match Pbrt.Decoder.key d with + | None -> ( + ); continue__ := false + | Some (1, Pbrt.Varint) -> begin + v.dummy <- Some (Pbrt.Decoder.int32_as_varint d); + end + | Some (1, pk) -> + Pbrt.Decoder.unexpected_payload "Message(request_edit_level_root), field(1)" pk + | Some (_, payload_kind) -> Pbrt.Decoder.skip d payload_kind + done; + ({ + dummy = v.dummy; + } : request_edit_level_root) + let rec decode_pb_request d = let rec loop () = let ret:request = match Pbrt.Decoder.key d with @@ -2424,6 +2703,11 @@ let rec decode_pb_request d = | Some (30, _) -> (Aux_set (decode_pb_request_aux_set (Pbrt.Decoder.nested d)) : request) | Some (31, _) -> (Aux_delete (decode_pb_request_aux_delete (Pbrt.Decoder.nested d)) : request) | Some (32, _) -> (Show_sessions (decode_pb_request_show_sessions (Pbrt.Decoder.nested d)) : request) + | Some (33, _) -> (Set_edit_level (decode_pb_request_set_edit_level (Pbrt.Decoder.nested d)) : request) + | Some (34, _) -> (Set_edit_level_up (decode_pb_request_set_edit_level_up (Pbrt.Decoder.nested d)) : request) + | 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 (n, payload_kind) -> ( Pbrt.Decoder.skip d payload_kind; loop () diff --git a/src/vyconf_pbt.mli b/src/vyconf_pbt.mli index b5b056a..75dea62 100644 --- a/src/vyconf_pbt.mli +++ b/src/vyconf_pbt.mli @@ -166,6 +166,26 @@ type request_show_sessions = { exclude_other : bool; } +type request_set_edit_level = { + path : string list; +} + +type request_set_edit_level_up = { + dummy : int32 option; +} + +type request_reset_edit_level = { + dummy : int32 option; +} + +type request_get_edit_level = { + dummy : int32 option; +} + +type request_edit_level_root = { + dummy : int32 option; +} + type request = | Prompt | Setup_session of request_setup_session @@ -199,6 +219,11 @@ type request = | Aux_set of request_aux_set | Aux_delete of request_aux_delete | Show_sessions of request_show_sessions + | Set_edit_level of request_set_edit_level + | Set_edit_level_up of request_set_edit_level_up + | Reset_edit_level of request_reset_edit_level + | Get_edit_level of request_get_edit_level + | Edit_level_root of request_edit_level_root type request_envelope = { token : string option; @@ -445,6 +470,36 @@ val default_request_show_sessions : request_show_sessions (** [default_request_show_sessions ()] is the default value for type [request_show_sessions] *) +val default_request_set_edit_level : + ?path:string list -> + unit -> + request_set_edit_level +(** [default_request_set_edit_level ()] is the default value for type [request_set_edit_level] *) + +val default_request_set_edit_level_up : + ?dummy:int32 option -> + unit -> + request_set_edit_level_up +(** [default_request_set_edit_level_up ()] is the default value for type [request_set_edit_level_up] *) + +val default_request_reset_edit_level : + ?dummy:int32 option -> + unit -> + request_reset_edit_level +(** [default_request_reset_edit_level ()] is the default value for type [request_reset_edit_level] *) + +val default_request_get_edit_level : + ?dummy:int32 option -> + unit -> + request_get_edit_level +(** [default_request_get_edit_level ()] is the default value for type [request_get_edit_level] *) + +val default_request_edit_level_root : + ?dummy:int32 option -> + unit -> + request_edit_level_root +(** [default_request_edit_level_root ()] is the default value for type [request_edit_level_root] *) + val default_request : unit -> request (** [default_request ()] is the default value for type [request] *) @@ -572,6 +627,21 @@ val pp_request_reload_reftree : Format.formatter -> request_reload_reftree -> un val pp_request_show_sessions : Format.formatter -> request_show_sessions -> unit (** [pp_request_show_sessions v] formats v *) +val pp_request_set_edit_level : Format.formatter -> request_set_edit_level -> unit +(** [pp_request_set_edit_level v] formats v *) + +val pp_request_set_edit_level_up : Format.formatter -> request_set_edit_level_up -> unit +(** [pp_request_set_edit_level_up v] formats v *) + +val pp_request_reset_edit_level : Format.formatter -> request_reset_edit_level -> unit +(** [pp_request_reset_edit_level v] formats v *) + +val pp_request_get_edit_level : Format.formatter -> request_get_edit_level -> unit +(** [pp_request_get_edit_level v] formats v *) + +val pp_request_edit_level_root : Format.formatter -> request_edit_level_root -> unit +(** [pp_request_edit_level_root v] formats v *) + val pp_request : Format.formatter -> request -> unit (** [pp_request v] formats v *) @@ -689,6 +759,21 @@ val encode_pb_request_reload_reftree : request_reload_reftree -> Pbrt.Encoder.t val encode_pb_request_show_sessions : request_show_sessions -> Pbrt.Encoder.t -> unit (** [encode_pb_request_show_sessions v encoder] encodes [v] with the given [encoder] *) +val encode_pb_request_set_edit_level : request_set_edit_level -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_set_edit_level v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_request_set_edit_level_up : request_set_edit_level_up -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_set_edit_level_up v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_request_reset_edit_level : request_reset_edit_level -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_reset_edit_level v encoder] encodes [v] with the given [encoder] *) + +val encode_pb_request_get_edit_level : request_get_edit_level -> Pbrt.Encoder.t -> unit +(** [encode_pb_request_get_edit_level v encoder] encodes [v] with the given [encoder] *) + +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 : request -> Pbrt.Encoder.t -> unit (** [encode_pb_request v encoder] encodes [v] with the given [encoder] *) @@ -806,6 +891,21 @@ val decode_pb_request_reload_reftree : Pbrt.Decoder.t -> request_reload_reftree val decode_pb_request_show_sessions : Pbrt.Decoder.t -> request_show_sessions (** [decode_pb_request_show_sessions decoder] decodes a [request_show_sessions] binary value from [decoder] *) +val decode_pb_request_set_edit_level : Pbrt.Decoder.t -> request_set_edit_level +(** [decode_pb_request_set_edit_level decoder] decodes a [request_set_edit_level] binary value from [decoder] *) + +val decode_pb_request_set_edit_level_up : Pbrt.Decoder.t -> request_set_edit_level_up +(** [decode_pb_request_set_edit_level_up decoder] decodes a [request_set_edit_level_up] binary value from [decoder] *) + +val decode_pb_request_reset_edit_level : Pbrt.Decoder.t -> request_reset_edit_level +(** [decode_pb_request_reset_edit_level decoder] decodes a [request_reset_edit_level] binary value from [decoder] *) + +val decode_pb_request_get_edit_level : Pbrt.Decoder.t -> request_get_edit_level +(** [decode_pb_request_get_edit_level decoder] decodes a [request_get_edit_level] binary value from [decoder] *) + +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 : Pbrt.Decoder.t -> request (** [decode_pb_request decoder] decodes a [request] binary value from [decoder] *) -- cgit v1.2.3 From 4d3f2d5da41a2871de68cd196ac969f0648ef578 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Mon, 17 Nov 2025 11:42:57 -0600 Subject: T8009: add vyconfd handlers for edit_level requests --- src/session.ml | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/session.mli | 11 +++++++++++ src/vyconfd.ml | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) (limited to 'src') diff --git a/src/session.ml b/src/session.ml index 03c5f91..44feb8f 100644 --- a/src/session.ml +++ b/src/session.ml @@ -34,6 +34,7 @@ type session_data = { conf_mode: bool; changeset: cfg_op list; mutable aux_changeset: aux_op list; + edit_level: string list; client_app: string; client_pid: int32; client_user: string; @@ -45,6 +46,7 @@ let make _world client_app sudo_user user pid = { conf_mode = false; changeset = []; aux_changeset = []; + edit_level = []; client_app = client_app; client_user = user; client_sudo_user = sudo_user; @@ -262,6 +264,63 @@ let aux_delete w s path name tagval = let discard _w s = { s with changeset = []; } +let edit_env_str s = + (* To maintain consistency with classic CLI, we return env variable for + PS1 on changes to edit level. + *) + let ps1 = + match s.edit_level with + | [] -> + "[edit]\\n\\u@\\H${VRF:+(vrf:$VRF)}${NETNS:+(ns:$NETNS)}# " + | _ as p -> + Printf.sprintf + "[edit %s]\\n\\u@\\H${VRF:+(vrf:$VRF)}${NETNS:+(ns:$NETNS)}# " + (Vyos1x.Util.string_of_list p) + in + Printf.sprintf "export PS1='%s';" ps1 + +let set_edit_level w s path = + let current_level = s.edit_level in + let new_level = current_level @ path in + let result = RT.allowed_edit_level w.reference_tree new_level in + match result with + | Ok () -> + let c = get_proposed_config w s in + let s' = + if not ((VT.exists[@alert "-exn"]) c path) then + set w s path + else s + in + let session = { s' with edit_level = new_level; } in + session, (edit_env_str session) + | Error msg -> + raise (Session_error msg) + +let set_edit_level_up w s = + let current_level = s.edit_level in + let new_level = + if Vyos1x.Util.is_empty current_level then + current_level + else + let up = Vyos1x.Util.drop_last current_level in + match RT.allowed_edit_level w.reference_tree up with + | Ok () -> up + | Error _ -> (* tag_value *) + Vyos1x.Util.drop_last up + in + let session = { s with edit_level = new_level; } + in session, (edit_env_str session) + +let get_edit_level _w s = + Vyos1x.Util.string_of_list s.edit_level + +let reset_edit_level _w s = + let session = { s with edit_level = []; } + in session, (edit_env_str session) + +let edit_level_root _w s = + Vyos1x.Util.is_empty s.edit_level + let session_changed w s = (* structural equality test requires consistent ordering, which is * practised, but may be unreliable; test actual difference diff --git a/src/session.mli b/src/session.mli index cb3f37a..757bc18 100644 --- a/src/session.mli +++ b/src/session.mli @@ -20,6 +20,7 @@ type session_data = { conf_mode: bool; changeset: cfg_op list; mutable aux_changeset: aux_op list; + edit_level: string list; client_app: string; client_pid: int32; client_user: string; @@ -50,6 +51,16 @@ val get_proposed_config : world -> session_data -> Vyos1x.Config_tree.t val discard : world -> session_data -> session_data +val set_edit_level : world -> session_data -> string list -> session_data * string + +val set_edit_level_up : world -> session_data -> session_data * string + +val get_edit_level : world -> session_data -> string + +val reset_edit_level : world -> session_data -> session_data * string + +val edit_level_root : world -> session_data -> bool + val session_changed : world -> session_data -> bool val load : world -> session_data -> string -> bool -> session_data diff --git a/src/vyconfd.ml b/src/vyconfd.ml index c09c4f4..ed84978 100644 --- a/src/vyconfd.ml +++ b/src/vyconfd.ml @@ -362,6 +362,51 @@ let reload_reftree world (_req: request_reload_reftree) = {response_tmpl with status=Success} | Error s -> {response_tmpl with status=Fail; error=(Some s)} +let set_edit_level world token (req: request_set_edit_level) = + let s = find_session token in + try + let session, edit_env = + Session.set_edit_level world s req.path + in + Hashtbl.replace sessions token session; + {response_tmpl with output=(Some edit_env)} + with Session.Session_error msg -> + {response_tmpl with status=Fail; error=(Some msg)} + +let set_edit_level_up world token (_req: request_set_edit_level_up) = + let s = find_session token in + try + let session, edit_env = + Session.set_edit_level_up world s + in + Hashtbl.replace sessions token session; + {response_tmpl with output=(Some edit_env)} + with Session.Session_error msg -> + {response_tmpl with status=Fail; error=(Some msg)} + +let reset_edit_level world token (_req: request_reset_edit_level) = + let s = find_session token in + try + let session, edit_env = + Session.reset_edit_level world s + in + Hashtbl.replace sessions token session; + {response_tmpl with output=(Some edit_env)} + with Session.Session_error msg -> + {response_tmpl with status=Fail; error=(Some msg)} + +let get_edit_level world token (_req: request_get_edit_level) = + let s = find_session token in + try + let edit_env = Session.get_edit_level world s in + {response_tmpl with output=(Some edit_env)} + with Session.Session_error msg -> + {response_tmpl with status=Fail; error=(Some msg)} + +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 send_response oc resp = let enc = Pbrt.Encoder.create () in let%lwt () = encode_pb_response resp enc |> return in @@ -413,6 +458,11 @@ let rec handle_connection world ic oc () = | Some t, Merge r -> merge world t r | Some t, Save r -> save world t r | Some t, Show_sessions r -> show_sessions world t r + | Some t, Set_edit_level r -> set_edit_level world t r + | Some t, Set_edit_level_up r -> set_edit_level_up world t r + | 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 | _ -> failwith "Unimplemented" ) |> Lwt.return end -- cgit v1.2.3 From 5a41a32b39acbac17a9e80df501195a9b84f4450 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Mon, 17 Nov 2025 11:45:32 -0600 Subject: T8009: add edit_level requests to client module --- src/vyconf_client.ml | 40 ++++++++++++++++++++++++++++++++++++++++ src/vyconf_client.mli | 10 ++++++++++ 2 files changed, 50 insertions(+) (limited to 'src') diff --git a/src/vyconf_client.ml b/src/vyconf_client.ml index 25b923f..9250851 100644 --- a/src/vyconf_client.ml +++ b/src/vyconf_client.ml @@ -181,3 +181,43 @@ let reload_reftree ?(on_behalf_of=None) client = | Success -> Ok "" |> Lwt.return | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let set_edit_level client path = + let req = Set_edit_level {path=path;} in + let%lwt resp = do_request client req in + match resp.status with + | Success -> unwrap resp.output |> Lwt.return + | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return + | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let set_edit_level_up client = + let req = Set_edit_level_up {dummy=None;} in + let%lwt resp = do_request client req in + match resp.status with + | Success -> unwrap resp.output |> Lwt.return + | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return + | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let reset_edit_level client = + let req = Reset_edit_level {dummy=None;} in + let%lwt resp = do_request client req in + match resp.status with + | Success -> unwrap resp.output |> Lwt.return + | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return + | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let get_edit_level client = + let req = Get_edit_level {dummy=None;} in + let%lwt resp = do_request client req in + match resp.status with + | Success -> unwrap resp.output |> Lwt.return + | Fail -> Error (Option.value resp.error ~default:"") |> Lwt.return + | _ -> Error (Option.value resp.error ~default:"") |> Lwt.return + +let edit_level_root client = + let req = Edit_level_root {dummy=None;} 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 9c63652..200f960 100644 --- a/src/vyconf_client.mli +++ b/src/vyconf_client.mli @@ -37,3 +37,13 @@ val discard : t -> (string, string) result Lwt.t val commit : t -> (string, string) result Lwt.t val reload_reftree : ?on_behalf_of:(int option) -> t -> (string, string) result Lwt.t + +val set_edit_level : t -> string list -> (string, string) result Lwt.t + +val set_edit_level_up : t -> (string, string) result Lwt.t + +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 -- cgit v1.2.3 From 6716443921891921619ff915b9306fbb9818fcdb Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Mon, 17 Nov 2025 11:56:58 -0600 Subject: T8009: add executable for replacing retained cli-shell-api calls For integration with CLI completion and shell operations we call standard options through vyconf_cli_compat. --- src/dune | 7 +++ src/vyconf_cli_compat.ml | 131 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 src/vyconf_cli_compat.ml (limited to 'src') diff --git a/src/dune b/src/dune index 60f1e30..82b95bd 100644 --- a/src/dune +++ b/src/dune @@ -55,6 +55,13 @@ (libraries vyconfd_client) (preprocess (pps lwt_ppx))) +(executable + (name vyconf_cli_compat) + (public_name vyconf_cli_compat) + (modules vyconf_cli_compat) + (libraries vyconfd_client) + (preprocess (pps lwt_ppx))) + (executable (name validate) (public_name validate) diff --git a/src/vyconf_cli_compat.ml b/src/vyconf_cli_compat.ml new file mode 100644 index 0000000..eaa3501 --- /dev/null +++ b/src/vyconf_cli_compat.ml @@ -0,0 +1,131 @@ +open Vyconfd_client.Vyconf_client +open Vyconf_connect.Vyconf_pbt + +type op_t = + | OpSetEditLevel + | OpSetEditLevelUp + | OpResetEditLevel + | OpGetEditLevel + | OpEditLevelRoot + | OpShowConfig + | OpSessionChanged + +let op_of_arg s = + match s with + | "getEditEnv" -> OpSetEditLevel + | "getEditUpEnv" -> OpSetEditLevelUp + | "getEditResetEnv" -> OpResetEditLevel + | "getEditLevelStr" -> OpGetEditLevel + | "editLevelAtRoot" -> OpEditLevelRoot + | "showCfg" -> OpShowConfig + | "sessionChanged" -> OpSessionChanged + | _ -> failwith (Printf.sprintf "Unknown operation %s" s) + +let in_cli_config_session () = + let env = Unix.environment () in + let res = Array.find_opt (fun c -> String.starts_with ~prefix:"_OFR_CONFIGURE" c) env + in + match res with + | Some _ -> true + | None -> false + +let config_format_of_string s = + match s with + | "curly" -> Curly + | "json" -> Json + | _ -> failwith (Printf.sprintf "Unknown config format %s, should be curly or json" s) + +let output_format_of_string s = + match s with + | "plain" -> Out_plain + | "json" -> Out_json + | _ -> failwith (Printf.sprintf "Unknown output format %s, should be plain or json" s) + +let get_session () = + let pid = + try (* set for config session *) + Int32.of_string (Sys.getenv "SESSION_PID") + with Not_found -> + Int32.of_int (Unix.getppid()) + in + let user = + try Sys.getenv "USER" + with Not_found -> "" + in + let sudo_user = + try Sys.getenv "SUDO_USER" + with Not_found -> "" + in + let socket = "/var/run/vyconfd.sock" in + let config_format = config_format_of_string "curly" in + let out_format = output_format_of_string "plain" in + let%lwt client = + create socket out_format config_format + in + let%lwt resp = session_of_pid client pid in + match resp with + | Error _ -> setup_session client "vyconf_cli_compat" sudo_user user pid + | _ as c -> c |> Lwt.return + +let close_session () = + let%lwt client = get_session () in + match client with + | Ok c -> + teardown_session c + | Error e -> Error e |> Lwt.return + +let main op path = + let%lwt client = get_session () in + let%lwt result = + match client with + | Ok c -> + begin + match op with + | OpSetEditLevel -> set_edit_level c path + | OpSetEditLevelUp -> set_edit_level_up c + | OpResetEditLevel -> reset_edit_level c + | OpGetEditLevel -> get_edit_level c + | OpEditLevelRoot -> edit_level_root c + | OpShowConfig -> show_config c path + | OpSessionChanged -> session_changed c + end + | Error e -> Error e |> Lwt.return + in + let () = + if not (in_cli_config_session ()) then + close_session () |> Lwt.ignore_result + in + match result with + | Ok s -> + begin + match s with + | "" -> Lwt.return 0 + | _ -> + let%lwt () = + Lwt_io.write Lwt_io.stdout (Printf.sprintf "%s\n" s) in Lwt.return 0 + end + | Error e -> + begin + match e with + | "" -> Lwt.return 1 + | _ -> + let%lwt () = + Lwt_io.write Lwt_io.stderr (Printf.sprintf "%s\n" e) in Lwt.return 1 + end + +let () = + if (Array.length Sys.argv) < 2 then + let () = print_endline "Must specify operation" in exit 1 + else + let path_list = Array.to_list (Array.sub Sys.argv 2 (Array.length Sys.argv - 2)) + in + let op = + try + op_of_arg Sys.argv.(1) + with Failure msg -> let () = print_endline msg in exit 1 + in + match op, path_list with + | OpSetEditLevel, [] -> + let () = print_endline "Must specify config path" in exit 1 + | _, _ -> + let result = Lwt_main.run (main op path_list) in exit result -- cgit v1.2.3 From a2cd5c0db7633a3cf92c6a0206eabaab7879f6af Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Mon, 17 Nov 2025 14:51:45 -0600 Subject: T8009: make set/delete/show edit-level aware --- src/session.ml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/session.ml b/src/session.ml index 44feb8f..248121d 100644 --- a/src/session.ml +++ b/src/session.ml @@ -197,15 +197,17 @@ let set w s path = if Vyos1x.Util.is_empty path then raise (Session_error "Path is empty") else - let _ = validate w s path in - let changeset' = update_set w s.changeset path in + let path_total = s.edit_level @ path in + let _ = validate w s path_total in + let changeset' = update_set w s.changeset path_total in { s with changeset = changeset' } let delete w s path = if Vyos1x.Util.is_empty path then raise (Session_error "Path is empty") else - let changeset' = update_delete w s.changeset path in + let path_total = s.edit_level @ path in + let changeset' = update_delete w s.changeset path_total in { s with changeset = changeset' } let aux_set w s path name tagval = @@ -559,14 +561,16 @@ let exists w s path = (VT.exists[@alert "-exn"]) c path let show_config w s path = + let path_total = s.edit_level @ path in let proposed_config = get_proposed_config w s in - if (path <> []) && not ((VT.exists[@alert "-exn"]) proposed_config path) + if not (Vyos1x.Util.is_empty path_total) && + not ((VT.exists[@alert "-exn"]) proposed_config path_total) then raise (Session_error "Path does not exist") else let res = (CD.diff_show[@alert "-exn"]) w.reference_tree - path + path_total w.running_config proposed_config in res -- cgit v1.2.3